PageRenderTime 27ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/filebrowser/file_info_context_module.php

https://gitlab.com/unofficial-mirrors/moodle
PHP | 347 lines | 179 code | 39 blank | 129 comment | 38 complexity | ada7bf2f3a2b9517146ea8f05ce7a0f7 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. * Utility class for browsing of module files.
  18. *
  19. * @package core_files
  20. * @copyright 2008 Petr Skoda (http://skodak.org)
  21. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  22. */
  23. defined('MOODLE_INTERNAL') || die();
  24. /**
  25. * Represents a module context in the tree navigated by {@link file_browser}.
  26. *
  27. * @package core_files
  28. * @copyright 2008 Petr Skoda (http://skodak.org)
  29. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  30. */
  31. class file_info_context_module extends file_info {
  32. /** @var stdClass Course object */
  33. protected $course;
  34. /** @var cm_info Course module object */
  35. protected $cm;
  36. /** @var string Module name */
  37. protected $modname;
  38. /** @var array Available file areas */
  39. protected $areas;
  40. /** @var array caches the result of last call to get_non_empty_children() */
  41. protected $nonemptychildren;
  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. * @param stdClass $cm course module object
  49. * @param string $modname module name
  50. */
  51. public function __construct($browser, $context, $course, $cm, $modname) {
  52. global $CFG;
  53. parent::__construct($browser, $context);
  54. $this->course = $course;
  55. $this->cm = cm_info::create($cm);
  56. $this->modname = $this->cm->modname;
  57. $this->nonemptychildren = null;
  58. if ($functionname = component_callback_exists('mod_'.$modname, 'get_file_areas')) {
  59. $cm = $this->cm->get_course_module_record();
  60. $this->areas = $functionname($course, $cm, $context);
  61. } else {
  62. $this->areas = array();
  63. }
  64. unset($this->areas['intro']); // hardcoded, ignore attempts to override it
  65. }
  66. /**
  67. * Return information about this specific context level
  68. *
  69. * @param string $component component
  70. * @param string $filearea file area
  71. * @param int $itemid item ID
  72. * @param string $filepath file path
  73. * @param string $filename file name
  74. * @return file_info|null
  75. */
  76. public function get_file_info($component, $filearea, $itemid, $filepath, $filename) {
  77. // try to emulate require_login() tests here
  78. if (!isloggedin()) {
  79. return null;
  80. }
  81. $coursecontext = $this->context->get_course_context(true);
  82. if (!$this->course->visible and !has_capability('moodle/course:viewhiddencourses', $coursecontext)) {
  83. return null;
  84. }
  85. if (!is_viewing($this->context) and !$this->browser->is_enrolled($this->course->id)) {
  86. // no peaking here if not enrolled or inspector
  87. return null;
  88. }
  89. if (!$this->cm->uservisible) {
  90. // activity hidden sorry
  91. return null;
  92. }
  93. if (empty($component)) {
  94. return $this;
  95. }
  96. if ($component == 'mod_'.$this->modname and $filearea === 'intro') {
  97. return $this->get_area_intro($itemid, $filepath, $filename);
  98. } else if ($component == 'backup' and $filearea === 'activity') {
  99. return $this->get_area_backup($itemid, $filepath, $filename);
  100. }
  101. if ($functionname = component_callback_exists('mod_'.$this->modname, 'get_file_info')) {
  102. $cm = $this->cm->get_course_module_record();
  103. return $functionname($this->browser, $this->areas, $this->course, $cm,
  104. $this->context, $filearea, $itemid, $filepath, $filename);
  105. }
  106. return null;
  107. }
  108. /**
  109. * Get a file from module intro area
  110. *
  111. * @param int $itemid item ID
  112. * @param string $filepath file path
  113. * @param string $filename file name
  114. * @return file_info|null
  115. */
  116. protected function get_area_intro($itemid, $filepath, $filename) {
  117. global $CFG;
  118. if (!plugin_supports('mod', $this->modname, FEATURE_MOD_INTRO, true) or !has_capability('moodle/course:managefiles', $this->context)) {
  119. return null;
  120. }
  121. $fs = get_file_storage();
  122. $filepath = is_null($filepath) ? '/' : $filepath;
  123. $filename = is_null($filename) ? '.' : $filename;
  124. if (!$storedfile = $fs->get_file($this->context->id, 'mod_'.$this->modname, 'intro', 0, $filepath, $filename)) {
  125. if ($filepath === '/' and $filename === '.') {
  126. $storedfile = new virtual_root_file($this->context->id, 'mod_'.$this->modname, 'intro', 0);
  127. } else {
  128. // not found
  129. return null;
  130. }
  131. }
  132. $urlbase = $CFG->wwwroot.'/pluginfile.php';
  133. return new file_info_stored($this->browser, $this->context, $storedfile, $urlbase, get_string('moduleintro'), false, true, true, false);
  134. }
  135. /**
  136. * Get a file from module backup area
  137. *
  138. * @param int $itemid item ID
  139. * @param string $filepath file path
  140. * @param string $filename file name
  141. * @return file_info|null
  142. */
  143. protected function get_area_backup($itemid, $filepath, $filename) {
  144. global $CFG;
  145. if (!has_capability('moodle/backup:backupactivity', $this->context)) {
  146. return null;
  147. }
  148. $fs = get_file_storage();
  149. $filepath = is_null($filepath) ? '/' : $filepath;
  150. $filename = is_null($filename) ? '.' : $filename;
  151. if (!$storedfile = $fs->get_file($this->context->id, 'backup', 'activity', 0, $filepath, $filename)) {
  152. if ($filepath === '/' and $filename === '.') {
  153. $storedfile = new virtual_root_file($this->context->id, 'backup', 'activity', 0);
  154. } else {
  155. // not found
  156. return null;
  157. }
  158. }
  159. $downloadable = has_capability('moodle/backup:downloadfile', $this->context);
  160. $uploadable = has_capability('moodle/restore:uploadfile', $this->context);
  161. $urlbase = $CFG->wwwroot.'/pluginfile.php';
  162. return new file_info_stored($this->browser, $this->context, $storedfile, $urlbase, get_string('activitybackup', 'repository'), false, $downloadable, $uploadable, false);
  163. }
  164. /**
  165. * Returns localised visible name.
  166. *
  167. * @return string
  168. */
  169. public function get_visible_name() {
  170. return $this->cm->get_formatted_name().' ('.$this->cm->get_module_type_name().')';
  171. }
  172. /**
  173. * Whether or not files or directories can be added
  174. *
  175. * @return bool
  176. */
  177. public function is_writable() {
  178. return false;
  179. }
  180. /**
  181. * Whether or not this is an emtpy area
  182. *
  183. * @return bool
  184. */
  185. public function is_empty_area() {
  186. if ($child = $this->get_area_backup(0, '/', '.')) {
  187. if (!$child->is_empty_area()) {
  188. return false;
  189. }
  190. }
  191. if ($child = $this->get_area_intro(0, '/', '.')) {
  192. if (!$child->is_empty_area()) {
  193. return false;
  194. }
  195. }
  196. foreach ($this->areas as $area=>$desctiption) {
  197. if ($child = $this->get_file_info('mod_'.$this->modname, $area, null, null, null)) {
  198. if (!$child->is_empty_area()) {
  199. return false;
  200. }
  201. }
  202. }
  203. return true;
  204. }
  205. /**
  206. * Whether or not this is a directory
  207. *
  208. * @return bool
  209. */
  210. public function is_directory() {
  211. return true;
  212. }
  213. /**
  214. * Returns list of children.
  215. *
  216. * @return array of file_info instances
  217. */
  218. public function get_children() {
  219. return $this->get_filtered_children('*', false, true);
  220. }
  221. /**
  222. * Help function to return files matching extensions or their count
  223. *
  224. * @param string|array $extensions, either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
  225. * @param bool|int $countonly if false returns the children, if an int returns just the
  226. * count of children but stops counting when $countonly number of children is reached
  227. * @param bool $returnemptyfolders if true returns items that don't have matching files inside
  228. * @return array|int array of file_info instances or the count
  229. */
  230. private function get_filtered_children($extensions = '*', $countonly = false, $returnemptyfolders = false) {
  231. global $DB;
  232. // prepare list of areas including intro and backup
  233. $areas = array(
  234. array('mod_'.$this->modname, 'intro'),
  235. array('backup', 'activity')
  236. );
  237. foreach ($this->areas as $area => $desctiption) {
  238. $areas[] = array('mod_'.$this->modname, $area);
  239. }
  240. $params1 = array('contextid' => $this->context->id, 'emptyfilename' => '.');
  241. list($sql2, $params2) = $this->build_search_files_sql($extensions);
  242. $children = array();
  243. foreach ($areas as $area) {
  244. if (!$returnemptyfolders) {
  245. // fast pre-check if there are any files in the filearea
  246. $params1['component'] = $area[0];
  247. $params1['filearea'] = $area[1];
  248. if (!$DB->record_exists_sql('SELECT 1 from {files}
  249. WHERE contextid = :contextid
  250. AND filename <> :emptyfilename
  251. AND component = :component
  252. AND filearea = :filearea '.$sql2,
  253. array_merge($params1, $params2))) {
  254. continue;
  255. }
  256. }
  257. if ($child = $this->get_file_info($area[0], $area[1], null, null, null)) {
  258. if ($returnemptyfolders || $child->count_non_empty_children($extensions)) {
  259. $children[] = $child;
  260. if ($countonly !== false && count($children) >= $countonly) {
  261. break;
  262. }
  263. }
  264. }
  265. }
  266. if ($countonly !== false) {
  267. return count($children);
  268. }
  269. return $children;
  270. }
  271. /**
  272. * Returns list of children which are either files matching the specified extensions
  273. * or folders that contain at least one such file.
  274. *
  275. * @param string|array $extensions either '*' or array of lowercase extensions, i.e. array('.gif','.jpg')
  276. * @return array of file_info instances
  277. */
  278. public function get_non_empty_children($extensions = '*') {
  279. if ($this->nonemptychildren !== null) {
  280. return $this->nonemptychildren;
  281. }
  282. $this->nonemptychildren = $this->get_filtered_children($extensions);
  283. return $this->nonemptychildren;
  284. }
  285. /**
  286. * Returns the number of children which are either files matching the specified extensions
  287. * or folders containing at least one such file.
  288. *
  289. * @param string|array $extensions for example '*' or array('.gif','.jpg')
  290. * @param int $limit stop counting after at least $limit non-empty children are found
  291. * @return int
  292. */
  293. public function count_non_empty_children($extensions = '*', $limit = 1) {
  294. if ($this->nonemptychildren !== null) {
  295. return count($this->nonemptychildren);
  296. }
  297. return $this->get_filtered_children($extensions, $limit);
  298. }
  299. /**
  300. * Returns parent file_info instance
  301. *
  302. * @return file_info|null file_info or null for root
  303. */
  304. public function get_parent() {
  305. $parent = $this->context->get_parent_context();
  306. return $this->browser->get_file_info($parent);
  307. }
  308. }