2008-08-08 03:47:14 +00:00
|
|
|
<?php
|
2009-12-04 09:19:54 +00:00
|
|
|
|
|
|
|
// This file is part of Moodle - http://moodle.org/
|
|
|
|
//
|
|
|
|
// Moodle is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// Moodle is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
2008-08-08 03:47:14 +00:00
|
|
|
|
2008-09-18 05:33:44 +00:00
|
|
|
/**
|
2009-12-04 09:19:54 +00:00
|
|
|
* repository_local class is used to browse moodle files
|
2008-09-18 05:33:44 +00:00
|
|
|
*
|
2012-03-21 13:55:22 +08:00
|
|
|
* @since 2.0
|
|
|
|
* @package repository_local
|
2010-09-06 11:29:21 +00:00
|
|
|
* @copyright 2009 Dongsheng Cai <dongsheng@moodle.com>
|
|
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
2008-09-18 05:33:44 +00:00
|
|
|
*/
|
2009-12-04 09:19:54 +00:00
|
|
|
|
2008-08-22 07:36:11 +00:00
|
|
|
class repository_local extends repository {
|
2008-09-18 05:33:44 +00:00
|
|
|
/**
|
2010-04-28 16:49:51 +00:00
|
|
|
* local plugin doesn't require login, so list all files
|
2009-05-20 05:24:53 +00:00
|
|
|
* @return mixed
|
2008-09-18 05:33:44 +00:00
|
|
|
*/
|
2009-09-03 03:12:24 +00:00
|
|
|
public function print_login() {
|
2008-08-08 03:47:14 +00:00
|
|
|
return $this->get_listing();
|
|
|
|
}
|
2008-08-20 04:24:38 +00:00
|
|
|
|
2008-09-18 05:33:44 +00:00
|
|
|
/**
|
2009-12-04 09:19:54 +00:00
|
|
|
* Get file listing
|
2008-09-18 05:33:44 +00:00
|
|
|
*
|
2009-05-20 05:24:53 +00:00
|
|
|
* @param string $encodedpath
|
|
|
|
* @return mixed
|
2008-09-18 05:33:44 +00:00
|
|
|
*/
|
2012-03-18 18:31:32 +01:00
|
|
|
public function get_listing($encodedpath = '', $page = '') {
|
2009-06-30 02:12:16 +00:00
|
|
|
global $CFG, $USER, $OUTPUT;
|
2009-05-20 05:24:53 +00:00
|
|
|
$ret = array();
|
|
|
|
$ret['dynload'] = true;
|
2009-06-25 04:12:43 +00:00
|
|
|
$ret['nosearch'] = true;
|
2010-05-19 02:49:18 +00:00
|
|
|
$ret['nologin'] = true;
|
2009-05-20 05:24:53 +00:00
|
|
|
$list = array();
|
2009-06-22 02:59:32 +00:00
|
|
|
|
2009-05-22 09:19:58 +00:00
|
|
|
if (!empty($encodedpath)) {
|
|
|
|
$params = unserialize(base64_decode($encodedpath));
|
|
|
|
if (is_array($params)) {
|
2011-09-24 15:07:27 +02:00
|
|
|
$component = is_null($params['component']) ? NULL : clean_param($params['component'], PARAM_COMPONENT);
|
|
|
|
$filearea = is_null($params['filearea']) ? NULL : clean_param($params['filearea'], PARAM_AREA);
|
2010-08-02 15:47:42 +00:00
|
|
|
$itemid = is_null($params['itemid']) ? NULL : clean_param($params['itemid'], PARAM_INT);
|
|
|
|
$filepath = is_null($params['filepath']) ? NULL : clean_param($params['filepath'], PARAM_PATH);;
|
|
|
|
$filename = is_null($params['filename']) ? NULL : clean_param($params['filename'], PARAM_FILE);
|
|
|
|
$context = get_context_instance_by_id(clean_param($params['contextid'], PARAM_INT));
|
2009-05-22 09:19:58 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$itemid = null;
|
|
|
|
$filename = null;
|
|
|
|
$filearea = null;
|
|
|
|
$filepath = null;
|
2010-07-06 07:15:08 +00:00
|
|
|
$component = null;
|
2010-07-19 17:44:23 +00:00
|
|
|
if (!empty($this->context)) {
|
|
|
|
list($context, $course, $cm) = get_context_info_array($this->context->id);
|
2012-03-21 13:55:22 +08:00
|
|
|
if (is_object($course)) {
|
|
|
|
$context = get_context_instance(CONTEXT_COURSE, $course->id);
|
|
|
|
} else {
|
|
|
|
$context = get_system_context();
|
|
|
|
}
|
2010-07-19 17:44:23 +00:00
|
|
|
} else {
|
|
|
|
$context = get_system_context();
|
|
|
|
}
|
2009-05-22 09:19:58 +00:00
|
|
|
}
|
|
|
|
|
2010-07-06 05:33:43 +00:00
|
|
|
$browser = get_file_browser();
|
|
|
|
|
2012-03-21 13:55:22 +08:00
|
|
|
$list = array();
|
2010-07-06 07:15:08 +00:00
|
|
|
if ($fileinfo = $browser->get_file_info($context, $component, $filearea, $itemid, $filepath, $filename)) {
|
2010-07-06 05:33:43 +00:00
|
|
|
// build file tree
|
2012-03-21 13:55:22 +08:00
|
|
|
$element = repository_local_file::retrieve_file_info($fileinfo, $this);
|
|
|
|
$nonemptychildren = $element->get_non_empty_children();
|
|
|
|
foreach ($nonemptychildren as $child) {
|
|
|
|
$list[] = (array)$child->get_node();
|
2009-05-20 05:24:53 +00:00
|
|
|
}
|
2010-07-20 04:54:57 +00:00
|
|
|
} else {
|
|
|
|
// if file doesn't exist, build path nodes root of current context
|
|
|
|
$fileinfo = $browser->get_file_info($context, null, null, null, null, null);
|
2012-03-21 13:55:22 +08:00
|
|
|
}
|
|
|
|
// build path navigation
|
|
|
|
$ret['path'] = array();
|
|
|
|
$element = repository_local_file::retrieve_file_info($fileinfo, $this);
|
|
|
|
for ($level = $element; $level; $level = $level->get_parent()) {
|
|
|
|
if ($level == $element || !$level->can_skip()) {
|
|
|
|
array_unshift($ret['path'], $level->get_node_path());
|
2010-07-20 04:54:57 +00:00
|
|
|
}
|
2008-08-08 03:47:14 +00:00
|
|
|
}
|
2010-05-31 03:45:41 +00:00
|
|
|
$ret['list'] = array_filter($list, array($this, 'filter'));
|
2009-05-20 05:24:53 +00:00
|
|
|
return $ret;
|
2008-08-08 03:47:14 +00:00
|
|
|
}
|
2008-11-26 07:03:10 +00:00
|
|
|
|
2009-12-04 09:19:54 +00:00
|
|
|
/**
|
|
|
|
* Local file don't support to link to external links
|
|
|
|
*
|
2009-12-16 22:22:37 +00:00
|
|
|
* @return int
|
2009-12-04 09:19:54 +00:00
|
|
|
*/
|
2009-11-02 06:45:12 +00:00
|
|
|
public function supported_returntypes() {
|
|
|
|
return FILE_INTERNAL;
|
|
|
|
}
|
2010-05-05 05:57:15 +00:00
|
|
|
|
2010-04-28 16:49:51 +00:00
|
|
|
/**
|
2011-05-02 10:11:19 +08:00
|
|
|
* Does this repository used to browse moodle files?
|
2010-04-28 16:49:51 +00:00
|
|
|
*
|
2011-05-02 10:11:19 +08:00
|
|
|
* @return boolean
|
2010-04-28 16:49:51 +00:00
|
|
|
*/
|
2011-05-02 10:11:19 +08:00
|
|
|
public function has_moodle_files() {
|
|
|
|
return true;
|
2010-09-09 07:36:20 +00:00
|
|
|
}
|
2010-04-28 16:49:51 +00:00
|
|
|
}
|
2012-03-21 13:55:22 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Class to cache some information about file
|
|
|
|
*
|
|
|
|
* This class is a wrapper to instances of file_info. It caches such information as
|
|
|
|
* parent and list of children. It also stores an array of already retrieved elements.
|
|
|
|
*
|
|
|
|
* It also implements more comprehensive algorithm for checking if folder is empty
|
|
|
|
* (taking into account the filtering of the files). To decrease number of levels
|
|
|
|
* we check if some subfolders can be skipped from the tree.
|
|
|
|
*
|
|
|
|
* As a result we display in Server files repository only non-empty folders and skip
|
|
|
|
* filearea folders if this is the only filearea in the module.
|
|
|
|
* For non-admin the course categories are not shown as well (courses are shown as a list)
|
|
|
|
*
|
|
|
|
* @package repository_local
|
|
|
|
* @copyright 2012 Marina Glancy
|
|
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
|
|
*/
|
|
|
|
class repository_local_file {
|
|
|
|
/** @var array stores already retrieved files */
|
|
|
|
private static $cachedfiles = array();
|
|
|
|
/** @var file_info Stores the original file */
|
|
|
|
public $fileinfo;
|
|
|
|
/** @var bool whether this file is directory */
|
|
|
|
private $isdir;
|
|
|
|
/** @var array caches retrieved children */
|
|
|
|
private $children = null;
|
|
|
|
/** @var array caches retrieved information whether this file is an empty directory */
|
|
|
|
protected $isempty = null;
|
|
|
|
/** @var repository link to the container repository (for filtering the results) */
|
|
|
|
private $repository;
|
|
|
|
/** @var repository_local_file link to parent directory */
|
|
|
|
protected $parent;
|
|
|
|
/** @var bool caches calculated information on whether this directory must be skipped in the tree */
|
|
|
|
private $skip = null;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates (or retrieves from cache) the repository_local_file object for $file_info
|
|
|
|
*
|
|
|
|
* @param file_info $fileinfo
|
|
|
|
* @param repository $repository
|
|
|
|
* @param repository_local_file $parent
|
|
|
|
* @return repository_local_file
|
|
|
|
*/
|
|
|
|
public static function retrieve_file_info(file_info $fileinfo, repository $repository, repository_local_file $parent = null) {
|
|
|
|
$encodedpath = base64_encode(serialize($fileinfo->get_params()));
|
|
|
|
if (!isset(self::$cachedfiles[$encodedpath])) {
|
|
|
|
self::$cachedfiles[$encodedpath] = new repository_local_file($fileinfo, $repository, $parent);
|
|
|
|
}
|
|
|
|
return self::$cachedfiles[$encodedpath];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Creates an object
|
|
|
|
*
|
|
|
|
* @param file_info $fileinfo
|
|
|
|
* @param repository $repository
|
|
|
|
* @param repository_local_file $parent
|
|
|
|
*/
|
|
|
|
private function __construct(file_info $fileinfo, repository $repository, repository_local_file $parent = null) {
|
|
|
|
$this->repository = $repository;
|
|
|
|
$this->fileinfo = $fileinfo;
|
|
|
|
$this->isdir = $fileinfo->is_directory();
|
|
|
|
if (!$this->isdir) {
|
|
|
|
$node = array('title' => $this->fileinfo->get_visible_name());
|
|
|
|
$this->isempty = !$repository->filter($node);
|
|
|
|
$this->skip = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns node for $ret['list']
|
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public function get_node() {
|
|
|
|
global $OUTPUT;
|
|
|
|
$encodedpath = base64_encode(serialize($this->fileinfo->get_params()));
|
|
|
|
$node = array(
|
|
|
|
'title' => $this->fileinfo->get_visible_name(),
|
|
|
|
'size' => 0,
|
|
|
|
'date' => '');
|
|
|
|
if ($this->isdir) {
|
|
|
|
$node['path'] = $encodedpath;
|
|
|
|
$node['thumbnail'] = $OUTPUT->pix_url('f/folder-32')->out(false);
|
|
|
|
$node['children'] = array();
|
|
|
|
} else {
|
|
|
|
$node['source'] = $encodedpath;
|
|
|
|
$node['thumbnail'] = $OUTPUT->pix_url(file_extension_icon($node['title'], 32))->out(false);
|
|
|
|
}
|
|
|
|
return $node;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns node for $ret['path']
|
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public function get_node_path() {
|
|
|
|
$encodedpath = base64_encode(serialize($this->fileinfo->get_params()));
|
|
|
|
return array(
|
|
|
|
'path' => $encodedpath,
|
|
|
|
'name' => $this->fileinfo->get_visible_name()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks if this is a directory
|
|
|
|
*
|
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
public function is_dir() {
|
|
|
|
return $this->isdir;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns children of this element
|
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public function get_children() {
|
|
|
|
if (!$this->isdir) {
|
|
|
|
return array();
|
|
|
|
}
|
|
|
|
if ($this->children === null) {
|
|
|
|
$this->children = array();
|
|
|
|
$children = $this->fileinfo->get_children();
|
|
|
|
for ($i=0; $i<count($children); $i++) {
|
|
|
|
$this->children[] = self::retrieve_file_info($children[$i], $this->repository, $this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $this->children;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks if this folder is empty (contains no non-empty children)
|
|
|
|
*
|
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
public function is_empty() {
|
|
|
|
if ($this->isempty === null) {
|
|
|
|
$this->isempty = true;
|
|
|
|
if (!$this->fileinfo->is_empty_area()) {
|
|
|
|
// even if is_empty_area() returns false, element still may be empty
|
|
|
|
$children = $this->get_children();
|
|
|
|
if (!empty($children)) {
|
|
|
|
// 1. Let's look at already retrieved children
|
|
|
|
foreach ($children as $childnode) {
|
|
|
|
if ($childnode->isempty === false) {
|
|
|
|
// we already calculated isempty for a child, and it is not empty
|
|
|
|
$this->isempty = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ($this->isempty) {
|
|
|
|
// 2. now we know that this directory contains children that are either empty or we don't know
|
|
|
|
foreach ($children as $childnode) {
|
|
|
|
if (!$childnode->is_empty()) {
|
|
|
|
$this->isempty = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $this->isempty;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the parent element
|
|
|
|
*
|
|
|
|
* @return repository_local_file
|
|
|
|
*/
|
|
|
|
public function get_parent() {
|
|
|
|
if ($this->parent === null) {
|
|
|
|
if ($parent = $this->fileinfo->get_parent()) {
|
|
|
|
$this->parent = self::retrieve_file_info($parent, $this->repository);
|
|
|
|
} else {
|
|
|
|
$this->parent = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $this->parent;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Wether this folder may be skipped in tree view
|
|
|
|
*
|
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
public function can_skip() {
|
|
|
|
global $CFG;
|
|
|
|
if ($this->skip === null) {
|
|
|
|
$this->skip = false;
|
|
|
|
if ($this->fileinfo instanceof file_info_stored) {
|
|
|
|
$params = $this->fileinfo->get_params();
|
|
|
|
if (strlen($params['filearea']) && $params['filepath'] == '/' && $params['filename'] == '.') {
|
|
|
|
// This is a filearea inside an activity, it can be skipped if it has no non-empty siblings
|
|
|
|
if ($parent = $this->get_parent()) {
|
|
|
|
$siblings = $parent->get_children();
|
|
|
|
$countnonempty = 0;
|
|
|
|
foreach ($siblings as $sibling) {
|
|
|
|
if (!$sibling->is_empty()) {
|
|
|
|
$countnonempty++;
|
|
|
|
if ($countnonempty > 1) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ($countnonempty <= 1) {
|
|
|
|
$this->skip = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if ($this->fileinfo instanceof file_info_context_coursecat) {
|
|
|
|
// This is a course category. For non-admins we do not display categories
|
|
|
|
$this->skip = empty($CFG->navshowmycoursecategories) &&
|
|
|
|
!has_capability('moodle/course:update', get_context_instance(CONTEXT_SYSTEM));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $this->skip;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns array of children who have any elmenets
|
|
|
|
*
|
|
|
|
* If a subfolder can be skipped - list children of subfolder instead
|
|
|
|
* (recursive function)
|
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public function get_non_empty_children() {
|
|
|
|
$children = $this->get_children();
|
|
|
|
$nonemptychildren = array();
|
|
|
|
foreach ($children as $child) {
|
|
|
|
if (!$child->is_empty()) {
|
|
|
|
if ($child->can_skip()) {
|
|
|
|
$nonemptychildren = array_merge($nonemptychildren, $child->get_non_empty_children());
|
|
|
|
} else {
|
|
|
|
$nonemptychildren[] = $child;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $nonemptychildren;
|
|
|
|
}
|
2012-03-21 14:51:40 +08:00
|
|
|
}
|