[ Index ]

PHP Cross Reference of moodle-2.8

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


Generated: Fri Nov 28 20:29:05 2014 Cross-referenced by PHPXref 0.7.1