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 26 defined('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 */ 35 class 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 */ 613 class 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 */ 712 class 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 */ 861 class 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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body