MDL-32709 book: coding style, deprecated and minor fixes
[moodle.git] / mod / book / locallib.php
1 <?php
2 // This file is part of Book module for 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/>.
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  */
25 defined('MOODLE_INTERNAL') || die;
27 require_once(dirname(__FILE__).'/lib.php');
28 require_once($CFG->libdir.'/filelib.php');
30 define('BOOK_NUM_NONE',     '0');
31 define('BOOK_NUM_NUMBERS',  '1');
32 define('BOOK_NUM_BULLETS',  '2');
33 define('BOOK_NUM_INDENTED', '3');
35 /**
36  * Preload book chapters and fix toc structure if necessary.
37  *
38  * Returns array of chapters with standard 'pagenum', 'id, pagenum, subchapter, title, hidden'
39  * and extra 'parent, number, subchapters, prev, next'.
40  * Please note the content/text of chapters is not included.
41  *
42  * @param  stdClass $book
43  * @return array of id=>chapter
44  */
45 function book_preload_chapters($book) {
46     global $DB;
47     $chapters = $DB->get_records('book_chapters', array('bookid'=>$book->id), 'pagenum', 'id, pagenum, subchapter, title, hidden');
48     if (!$chapters) {
49         return array();
50     }
52     $prev = null;
53     $prevsub = null;
55     $first = true;
56     $hidesub = true;
57     $parent = null;
58     $pagenum = 0; // chapter sort
59     $i = 0;       // main chapter num
60     $j = 0;       // subchapter num
61     foreach ($chapters as $id => $ch) {
62         $oldch = clone($ch);
63         $pagenum++;
64         $ch->pagenum = $pagenum;
65         if ($first) {
66             // book can not start with a subchapter
67             $ch->subchapter = 0;
68             $first = false;
69         }
70         if (!$ch->subchapter) {
71             $ch->prev = $prev;
72             $ch->next = null;
73             if ($prev) {
74                 $chapters[$prev]->next = $ch->id;
75             }
76             if ($ch->hidden) {
77                 if ($book->numbering == BOOK_NUM_NUMBERS) {
78                     $ch->number = 'x';
79                 } else {
80                     $ch->number = null;
81                 }
82             } else {
83                 $i++;
84                 $ch->number = $i;
85             }
86             $j = 0;
87             $prevsub = null;
88             $hidesub = $ch->hidden;
89             $parent = $ch->id;
90             $ch->parent = null;
91             $ch->subchpaters = array();
92         } else {
93             $ch->prev = $prevsub;
94             $ch->next = null;
95             if ($prevsub) {
96                 $chapters[$prevsub]->next = $ch->id;
97             }
98             $ch->parent = $parent;
99             $ch->subchpaters = null;
100             $chapters[$parent]->subchapters[$ch->id] = $ch->id;
101             if ($hidesub) {
102                 // all subchapters in hidden chapter must be hidden too
103                 $ch->hidden = 1;
104             }
105             if ($ch->hidden) {
106                 if ($book->numbering == BOOK_NUM_NUMBERS) {
107                     $ch->number = 'x';
108                 } else {
109                     $ch->number = null;
110                 }
111             } else {
112                 $j++;
113                 $ch->number = $j;
114             }
115         }
116         if ($oldch->subchapter != $ch->subchapter or $oldch->pagenum != $ch->pagenum or $oldch->hidden != $ch->hidden) {
117             // update only if something changed
118             $DB->update_record('book_chapters', $ch);
119         }
120         $chapters[$id] = $ch;
121     }
123     return $chapters;
126 /**
127  * Returns the title for a given chapter
128  *
129  * @param int $chid
130  * @param array $chapters
131  * @param stdClass $book
132  * @param context_module $context
133  * @return string
134  */
135 function book_get_chapter_title($chid, $chapters, $book, $context) {
136     $ch = $chapters[$chid];
137     $title = trim(format_string($ch->title, true, array('context'=>$context)));
138     $numbers = array();
139     if ($book->numbering == BOOK_NUM_NUMBERS) {
140         if ($ch->parent and $chapters[$ch->parent]->number) {
141             $numbers[] = $chapters[$ch->parent]->number;
142         }
143         if ($ch->number) {
144             $numbers[] = $ch->number;
145         }
146     }
148     if ($numbers) {
149         $title = implode('.', $numbers).' '.$title;
150     }
152     return $title;
155 /**
156  * General logging to table
157  * @param string $str1
158  * @param string $str2
159  * @param int $level
160  * @return void
161  */
162 function book_log($str1, $str2, $level = 0) {
163     switch ($level) {
164         case 1:
165             echo '<tr><td><span class="dimmed_text">'.$str1.'</span></td><td><span class="dimmed_text">'.$str2.'</span></td></tr>';
166             break;
167         case 2:
168             echo '<tr><td><span style="color: rgb(255, 0, 0);">'.$str1.'</span></td><td><span style="color: rgb(255, 0, 0);">'.$str2.'</span></td></tr>';
169             break;
170         default:
171             echo '<tr><td>'.$str1.'</class></td><td>'.$str2.'</td></tr>';
172             break;
173     }
176 /**
177  * Add the book TOC sticky block to the 1st region available
178  *
179  * @param array $chapters
180  * @param stdClass $chapter
181  * @param stdClass $book
182  * @param stdClass $cm
183  * @param bool $edit
184  */
185 function book_add_fake_block($chapters, $chapter, $book, $cm, $edit) {
186     global $OUTPUT, $PAGE;
188     $toc = book_get_toc($chapters, $chapter, $book, $cm, $edit, 0);
190     if ($edit) {
191         $toc .= '<div class="book_faq">';
192         $toc .=  $OUTPUT->help_icon('faq', 'mod_book', get_string('faq', 'mod_book'));
193         $toc .=  '</div>';
194     }
196     $bc = new block_contents();
197     $bc->title = get_string('toc', 'mod_book');
198     $bc->attributes['class'] = 'block';
199     $bc->content = $toc;
201     $regions = $PAGE->blocks->get_regions();
202     $firstregion = reset($regions);
203     $PAGE->blocks->add_fake_block($bc, $firstregion);
206 /**
207  * Generate toc structure
208  *
209  * @param array $chapters
210  * @param stdClass $chapter
211  * @param stdClass $book
212  * @param stdClass $cm
213  * @param bool $edit
214  * @return string
215  */
216 function book_get_toc($chapters, $chapter, $book, $cm, $edit) {
217     global $USER, $OUTPUT;
219     $toc = '';  // Representation of toc (HTML)
220     $nch = 0;   // Chapter number
221     $ns = 0;    // Subchapter number
222     $first = 1;
224     $context = context_module::instance($cm->id);
226     switch ($book->numbering) {
227         case BOOK_NUM_NONE:
228             $toc .= '<div class="book_toc_none">';
229             break;
230         case BOOK_NUM_NUMBERS:
231             $toc .= '<div class="book_toc_numbered">';
232             break;
233         case BOOK_NUM_BULLETS:
234             $toc .= '<div class="book_toc_bullets">';
235             break;
236         case BOOK_NUM_INDENTED:
237             $toc .= '<div class="book_toc_indented">';
238             break;
239     }
241     if ($edit) { // Teacher's TOC
242         $toc .= '<ul>';
243         $i = 0;
244         foreach ($chapters as $ch) {
245             $i++;
246             $title = trim(format_string($ch->title, true, array('context'=>$context)));
247             if (!$ch->subchapter) {
248                 $toc .= ($first) ? '<li>' : '</ul></li><li>';
249                 if (!$ch->hidden) {
250                     $nch++;
251                     $ns = 0;
252                     if ($book->numbering == BOOK_NUM_NUMBERS) {
253                         $title = "$nch $title";
254                     }
255                 } else {
256                     if ($book->numbering == BOOK_NUM_NUMBERS) {
257                         $title = "x $title";
258                     }
259                     $title = '<span class="dimmed_text">'.$title.'</span>';
260                 }
261             } else {
262                 $toc .= ($first) ? '<li><ul><li>' : '<li>';
263                 if (!$ch->hidden) {
264                     $ns++;
265                     if ($book->numbering == BOOK_NUM_NUMBERS) {
266                         $title = "$nch.$ns $title";
267                     }
268                 } else {
269                     if ($book->numbering == BOOK_NUM_NUMBERS) {
270                         $title = "x.x $title";
271                     }
272                     $title = '<span class="dimmed_text">'.$title.'</span>';
273                 }
274             }
276             if ($ch->id == $chapter->id) {
277                 $toc .= '<strong>'.$title.'</strong>';
278             } else {
279                 $toc .= '<a title="'.s($title).'" href="view.php?id='.$cm->id.'&amp;chapterid='.$ch->id.'">'.$title.'</a>';
280             }
281             $toc .=  '&nbsp;&nbsp;';
282             if ($i != 1) {
283                 $toc .=  ' <a title="'.get_string('up').'" href="move.php?id='.$cm->id.'&amp;chapterid='.$ch->id.
284                         '&amp;up=1&amp;sesskey='.$USER->sesskey.'"><img src="'.$OUTPUT->pix_url('t/up').'" class="iconsmall" alt="'.get_string('up').'" /></a>';
285             }
286             if ($i != count($chapters)) {
287                 $toc .=  ' <a title="'.get_string('down').'" href="move.php?id='.$cm->id.'&amp;chapterid='.$ch->id.
288                         '&amp;up=0&amp;sesskey='.$USER->sesskey.'"><img src="'.$OUTPUT->pix_url('t/down').'" class="iconsmall" alt="'.get_string('down').'" /></a>';
289             }
290             $toc .=  ' <a title="'.get_string('edit').'" href="edit.php?cmid='.$cm->id.'&amp;id='.$ch->id.'"><img src="'.
291                     $OUTPUT->pix_url('t/edit').'" class="iconsmall" alt="'.get_string('edit').'" /></a>';
292             $toc .=  ' <a title="'.get_string('delete').'" href="delete.php?id='.$cm->id.'&amp;chapterid='.$ch->id.
293                     '&amp;sesskey='.$USER->sesskey.'"><img src="'.$OUTPUT->pix_url('t/delete').'" class="iconsmall" alt="'.get_string('delete').'" /></a>';
294             if ($ch->hidden) {
295                 $toc .= ' <a title="'.get_string('show').'" href="show.php?id='.$cm->id.'&amp;chapterid='.$ch->id.
296                         '&amp;sesskey='.$USER->sesskey.'"><img src="'.$OUTPUT->pix_url('t/show').'" class="iconsmall" alt="'.get_string('show').'" /></a>';
297             } else {
298                 $toc .= ' <a title="'.get_string('hide').'" href="show.php?id='.$cm->id.'&amp;chapterid='.$ch->id.
299                         '&amp;sesskey='.$USER->sesskey.'"><img src="'.$OUTPUT->pix_url('t/hide').'" class="iconsmall" alt="'.get_string('hide').'" /></a>';
300             }
301             $toc .= ' <a title="'.get_string('addafter', 'mod_book').'" href="edit.php?cmid='.$cm->id.
302                     '&amp;pagenum='.$ch->pagenum.'&amp;subchapter='.$ch->subchapter.'"><img src="'.
303                     $OUTPUT->pix_url('add', 'mod_book').'" class="iconsmall" alt="'.get_string('addafter', 'mod_book').'" /></a>';
305             $toc .= (!$ch->subchapter) ? '<ul>' : '</li>';
306             $first = 0;
307         }
308         $toc .= '</ul></li></ul>';
309     } else { // Normal students view
310         $toc .= '<ul>';
311         foreach ($chapters as $ch) {
312             $title = trim(format_string($ch->title, true, array('context'=>$context)));
313             if (!$ch->hidden) {
314                 if (!$ch->subchapter) {
315                     $nch++;
316                     $ns = 0;
317                     $toc .= ($first) ? '<li>' : '</ul></li><li>';
318                     if ($book->numbering == BOOK_NUM_NUMBERS) {
319                           $title = "$nch $title";
320                     }
321                 } else {
322                     $ns++;
323                     $toc .= ($first) ? '<li><ul><li>' : '<li>';
324                     if ($book->numbering == BOOK_NUM_NUMBERS) {
325                           $title = "$nch.$ns $title";
326                     }
327                 }
328                 if ($ch->id == $chapter->id) {
329                     $toc .= '<strong>'.$title.'</strong>';
330                 } else {
331                     $toc .= '<a title="'.s($title).'" href="view.php?id='.$cm->id.'&amp;chapterid='.$ch->id.'">'.$title.'</a>';
332                 }
333                 $toc .= (!$ch->subchapter) ? '<ul>' : '</li>';
334                 $first = 0;
335             }
336         }
337         $toc .= '</ul></li></ul>';
338     }
340     $toc .= '</div>';
342     $toc = str_replace('<ul></ul>', '', $toc); // Cleanup of invalid structures.
344     return $toc;
348 /**
349  * File browsing support class
350  *
351  * @copyright  2010-2011 Petr Skoda {@link http://skodak.org}
352  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
353  */
354 class book_file_info extends file_info {
355     /** @var stdClass Course object */
356     protected $course;
357     /** @var stdClass Course module object */
358     protected $cm;
359     /** @var array Available file areas */
360     protected $areas;
361     /** @var string File area to browse */
362     protected $filearea;
364     /**
365      * Constructor
366      *
367      * @param file_browser $browser file_browser instance
368      * @param stdClass $course course object
369      * @param stdClass $cm course module object
370      * @param stdClass $context module context
371      * @param array $areas available file areas
372      * @param string $filearea file area to browse
373      */
374     public function __construct($browser, $course, $cm, $context, $areas, $filearea) {
375         parent::__construct($browser, $context);
376         $this->course   = $course;
377         $this->cm       = $cm;
378         $this->areas    = $areas;
379         $this->filearea = $filearea;
380     }
382     /**
383      * Returns list of standard virtual file/directory identification.
384      * The difference from stored_file parameters is that null values
385      * are allowed in all fields
386      * @return array with keys contextid, filearea, itemid, filepath and filename
387      */
388     public function get_params() {
389         return array('contextid'=>$this->context->id,
390                      'component'=>'mod_book',
391                      'filearea' =>$this->filearea,
392                      'itemid'   =>null,
393                      'filepath' =>null,
394                      'filename' =>null);
395     }
397     /**
398      * Returns localised visible name.
399      * @return string
400      */
401     public function get_visible_name() {
402         return $this->areas[$this->filearea];
403     }
405     /**
406      * Can I add new files or directories?
407      * @return bool
408      */
409     public function is_writable() {
410         return false;
411     }
413     /**
414      * Is directory?
415      * @return bool
416      */
417     public function is_directory() {
418         return true;
419     }
421     /**
422      * Returns list of children.
423      * @return array of file_info instances
424      */
425     public function get_children() {
426         global $DB;
428         $children = array();
429         $chapters = $DB->get_records('book_chapters', array('bookid'=>$this->cm->instance), 'pagenum', 'id, pagenum');
430         foreach ($chapters as $itemid => $unused) {
431             if ($child = $this->browser->get_file_info($this->context, 'mod_book', $this->filearea, $itemid)) {
432                 $children[] = $child;
433             }
434         }
435         return $children;
436     }
438     /**
439      * Returns parent file_info instance
440      * @return file_info or null for root
441      */
442     public function get_parent() {
443         return $this->browser->get_file_info($this->context);
444     }