[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/mod/book/ -> locallib.php (source)

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * Book module local lib functions
  19   *
  20   * @package    mod_book
  21   * @copyright  2010-2011 Petr Skoda {@link http://skodak.org}
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  defined('MOODLE_INTERNAL') || die;
  26  
  27  require_once (__DIR__.'/lib.php');
  28  require_once($CFG->libdir.'/filelib.php');
  29  
  30  /**
  31   * The following defines are used to define how the chapters and subchapters of a book should be displayed in that table of contents.
  32   * BOOK_NUM_NONE        No special styling will applied and the editor will be able to do what ever thay want in the title
  33   * BOOK_NUM_NUMBERS     Chapters and subchapters are numbered (1, 1.1, 1.2, 2, ...)
  34   * BOOK_NUM_BULLETS     Subchapters are indented and displayed with bullets
  35   * BOOK_NUM_INDENTED    Subchapters are indented
  36   */
  37  define('BOOK_NUM_NONE',     '0');
  38  define('BOOK_NUM_NUMBERS',  '1');
  39  define('BOOK_NUM_BULLETS',  '2');
  40  define('BOOK_NUM_INDENTED', '3');
  41  
  42  /**
  43   * The following defines are used to define the navigation style used within a book.
  44   * BOOK_LINK_TOCONLY    Only the table of contents is shown, in a side region.
  45   * BOOK_LINK_IMAGE      Arrows link to previous/next/exit pages, in addition to the TOC.
  46   * BOOK_LINK_TEXT       Page names and arrows link to previous/next/exit pages, in addition to the TOC.
  47   */
  48  define ('BOOK_LINK_TOCONLY', '0');
  49  define ('BOOK_LINK_IMAGE', '1');
  50  define ('BOOK_LINK_TEXT', '2');
  51  
  52  /**
  53   * Preload book chapters and fix toc structure if necessary.
  54   *
  55   * Returns array of chapters with standard 'pagenum', 'id, pagenum, subchapter, title, hidden'
  56   * and extra 'parent, number, subchapters, prev, next'.
  57   * Please note the content/text of chapters is not included.
  58   *
  59   * @param  stdClass $book
  60   * @return array of id=>chapter
  61   */
  62  function book_preload_chapters($book) {
  63      global $DB;
  64      $chapters = $DB->get_records('book_chapters', array('bookid'=>$book->id), 'pagenum', 'id, pagenum, subchapter, title, hidden');
  65      if (!$chapters) {
  66          return array();
  67      }
  68  
  69      $prev = null;
  70      $prevsub = null;
  71  
  72      $first = true;
  73      $hidesub = true;
  74      $parent = null;
  75      $pagenum = 0; // chapter sort
  76      $i = 0;       // main chapter num
  77      $j = 0;       // subchapter num
  78      foreach ($chapters as $id => $ch) {
  79          $oldch = clone($ch);
  80          $pagenum++;
  81          $ch->pagenum = $pagenum;
  82          if ($first) {
  83              // book can not start with a subchapter
  84              $ch->subchapter = 0;
  85              $first = false;
  86          }
  87          if (!$ch->subchapter) {
  88              if ($ch->hidden) {
  89                  if ($book->numbering == BOOK_NUM_NUMBERS) {
  90                      $ch->number = 'x';
  91                  } else {
  92                      $ch->number = null;
  93                  }
  94              } else {
  95                  $i++;
  96                  $ch->number = $i;
  97              }
  98              $j = 0;
  99              $prevsub = null;
 100              $hidesub = $ch->hidden;
 101              $parent = $ch->id;
 102              $ch->parent = null;
 103              $ch->subchapters = array();
 104          } else {
 105              $ch->parent = $parent;
 106              $ch->subchapters = null;
 107              $chapters[$parent]->subchapters[$ch->id] = $ch->id;
 108              if ($hidesub) {
 109                  // all subchapters in hidden chapter must be hidden too
 110                  $ch->hidden = 1;
 111              }
 112              if ($ch->hidden) {
 113                  if ($book->numbering == BOOK_NUM_NUMBERS) {
 114                      $ch->number = 'x';
 115                  } else {
 116                      $ch->number = null;
 117                  }
 118              } else {
 119                  $j++;
 120                  $ch->number = $j;
 121              }
 122          }
 123  
 124          if ($oldch->subchapter != $ch->subchapter or $oldch->pagenum != $ch->pagenum or $oldch->hidden != $ch->hidden) {
 125              // update only if something changed
 126              $DB->update_record('book_chapters', $ch);
 127          }
 128          $chapters[$id] = $ch;
 129      }
 130  
 131      return $chapters;
 132  }
 133  
 134  /**
 135   * Returns the title for a given chapter
 136   *
 137   * @param int $chid
 138   * @param array $chapters
 139   * @param stdClass $book
 140   * @param context_module $context
 141   * @return string
 142   */
 143  function book_get_chapter_title($chid, $chapters, $book, $context) {
 144      $ch = $chapters[$chid];
 145      $title = trim(format_string($ch->title, true, array('context'=>$context)));
 146      $numbers = array();
 147      if ($book->numbering == BOOK_NUM_NUMBERS) {
 148          if ($ch->parent and $chapters[$ch->parent]->number) {
 149              $numbers[] = $chapters[$ch->parent]->number;
 150          }
 151          if ($ch->number) {
 152              $numbers[] = $ch->number;
 153          }
 154      }
 155  
 156      if ($numbers) {
 157          $title = implode('.', $numbers).' '.$title;
 158      }
 159  
 160      return $title;
 161  }
 162  
 163  /**
 164   * Add the book TOC sticky block to the default region
 165   *
 166   * @param array $chapters
 167   * @param stdClass $chapter
 168   * @param stdClass $book
 169   * @param stdClass $cm
 170   * @param bool $edit
 171   */
 172  function book_add_fake_block($chapters, $chapter, $book, $cm, $edit) {
 173      global $OUTPUT, $PAGE;
 174  
 175      $toc = book_get_toc($chapters, $chapter, $book, $cm, $edit, 0);
 176  
 177      $bc = new block_contents();
 178      $bc->title = get_string('toc', 'mod_book');
 179      $bc->attributes['class'] = 'block block_book_toc';
 180      $bc->content = $toc;
 181  
 182      $defaultregion = $PAGE->blocks->get_default_region();
 183      $PAGE->blocks->add_fake_block($bc, $defaultregion);
 184  }
 185  
 186  /**
 187   * Generate toc structure
 188   *
 189   * @param array $chapters
 190   * @param stdClass $chapter
 191   * @param stdClass $book
 192   * @param stdClass $cm
 193   * @param bool $edit
 194   * @return string
 195   */
 196  function book_get_toc($chapters, $chapter, $book, $cm, $edit) {
 197      global $USER, $OUTPUT;
 198  
 199      $toc = '';
 200      $nch = 0;   // Chapter number
 201      $ns = 0;    // Subchapter number
 202      $first = 1;
 203  
 204      $context = context_module::instance($cm->id);
 205  
 206      switch ($book->numbering) {
 207          case BOOK_NUM_NONE:
 208              $toc .= html_writer::start_tag('div', array('class' => 'book_toc_none clearfix'));
 209              break;
 210          case BOOK_NUM_NUMBERS:
 211              $toc .= html_writer::start_tag('div', array('class' => 'book_toc_numbered clearfix'));
 212              break;
 213          case BOOK_NUM_BULLETS:
 214              $toc .= html_writer::start_tag('div', array('class' => 'book_toc_bullets clearfix'));
 215              break;
 216          case BOOK_NUM_INDENTED:
 217              $toc .= html_writer::start_tag('div', array('class' => 'book_toc_indented clearfix'));
 218              break;
 219      }
 220  
 221      if ($edit) { // Teacher's TOC
 222          $toc .= html_writer::start_tag('ul');
 223          $i = 0;
 224          foreach ($chapters as $ch) {
 225              $i++;
 226              $title = trim(format_string($ch->title, true, array('context' => $context)));
 227              $titleunescaped = trim(format_string($ch->title, true, array('context' => $context, 'escape' => false)));
 228              $titleout = $title;
 229  
 230              if (!$ch->subchapter) {
 231  
 232                  if ($first) {
 233                      $toc .= html_writer::start_tag('li', array('class' => 'clearfix'));
 234                  } else {
 235                      $toc .= html_writer::end_tag('ul');
 236                      $toc .= html_writer::end_tag('li');
 237                      $toc .= html_writer::start_tag('li', array('class' => 'clearfix'));
 238                  }
 239  
 240                  if (!$ch->hidden) {
 241                      $nch++;
 242                      $ns = 0;
 243                      if ($book->numbering == BOOK_NUM_NUMBERS) {
 244                          $title = "$nch $title";
 245                          $titleout = $title;
 246                      }
 247                  } else {
 248                      if ($book->numbering == BOOK_NUM_NUMBERS) {
 249                          $title = "x $title";
 250                      }
 251                      $titleout = html_writer::tag('span', $title, array('class' => 'dimmed_text'));
 252                  }
 253              } else {
 254  
 255                  if ($first) {
 256                      $toc .= html_writer::start_tag('li', array('class' => 'clearfix'));
 257                      $toc .= html_writer::start_tag('ul');
 258                      $toc .= html_writer::start_tag('li', array('class' => 'clearfix'));
 259                  } else {
 260                      $toc .= html_writer::start_tag('li', array('class' => 'clearfix'));
 261                  }
 262  
 263                  if (!$ch->hidden) {
 264                      $ns++;
 265                      if ($book->numbering == BOOK_NUM_NUMBERS) {
 266                          $title = "$nch.$ns $title";
 267                          $titleout = $title;
 268                      }
 269                  } else {
 270                      if ($book->numbering == BOOK_NUM_NUMBERS) {
 271                          if (empty($chapters[$ch->parent]->hidden)) {
 272                              $title = "$nch.x $title";
 273                          } else {
 274                              $title = "x.x $title";
 275                          }
 276                      }
 277                      $titleout = html_writer::tag('span', $title, array('class' => 'dimmed_text'));
 278                  }
 279              }
 280  
 281              if ($ch->id == $chapter->id) {
 282                  $toc .= html_writer::tag('strong', $titleout);
 283              } else {
 284                  $toc .= html_writer::link(new moodle_url('view.php', array('id' => $cm->id, 'chapterid' => $ch->id)), $titleout,
 285                      array('title' => $titleunescaped));
 286              }
 287  
 288              $toc .= html_writer::start_tag('div', array('class' => 'action-list'));
 289              if ($i != 1) {
 290                  $toc .= html_writer::link(new moodle_url('move.php', array('id' => $cm->id, 'chapterid' => $ch->id, 'up' => '1', 'sesskey' => $USER->sesskey)),
 291                          $OUTPUT->pix_icon('t/up', get_string('movechapterup', 'mod_book', $title)),
 292                          array('title' => get_string('movechapterup', 'mod_book', $titleunescaped)));
 293              }
 294              if ($i != count($chapters)) {
 295                  $toc .= html_writer::link(new moodle_url('move.php', array('id' => $cm->id, 'chapterid' => $ch->id, 'up' => '0', 'sesskey' => $USER->sesskey)),
 296                          $OUTPUT->pix_icon('t/down', get_string('movechapterdown', 'mod_book', $title)),
 297                          array('title' => get_string('movechapterdown', 'mod_book', $titleunescaped)));
 298              }
 299              $toc .= html_writer::link(new moodle_url('edit.php', array('cmid' => $cm->id, 'id' => $ch->id)),
 300                      $OUTPUT->pix_icon('t/edit', get_string('editchapter', 'mod_book', $title)),
 301                      array('title' => get_string('editchapter', 'mod_book', $titleunescaped)));
 302              $toc .= html_writer::link(new moodle_url('delete.php', array('id' => $cm->id, 'chapterid' => $ch->id, 'sesskey' => $USER->sesskey)),
 303                          $OUTPUT->pix_icon('t/delete', get_string('deletechapter', 'mod_book', $title)),
 304                          array('title' => get_string('deletechapter', 'mod_book', $titleunescaped)));
 305              if ($ch->hidden) {
 306                  $toc .= html_writer::link(new moodle_url('show.php', array('id' => $cm->id, 'chapterid' => $ch->id, 'sesskey' => $USER->sesskey)),
 307                          $OUTPUT->pix_icon('t/show', get_string('showchapter', 'mod_book', $title)),
 308                          array('title' => get_string('showchapter', 'mod_book', $titleunescaped)));
 309              } else {
 310                  $toc .= html_writer::link(new moodle_url('show.php', array('id' => $cm->id, 'chapterid' => $ch->id, 'sesskey' => $USER->sesskey)),
 311                          $OUTPUT->pix_icon('t/hide', get_string('hidechapter', 'mod_book', $title)),
 312                          array('title' => get_string('hidechapter', 'mod_book', $titleunescaped)));
 313              }
 314              $toc .= html_writer::link(new moodle_url('edit.php', array('cmid' => $cm->id, 'pagenum' => $ch->pagenum, 'subchapter' => $ch->subchapter)),
 315                                              $OUTPUT->pix_icon('add', get_string('addafter', 'mod_book'), 'mod_book'), array('title' => get_string('addafter', 'mod_book')));
 316              $toc .= html_writer::end_tag('div');
 317  
 318              if (!$ch->subchapter) {
 319                  $toc .= html_writer::start_tag('ul');
 320              } else {
 321                  $toc .= html_writer::end_tag('li');
 322              }
 323              $first = 0;
 324          }
 325  
 326          $toc .= html_writer::end_tag('ul');
 327          $toc .= html_writer::end_tag('li');
 328          $toc .= html_writer::end_tag('ul');
 329  
 330      } else { // Normal students view
 331          $toc .= html_writer::start_tag('ul');
 332          foreach ($chapters as $ch) {
 333              $title = trim(format_string($ch->title, true, array('context'=>$context)));
 334              $titleunescaped = trim(format_string($ch->title, true, array('context' => $context, 'escape' => false)));
 335              if (!$ch->hidden) {
 336                  if (!$ch->subchapter) {
 337                      $nch++;
 338                      $ns = 0;
 339  
 340                      if ($first) {
 341                          $toc .= html_writer::start_tag('li', array('class' => 'clearfix'));
 342                      } else {
 343                          $toc .= html_writer::end_tag('ul');
 344                          $toc .= html_writer::end_tag('li');
 345                          $toc .= html_writer::start_tag('li', array('class' => 'clearfix'));
 346                      }
 347  
 348                      if ($book->numbering == BOOK_NUM_NUMBERS) {
 349                            $title = "$nch $title";
 350                      }
 351                  } else {
 352                      $ns++;
 353  
 354                      if ($first) {
 355                          $toc .= html_writer::start_tag('li', array('class' => 'clearfix'));
 356                          $toc .= html_writer::start_tag('ul');
 357                          $toc .= html_writer::start_tag('li', array('class' => 'clearfix'));
 358                      } else {
 359                          $toc .= html_writer::start_tag('li', array('class' => 'clearfix'));
 360                      }
 361  
 362                      if ($book->numbering == BOOK_NUM_NUMBERS) {
 363                            $title = "$nch.$ns $title";
 364                      }
 365                  }
 366                  if ($ch->id == $chapter->id) {
 367                      $toc .= html_writer::tag('strong', $title);
 368                  } else {
 369                      $toc .= html_writer::link(new moodle_url('view.php',
 370                                                array('id' => $cm->id, 'chapterid' => $ch->id)),
 371                                                $title, array('title' => s($titleunescaped)));
 372                  }
 373  
 374                  if (!$ch->subchapter) {
 375                      $toc .= html_writer::start_tag('ul');
 376                  } else {
 377                      $toc .= html_writer::end_tag('li');
 378                  }
 379  
 380                  $first = 0;
 381              }
 382          }
 383  
 384          $toc .= html_writer::end_tag('ul');
 385          $toc .= html_writer::end_tag('li');
 386          $toc .= html_writer::end_tag('ul');
 387  
 388      }
 389  
 390      $toc .= html_writer::end_tag('div');
 391  
 392      $toc = str_replace('<ul></ul>', '', $toc); // Cleanup of invalid structures.
 393  
 394      return $toc;
 395  }
 396  
 397  
 398  /**
 399   * File browsing support class
 400   *
 401   * @copyright  2010-2011 Petr Skoda {@link http://skodak.org}
 402   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 403   */
 404  class book_file_info extends file_info {
 405      /** @var stdClass Course object */
 406      protected $course;
 407      /** @var stdClass Course module object */
 408      protected $cm;
 409      /** @var array Available file areas */
 410      protected $areas;
 411      /** @var string File area to browse */
 412      protected $filearea;
 413  
 414      /**
 415       * Constructor
 416       *
 417       * @param file_browser $browser file_browser instance
 418       * @param stdClass $course course object
 419       * @param stdClass $cm course module object
 420       * @param stdClass $context module context
 421       * @param array $areas available file areas
 422       * @param string $filearea file area to browse
 423       */
 424      public function __construct($browser, $course, $cm, $context, $areas, $filearea) {
 425          parent::__construct($browser, $context);
 426          $this->course   = $course;
 427          $this->cm       = $cm;
 428          $this->areas    = $areas;
 429          $this->filearea = $filearea;
 430      }
 431  
 432      /**
 433       * Returns list of standard virtual file/directory identification.
 434       * The difference from stored_file parameters is that null values
 435       * are allowed in all fields
 436       * @return array with keys contextid, filearea, itemid, filepath and filename
 437       */
 438      public function get_params() {
 439          return array('contextid'=>$this->context->id,
 440                       'component'=>'mod_book',
 441                       'filearea' =>$this->filearea,
 442                       'itemid'   =>null,
 443                       'filepath' =>null,
 444                       'filename' =>null);
 445      }
 446  
 447      /**
 448       * Returns localised visible name.
 449       * @return string
 450       */
 451      public function get_visible_name() {
 452          return $this->areas[$this->filearea];
 453      }
 454  
 455      /**
 456       * Can I add new files or directories?
 457       * @return bool
 458       */
 459      public function is_writable() {
 460          return false;
 461      }
 462  
 463      /**
 464       * Is directory?
 465       * @return bool
 466       */
 467      public function is_directory() {
 468          return true;
 469      }
 470  
 471      /**
 472       * Returns list of children.
 473       * @return array of file_info instances
 474       */
 475      public function get_children() {
 476          return $this->get_filtered_children('*', false, true);
 477      }
 478  
 479      /**
 480       * Help function to return files matching extensions or their count
 481       *
 482       * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
 483       * @param bool|int $countonly if false returns the children, if an int returns just the
 484       *    count of children but stops counting when $countonly number of children is reached
 485       * @param bool $returnemptyfolders if true returns items that don't have matching files inside
 486       * @return array|int array of file_info instances or the count
 487       */
 488      private function get_filtered_children($extensions = '*', $countonly = false, $returnemptyfolders = false) {
 489          global $DB;
 490          $params = array('contextid' => $this->context->id,
 491              'component' => 'mod_book',
 492              'filearea' => $this->filearea,
 493              'bookid' => $this->cm->instance);
 494          $sql = 'SELECT DISTINCT bc.id, bc.pagenum
 495                      FROM {files} f, {book_chapters} bc
 496                      WHERE f.contextid = :contextid
 497                      AND f.component = :component
 498                      AND f.filearea = :filearea
 499                      AND bc.bookid = :bookid
 500                      AND bc.id = f.itemid';
 501          if (!$returnemptyfolders) {
 502              $sql .= ' AND filename <> :emptyfilename';
 503              $params['emptyfilename'] = '.';
 504          }
 505          list($sql2, $params2) = $this->build_search_files_sql($extensions, 'f');
 506          $sql .= ' '.$sql2;
 507          $params = array_merge($params, $params2);
 508          if ($countonly === false) {
 509              $sql .= ' ORDER BY bc.pagenum';
 510          }
 511  
 512          $rs = $DB->get_recordset_sql($sql, $params);
 513          $children = array();
 514          foreach ($rs as $record) {
 515              if ($child = $this->browser->get_file_info($this->context, 'mod_book', $this->filearea, $record->id)) {
 516                  if ($returnemptyfolders || $child->count_non_empty_children($extensions)) {
 517                      $children[] = $child;
 518                  }
 519              }
 520              if ($countonly !== false && count($children) >= $countonly) {
 521                  break;
 522              }
 523          }
 524          $rs->close();
 525          if ($countonly !== false) {
 526              return count($children);
 527          }
 528          return $children;
 529      }
 530  
 531      /**
 532       * Returns list of children which are either files matching the specified extensions
 533       * or folders that contain at least one such file.
 534       *
 535       * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
 536       * @return array of file_info instances
 537       */
 538      public function get_non_empty_children($extensions = '*') {
 539          return $this->get_filtered_children($extensions, false);
 540      }
 541  
 542      /**
 543       * Returns the number of children which are either files matching the specified extensions
 544       * or folders containing at least one such file.
 545       *
 546       * @param string|array $extensions, for example '*' or array('.gif','.jpg')
 547       * @param int $limit stop counting after at least $limit non-empty children are found
 548       * @return int
 549       */
 550      public function count_non_empty_children($extensions = '*', $limit = 1) {
 551          return $this->get_filtered_children($extensions, $limit);
 552      }
 553  
 554      /**
 555       * Returns parent file_info instance
 556       * @return file_info or null for root
 557       */
 558      public function get_parent() {
 559          return $this->browser->get_file_info($this->context);
 560      }
 561  }


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1