PageRenderTime 70ms CodeModel.GetById 2ms app.highlight 60ms RepoModel.GetById 2ms app.codeStats 0ms

/lib/filebrowser/file_info_context_course.php

http://github.com/moodle/moodle
PHP | 997 lines | 533 code | 116 blank | 348 comment | 87 complexity | 3c993910e8d861556a7753dac8dcac43 MD5 | raw file
  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/**
 19 * Utility class for browsing of course files.
 20 *
 21 * @package    core_files
 22 * @copyright  2008 Petr Skoda (http://skodak.org)
 23 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 24 */
 25
 26defined('MOODLE_INTERNAL') || die();
 27
 28/**
 29 * Represents a course context in the tree navigated by {@link file_browser}.
 30 *
 31 * @package    core_files
 32 * @copyright  2008 Petr Skoda (http://skodak.org)
 33 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 34 */
 35class file_info_context_course extends file_info {
 36    /** @var stdClass course object */
 37    protected $course;
 38
 39    /** @var file_info_context_module[] cached child modules. See {@link get_child_module()} */
 40    protected $childrenmodules = [];
 41
 42    /**
 43     * Constructor
 44     *
 45     * @param file_browser $browser file browser instance
 46     * @param stdClass $context context object
 47     * @param stdClass $course course object
 48     */
 49    public function __construct($browser, $context, $course) {
 50        parent::__construct($browser, $context);
 51        $this->course   = $course;
 52    }
 53
 54    /**
 55     * Return information about this specific context level
 56     *
 57     * @param string $component component
 58     * @param string $filearea file area
 59     * @param int $itemid item ID
 60     * @param string $filepath file path
 61     * @param string $filename file name
 62     * @return file_info|null file_info instance or null if not found or access not allowed
 63     */
 64    public function get_file_info($component, $filearea, $itemid, $filepath, $filename) {
 65        // try to emulate require_login() tests here
 66        if (!isloggedin()) {
 67            return null;
 68        }
 69
 70        if (!$this->course->visible and !has_capability('moodle/course:viewhiddencourses', $this->context)) {
 71            return null;
 72        }
 73
 74        if (!is_viewing($this->context) and !$this->browser->is_enrolled($this->course->id)) {
 75            // no peaking here if not enrolled or inspector
 76            return null;
 77        }
 78
 79        if (empty($component)) {
 80            return $this;
 81        }
 82
 83        $methodname = "get_area_{$component}_{$filearea}";
 84
 85        if (method_exists($this, $methodname)) {
 86            return $this->$methodname($itemid, $filepath, $filename);
 87        }
 88
 89        return null;
 90    }
 91
 92    /**
 93     * Returns list of areas inside this course
 94     *
 95     * @param string $extensions Only return areas that have files with these extensions
 96     * @param bool $returnemptyfolders return all areas always, if true it will ignore the previous argument
 97     * @return array
 98     */
 99    protected function get_course_areas($extensions = '*', $returnemptyfolders = false) {
100        global $DB;
101
102        $allareas = [
103            'course_summary',
104            'course_overviewfiles',
105            'course_section',
106            'backup_section',
107            'backup_course',
108            'backup_automated',
109            'course_legacy'
110        ];
111
112        if ($returnemptyfolders) {
113            return $allareas;
114        }
115
116        $params1 = ['contextid' => $this->context->id, 'emptyfilename' => '.'];
117        $sql1 = "SELECT " . $DB->sql_concat('f.component', "'_'", 'f.filearea') . "
118            FROM {files} f
119            WHERE f.filename <> :emptyfilename AND f.contextid = :contextid ";
120        $sql3 = ' GROUP BY f.component, f.filearea';
121        list($sql2, $params2) = $this->build_search_files_sql($extensions);
122        $areaswithfiles = $DB->get_fieldset_sql($sql1 . $sql2 . $sql3, array_merge($params1, $params2));
123
124        return array_intersect($allareas, $areaswithfiles);
125    }
126
127    /**
128     * Gets a stored file for the course summary filearea directory
129     *
130     * @param int $itemid item ID
131     * @param string $filepath file path
132     * @param string $filename file name
133     * @return file_info|null file_info instance or null if not found or access not allowed
134     */
135    protected function get_area_course_summary($itemid, $filepath, $filename) {
136        global $CFG;
137
138        if (!has_capability('moodle/course:update', $this->context)) {
139            return null;
140        }
141        if (is_null($itemid)) {
142            return $this;
143        }
144
145        $fs = get_file_storage();
146
147        $filepath = is_null($filepath) ? '/' : $filepath;
148        $filename = is_null($filename) ? '.' : $filename;
149        if (!$storedfile = $fs->get_file($this->context->id, 'course', 'summary', 0, $filepath, $filename)) {
150            if ($filepath === '/' and $filename === '.') {
151                $storedfile = new virtual_root_file($this->context->id, 'course', 'summary', 0);
152            } else {
153                // not found
154                return null;
155            }
156        }
157        $urlbase = $CFG->wwwroot.'/pluginfile.php';
158        return new file_info_stored($this->browser, $this->context, $storedfile, $urlbase, get_string('areacourseintro', 'repository'), false, true, true, false);
159    }
160
161    /**
162     * Gets a stored file for the course images filearea directory
163     *
164     * @param int $itemid item ID
165     * @param string $filepath file path
166     * @param string $filename file name
167     * @return file_info|null file_info instance or null if not found or access not allowed
168     */
169    protected function get_area_course_overviewfiles($itemid, $filepath, $filename) {
170        global $CFG;
171
172        if (!has_capability('moodle/course:update', $this->context)) {
173            return null;
174        }
175        if (is_null($itemid)) {
176            return $this;
177        }
178
179        $fs = get_file_storage();
180
181        $filepath = is_null($filepath) ? '/' : $filepath;
182        $filename = is_null($filename) ? '.' : $filename;
183        if (!$storedfile = $fs->get_file($this->context->id, 'course', 'overviewfiles', 0, $filepath, $filename)) {
184            if ($filepath === '/' and $filename === '.') {
185                $storedfile = new virtual_root_file($this->context->id, 'course', 'overviewfiles', 0);
186            } else {
187                // not found
188                return null;
189            }
190        }
191        $urlbase = $CFG->wwwroot.'/pluginfile.php';
192        return new file_info_stored($this->browser, $this->context, $storedfile, $urlbase, get_string('areacourseoverviewfiles', 'repository'), false, true, true, false);
193    }
194
195    /**
196     * Gets a stored file for the course section filearea directory
197     *
198     * @param int $itemid item ID
199     * @param string $filepath file path
200     * @param string $filename file name
201     * @return file_info|null file_info instance or null if not found or access not allowed
202     */
203    protected function get_area_course_section($itemid, $filepath, $filename) {
204        global $CFG, $DB;
205
206        if (!has_capability('moodle/course:update', $this->context)) {
207            return null;
208        }
209
210        if (empty($itemid)) {
211            // list all sections
212            return new file_info_area_course_section($this->browser, $this->context, $this->course, $this);
213        }
214
215        if (!$section = $DB->get_record('course_sections', array('course'=>$this->course->id, 'id'=>$itemid))) {
216            return null; // does not exist
217        }
218
219        $fs = get_file_storage();
220
221        $filepath = is_null($filepath) ? '/' : $filepath;
222        $filename = is_null($filename) ? '.' : $filename;
223        if (!$storedfile = $fs->get_file($this->context->id, 'course', 'section', $itemid, $filepath, $filename)) {
224            if ($filepath === '/' and $filename === '.') {
225                $storedfile = new virtual_root_file($this->context->id, 'course', 'section', $itemid);
226            } else {
227                // not found
228                return null;
229            }
230        }
231        $urlbase = $CFG->wwwroot.'/pluginfile.php';
232        require_once($CFG->dirroot.'/course/lib.php');
233        $sectionname = get_section_name($this->course, $section);
234        return new file_info_stored($this->browser, $this->context, $storedfile, $urlbase, $sectionname, true, true, true, false);
235    }
236
237    /**
238     * Gets a stored file for the course legacy filearea directory
239     *
240     * @param int $itemid item ID
241     * @param string $filepath file path
242     * @param string $filename file name
243     * @return file_info|null file_info instance or null if not found or access not allowed
244     */
245    protected function get_area_course_legacy($itemid, $filepath, $filename) {
246        if (!has_capability('moodle/course:managefiles', $this->context)) {
247            return null;
248        }
249
250        if ($this->course->id != SITEID and $this->course->legacyfiles != 2) {
251            // bad luck, legacy course files not used any more
252        }
253
254        if (is_null($itemid)) {
255            return $this;
256        }
257
258        $fs = get_file_storage();
259
260        $filepath = is_null($filepath) ? '/' : $filepath;
261        $filename = is_null($filename) ? '.' : $filename;
262        if (!$storedfile = $fs->get_file($this->context->id, 'course', 'legacy', 0, $filepath, $filename)) {
263            if ($filepath === '/' and $filename === '.') {
264                $storedfile = new virtual_root_file($this->context->id, 'course', 'legacy', 0);
265            } else {
266                // not found
267                return null;
268            }
269        }
270
271        return new file_info_area_course_legacy($this->browser, $this->context, $storedfile);
272    }
273
274    /**
275     * Gets a stored file for the backup course filearea directory
276     *
277     * @param int $itemid item ID
278     * @param string $filepath file path
279     * @param string $filename file name
280     * @return file_info|null file_info instance or null if not found or access not allowed
281     */
282    protected function get_area_backup_course($itemid, $filepath, $filename) {
283        global $CFG;
284
285        if (!has_capability('moodle/backup:backupcourse', $this->context) and !has_capability('moodle/restore:restorecourse', $this->context)) {
286            return null;
287        }
288        if (is_null($itemid)) {
289            return $this;
290        }
291
292        $fs = get_file_storage();
293
294        $filepath = is_null($filepath) ? '/' : $filepath;
295        $filename = is_null($filename) ? '.' : $filename;
296        if (!$storedfile = $fs->get_file($this->context->id, 'backup', 'course', 0, $filepath, $filename)) {
297            if ($filepath === '/' and $filename === '.') {
298                $storedfile = new virtual_root_file($this->context->id, 'backup', 'course', 0);
299            } else {
300                // not found
301                return null;
302            }
303        }
304
305        $downloadable = has_capability('moodle/backup:downloadfile', $this->context);
306        $uploadable   = has_capability('moodle/restore:uploadfile', $this->context);
307
308        $urlbase = $CFG->wwwroot.'/pluginfile.php';
309        return new file_info_stored($this->browser, $this->context, $storedfile, $urlbase, get_string('coursebackup', 'repository'), false, $downloadable, $uploadable, false);
310    }
311
312    /**
313     * Gets a stored file for the automated backup filearea directory
314     *
315     * @param int $itemid item ID
316     * @param string $filepath file path
317     * @param string $filename file name
318     * @return file_info|null
319     */
320    protected function get_area_backup_automated($itemid, $filepath, $filename) {
321        global $CFG;
322
323        if (!has_capability('moodle/restore:viewautomatedfilearea', $this->context)) {
324            return null;
325        }
326        if (is_null($itemid)) {
327            return $this;
328        }
329
330        $fs = get_file_storage();
331
332        $filepath = is_null($filepath) ? '/' : $filepath;
333        $filename = is_null($filename) ? '.' : $filename;
334        if (!$storedfile = $fs->get_file($this->context->id, 'backup', 'automated', 0, $filepath, $filename)) {
335            if ($filepath === '/' and $filename === '.') {
336                $storedfile = new virtual_root_file($this->context->id, 'backup', 'automated', 0);
337            } else {
338                // not found
339                return null;
340            }
341        }
342
343        // Automated backup files are only downloadable if the user has both 'backup:downloadfile and 'restore:userinfo'.
344        $downloadable = has_capability('moodle/backup:downloadfile', $this->context) &&
345                        has_capability('moodle/restore:userinfo', $this->context);
346        $uploadable   = false;
347
348        $urlbase = $CFG->wwwroot.'/pluginfile.php';
349        return new file_info_stored($this->browser, $this->context, $storedfile, $urlbase, get_string('automatedbackup', 'repository'), true, $downloadable, $uploadable, false);
350    }
351
352    /**
353     * Gets a stored file for the backup section filearea directory
354     *
355     * @param int $itemid item ID
356     * @param string $filepath file path
357     * @param string $filename file name
358     * @return file_info|null file_info instance or null if not found or access not allowed
359     */
360    protected function get_area_backup_section($itemid, $filepath, $filename) {
361        global $CFG, $DB;
362
363        if (!has_capability('moodle/backup:backupcourse', $this->context) and !has_capability('moodle/restore:restorecourse', $this->context)) {
364            return null;
365        }
366
367        if (empty($itemid)) {
368            // list all sections
369            return new file_info_area_backup_section($this->browser, $this->context, $this->course, $this);
370        }
371
372        if (!$section = $DB->get_record('course_sections', array('course'=>$this->course->id, 'id'=>$itemid))) {
373            return null; // does not exist
374        }
375
376        $fs = get_file_storage();
377
378        $filepath = is_null($filepath) ? '/' : $filepath;
379        $filename = is_null($filename) ? '.' : $filename;
380        if (!$storedfile = $fs->get_file($this->context->id, 'backup', 'section', $itemid, $filepath, $filename)) {
381            if ($filepath === '/' and $filename === '.') {
382                $storedfile = new virtual_root_file($this->context->id, 'backup', 'section', $itemid);
383            } else {
384                // not found
385                return null;
386            }
387        }
388
389        $downloadable = has_capability('moodle/backup:downloadfile', $this->context);
390        $uploadable   = has_capability('moodle/restore:uploadfile', $this->context);
391
392        $urlbase = $CFG->wwwroot.'/pluginfile.php';
393        return new file_info_stored($this->browser, $this->context, $storedfile, $urlbase, $section->id, true, $downloadable, $uploadable, false);
394    }
395
396    /**
397     * Returns localised visible name.
398     *
399     * @return string
400     */
401    public function get_visible_name() {
402        return ($this->course->id == SITEID) ? get_string('frontpage', 'admin') : format_string(get_course_display_name_for_list($this->course), true, array('context'=>$this->context));
403    }
404
405    /**
406     * Whether or not new files or directories can be added
407     *
408     * @return bool
409     */
410    public function is_writable() {
411        return false;
412    }
413
414    /**
415     * Whether or not this is a directory
416     *
417     * @return bool
418     */
419    public function is_directory() {
420        return true;
421    }
422
423    /**
424     * Returns list of children.
425     *
426     * @return array of file_info instances
427     */
428    public function get_children() {
429        return $this->get_filtered_children('*', false, true);
430    }
431
432    /**
433     * Returns the child module if it is accessible by the current user
434     *
435     * @param cm_info|int $cm
436     * @return file_info_context_module|null
437     */
438    protected function get_child_module($cm) {
439        $cmid = is_object($cm) ? $cm->id : $cm;
440        if (!array_key_exists($cmid, $this->childrenmodules)) {
441            $this->childrenmodules[$cmid] = null;
442            if (!($cm instanceof cm_info)) {
443                $cms = get_fast_modinfo($this->course)->cms;
444                $cm = array_key_exists($cmid, $cms) ? $cms[$cmid] : null;
445            }
446            if ($cm && $cm->uservisible) {
447                $this->childrenmodules[$cmid] = new file_info_context_module($this->browser,
448                    $cm->context, $this->course, $cm, $cm->modname);
449            }
450        }
451        return $this->childrenmodules[$cmid];
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        $children = array();
465
466        $courseareas = $this->get_course_areas($extensions, $returnemptyfolders);
467        foreach ($courseareas as $areaname) {
468            $area = explode('_', $areaname, 2);
469            if ($child = $this->get_file_info($area[0], $area[1], 0, '/', '.')) {
470                $children[] = $child;
471                if (($countonly !== false) && count($children) >= $countonly) {
472                    return $countonly;
473                }
474            }
475        }
476
477        $cnt = count($children);
478        if (!has_capability('moodle/course:managefiles', $this->context)) {
479            // 'managefiles' capability is checked in every activity module callback.
480            // Don't even waste time on retrieving the modules if we can't browse the files anyway
481        } else {
482            if ($returnemptyfolders) {
483                $modinfo = get_fast_modinfo($this->course);
484                foreach ($modinfo->cms as $cminfo) {
485                    if ($child = $this->get_child_module($cminfo)) {
486                        $children[] = $child;
487                        $cnt++;
488                    }
489                }
490            } else if ($moduleareas = $this->get_module_areas_with_files($extensions)) {
491                // We found files in some of the modules.
492                // Create array of children modules ordered with the same way as cms in modinfo.
493                $modulechildren = array_fill_keys(array_keys(get_fast_modinfo($this->course)->get_cms()), null);
494                foreach ($moduleareas as $area) {
495                    if ($modulechildren[$area->cmid]) {
496                        // We already found non-empty area within the same module, do not analyse other areas.
497                        continue;
498                    }
499                    if ($child = $this->get_child_module($area->cmid)) {
500                        if ($child->get_file_info($area->component, $area->filearea, $area->itemid, null, null)) {
501                            $modulechildren[$area->cmid] = $child;
502                            $cnt++;
503                            if (($countonly !== false) && $cnt >= $countonly) {
504                                return $cnt;
505                            }
506                        }
507                    }
508                }
509                $children = array_merge($children, array_values(array_filter($modulechildren)));
510            }
511        }
512
513        if ($countonly !== false) {
514            return count($children);
515        }
516        return $children;
517    }
518
519    /**
520     * Returns list of areas inside the course modules that have files with the given extension
521     *
522     * @param string $extensions
523     * @return array
524     */
525    protected function get_module_areas_with_files($extensions = '*') {
526        global $DB;
527
528        $params1 = ['contextid' => $this->context->id,
529            'emptyfilename' => '.',
530            'contextlevel' => CONTEXT_MODULE,
531            'course' => $this->course->id];
532        $ctxfieldsas = context_helper::get_preload_record_columns_sql('ctx');
533        $ctxfields = implode(', ', array_keys(context_helper::get_preload_record_columns('ctx')));
534        $sql1 = "SELECT
535                    ctx.id AS contextid,
536                    f.component,
537                    f.filearea,
538                    f.itemid,
539                    ctx.instanceid AS cmid,
540                    {$ctxfieldsas}
541            FROM {files} f
542            INNER JOIN {context} ctx ON ctx.id = f.contextid
543            INNER JOIN {course_modules} cm ON cm.id = ctx.instanceid
544            WHERE f.filename <> :emptyfilename
545              AND cm.course = :course
546              AND ctx.contextlevel = :contextlevel";
547        $sql3 = "
548            GROUP BY ctx.id, f.component, f.filearea, f.itemid, {$ctxfields}
549            ORDER BY ctx.id, f.component, f.filearea, f.itemid";
550        list($sql2, $params2) = $this->build_search_files_sql($extensions);
551        $areas = [];
552        if ($rs = $DB->get_recordset_sql($sql1. $sql2 . $sql3, array_merge($params1, $params2))) {
553            foreach ($rs as $record) {
554                context_helper::preload_from_record($record);
555                $areas[] = $record;
556            }
557            $rs->close();
558        }
559
560        // Sort areas so 'backup' and 'intro' are in the beginning of the list, they are the easiest to check access to.
561        usort($areas, function($a, $b) {
562            $aeasy = ($a->filearea === 'intro' && substr($a->component, 0, 4) === 'mod_') ||
563                ($a->filearea === 'activity' && $a->component === 'backup');
564            $beasy = ($b->filearea === 'intro' && substr($b->component, 0, 4) === 'mod_') ||
565                ($b->filearea === 'activity' && $b->component === 'backup');
566            return $aeasy == $beasy ? 0 : ($aeasy ? -1 : 1);
567        });
568        return $areas;
569    }
570
571    /**
572     * Returns list of children which are either files matching the specified extensions
573     * or folders that contain at least one such file.
574     *
575     * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
576     * @return array of file_info instances
577     */
578    public function get_non_empty_children($extensions = '*') {
579        return $this->get_filtered_children($extensions, false);
580    }
581
582    /**
583     * Returns the number of children which are either files matching the specified extensions
584     * or folders containing at least one such file.
585     *
586     * @param string|array $extensions, for example '*' or array('.gif','.jpg')
587     * @param int $limit stop counting after at least $limit non-empty children are found
588     * @return int
589     */
590    public function count_non_empty_children($extensions = '*', $limit = 1) {
591        return $this->get_filtered_children($extensions, $limit);
592    }
593
594    /**
595     * Returns parent file_info instance
596     *
597     * @return file_info or null for root
598     */
599    public function get_parent() {
600        $parent = $this->context->get_parent_context();
601        return $this->browser->get_file_info($parent);
602    }
603}
604
605
606/**
607 * Subclass of file_info_stored for files in the course files area.
608 *
609 * @package   core_files
610 * @copyright 2008 Petr Skoda (http://skodak.org)
611 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
612 */
613class file_info_area_course_legacy extends file_info_stored {
614    /**
615     * Constructor
616     *
617     * @param file_browser $browser file browser instance
618     * @param stdClass $context context object
619     * @param stored_file $storedfile stored_file instance
620     */
621    public function __construct($browser, $context, $storedfile) {
622        global $CFG;
623        $urlbase = $CFG->wwwroot.'/file.php';
624        parent::__construct($browser, $context, $storedfile, $urlbase, get_string('coursefiles'), false, true, true, false);
625    }
626
627    /**
628     * Returns file download url
629     *
630     * @param bool $forcedownload whether or not force download
631     * @param bool $https whether or not force https
632     * @return string url
633     */
634    public function get_url($forcedownload=false, $https=false) {
635        if (!$this->is_readable()) {
636            return null;
637        }
638
639        if ($this->lf->is_directory()) {
640            return null;
641        }
642
643        $filepath = $this->lf->get_filepath();
644        $filename = $this->lf->get_filename();
645        $courseid = $this->context->instanceid;
646
647        $path = '/'.$courseid.$filepath.$filename;
648
649        return file_encode_url($this->urlbase, $path, $forcedownload, $https);
650    }
651
652    /**
653     * Returns list of children.
654     *
655     * @return array of file_info instances
656     */
657    public function get_children() {
658        if (!$this->lf->is_directory()) {
659            return array();
660        }
661
662        $result = array();
663        $fs = get_file_storage();
664
665        $storedfiles = $fs->get_directory_files($this->context->id, 'course', 'legacy', 0, $this->lf->get_filepath(), false, true, "filepath ASC, filename ASC");
666        foreach ($storedfiles as $file) {
667            $result[] = new file_info_area_course_legacy($this->browser, $this->context, $file);
668        }
669
670        return $result;
671    }
672
673    /**
674     * Returns list of children which are either files matching the specified extensions
675     * or folders that contain at least one such file.
676     *
677     * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
678     * @return array of file_info instances
679     */
680    public function get_non_empty_children($extensions = '*') {
681        if (!$this->lf->is_directory()) {
682            return array();
683        }
684
685        $result = array();
686        $fs = get_file_storage();
687
688        $storedfiles = $fs->get_directory_files($this->context->id, 'course', 'legacy', 0,
689                                                $this->lf->get_filepath(), false, true, "filepath, filename");
690        foreach ($storedfiles as $file) {
691            $extension = core_text::strtolower(pathinfo($file->get_filename(), PATHINFO_EXTENSION));
692            if ($file->is_directory() || $extensions === '*' || (!empty($extension) && in_array('.'.$extension, $extensions))) {
693                $fileinfo = new file_info_area_course_legacy($this->browser, $this->context, $file, $this->urlbase, $this->topvisiblename,
694                                                 $this->itemidused, $this->readaccess, $this->writeaccess, false);
695                if (!$file->is_directory() || $fileinfo->count_non_empty_children($extensions)) {
696                    $result[] = $fileinfo;
697                }
698            }
699        }
700
701        return $result;
702    }
703}
704
705/**
706 * Represents a course category context in the tree navigated by {@link file_browser}.
707 *
708 * @package    core_files
709 * @copyright  2008 Petr Skoda (http://skodak.org)
710 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
711 */
712class file_info_area_course_section extends file_info {
713    /** @var stdClass course object */
714    protected $course;
715    /** @var file_info_context_course course file info object */
716    protected $courseinfo;
717
718    /**
719     * Constructor
720     *
721     * @param file_browser $browser file browser instance
722     * @param stdClass $context context object
723     * @param stdClass $course course object
724     * @param file_info_context_course $courseinfo file info instance
725     */
726    public function __construct($browser, $context, $course, file_info_context_course $courseinfo) {
727        parent::__construct($browser, $context);
728        $this->course     = $course;
729        $this->courseinfo = $courseinfo;
730    }
731
732    /**
733     * Returns list of standard virtual file/directory identification.
734     * The difference from stored_file parameters is that null values
735     * are allowed in all fields
736     *
737     * @return array with keys contextid, filearea, itemid, filepath and filename
738     */
739    public function get_params() {
740        return array('contextid' => $this->context->id,
741                     'component' => 'course',
742                     'filearea'  => 'section',
743                     'itemid'    => null,
744                     'filepath'  => null,
745                     'filename'  => null);
746    }
747
748    /**
749     * Returns localised visible name.
750     *
751     * @return string
752     */
753    public function get_visible_name() {
754        //$format = $this->course->format;
755        $sectionsname = get_string("coursesectionsummaries");
756
757        return $sectionsname;
758    }
759
760    /**
761     * Return whether or not new files or directories can be added
762     *
763     * @return bool
764     */
765    public function is_writable() {
766        return false;
767    }
768
769    /**
770     * Return whether or not this is a empty area
771     *
772     * @return bool
773     */
774    public function is_empty_area() {
775        $fs = get_file_storage();
776        return $fs->is_area_empty($this->context->id, 'course', 'section');
777    }
778
779    /**
780     * Return whether or not this is a empty area
781     *
782     * @return bool
783     */
784    public function is_directory() {
785        return true;
786    }
787
788    /**
789     * Returns list of children.
790     *
791     * @return array of file_info instances
792     */
793    public function get_children() {
794        global $DB;
795
796        $children = array();
797
798        $course_sections = $DB->get_records('course_sections', array('course'=>$this->course->id), 'section');
799        foreach ($course_sections as $section) {
800            if ($child = $this->courseinfo->get_file_info('course', 'section', $section->id, '/', '.')) {
801                $children[] = $child;
802            }
803        }
804
805        return $children;
806    }
807
808    /**
809     * Returns the number of children which are either files matching the specified extensions
810     * or folders containing at least one such file.
811     *
812     * @param string|array $extensions, for example '*' or array('.gif','.jpg')
813     * @param int $limit stop counting after at least $limit non-empty children are found
814     * @return int
815     */
816    public function count_non_empty_children($extensions = '*', $limit = 1) {
817        global $DB;
818        $params1 = array(
819            'courseid' => $this->course->id,
820            'contextid' => $this->context->id,
821            'component' => 'course',
822            'filearea' => 'section',
823            'emptyfilename' => '.');
824        $sql1 = "SELECT DISTINCT cs.id FROM {files} f, {course_sections} cs
825            WHERE cs.course = :courseid
826            AND f.contextid = :contextid
827            AND f.component = :component
828            AND f.filearea = :filearea
829            AND f.itemid = cs.id
830            AND f.filename <> :emptyfilename";
831        list($sql2, $params2) = $this->build_search_files_sql($extensions);
832        $rs = $DB->get_recordset_sql($sql1. ' '. $sql2, array_merge($params1, $params2));
833        $cnt = 0;
834        foreach ($rs as $record) {
835            if ((++$cnt) >= $limit) {
836                break;
837            }
838        }
839        $rs->close();
840        return $cnt;
841    }
842
843    /**
844     * Returns parent file_info instance
845     *
846     * @return file_info|null file_info or null for root
847     */
848    public function get_parent() {
849        return $this->courseinfo;
850    }
851}
852
853
854/**
855 * Implementation of course section backup area
856 *
857 * @package    core_files
858 * @copyright  2008 Petr Skoda (http://skodak.org)
859 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
860 */
861class file_info_area_backup_section extends file_info {
862    /** @var stdClass course object */
863    protected $course;
864    /** @var file_info_context_course course file info object */
865    protected $courseinfo;
866
867    /**
868     * Constructor
869     *
870     * @param file_browser $browser file browser instance
871     * @param stdClass $context context object
872     * @param stdClass $course course object
873     * @param file_info_context_course $courseinfo file info instance
874     */
875    public function __construct($browser, $context, $course, file_info_context_course $courseinfo) {
876        parent::__construct($browser, $context);
877        $this->course     = $course;
878        $this->courseinfo = $courseinfo;
879    }
880
881    /**
882     * Returns list of standard virtual file/directory identification.
883     * The difference from stored_file parameters is that null values
884     * are allowed in all fields
885     *
886     * @return array with keys contextid, component, filearea, itemid, filepath and filename
887     */
888    public function get_params() {
889        return array('contextid' => $this->context->id,
890                     'component' => 'backup',
891                     'filearea'  => 'section',
892                     'itemid'    => null,
893                     'filepath'  => null,
894                     'filename'  => null);
895    }
896
897    /**
898     * Returns localised visible name.
899     *
900     * @return string
901     */
902    public function get_visible_name() {
903        return get_string('sectionbackup', 'repository');
904    }
905
906    /**
907     * Return whether or not new files and directories can be added
908     *
909     * @return bool
910     */
911    public function is_writable() {
912        return false;
913    }
914
915    /**
916     * Whether or not this is an empty area
917     *
918     * @return bool
919     */
920    public function is_empty_area() {
921        $fs = get_file_storage();
922        return $fs->is_area_empty($this->context->id, 'backup', 'section');
923    }
924
925    /**
926     * Return whether or not this is a directory
927     *
928     * @return bool
929     */
930    public function is_directory() {
931        return true;
932    }
933
934    /**
935     * Returns list of children.
936     *
937     * @return array of file_info instances
938     */
939    public function get_children() {
940        global $DB;
941
942        $children = array();
943
944        $course_sections = $DB->get_records('course_sections', array('course'=>$this->course->id), 'section');
945        foreach ($course_sections as $section) {
946            if ($child = $this->courseinfo->get_file_info('backup', 'section', $section->id, '/', '.')) {
947                $children[] = $child;
948            }
949        }
950
951        return $children;
952    }
953
954    /**
955     * Returns the number of children which are either files matching the specified extensions
956     * or folders containing at least one such file.
957     *
958     * @param string|array $extensions, for example '*' or array('.gif','.jpg')
959     * @param int $limit stop counting after at least $limit non-empty children are found
960     * @return int
961     */
962    public function count_non_empty_children($extensions = '*', $limit = 1) {
963        global $DB;
964        $params1 = array(
965            'courseid' => $this->course->id,
966            'contextid' => $this->context->id,
967            'component' => 'backup',
968            'filearea' => 'section',
969            'emptyfilename' => '.');
970        $sql1 = "SELECT DISTINCT cs.id AS sectionid FROM {files} f, {course_sections} cs
971            WHERE cs.course = :courseid
972            AND f.contextid = :contextid
973            AND f.component = :component
974            AND f.filearea = :filearea
975            AND f.itemid = cs.id
976            AND f.filename <> :emptyfilename";
977        list($sql2, $params2) = $this->build_search_files_sql($extensions);
978        $rs = $DB->get_recordset_sql($sql1. ' '. $sql2, array_merge($params1, $params2));
979        $cnt = 0;
980        foreach ($rs as $record) {
981            if ((++$cnt) >= $limit) {
982                break;
983            }
984        }
985        $rs->close();
986        return $cnt;
987    }
988
989    /**
990     * Returns parent file_info instance
991     *
992     * @return file_info or null for root
993     */
994    public function get_parent() {
995        return $this->browser->get_file_info($this->context);
996    }
997}