MDL-69549 core: Add context export API
[moodle.git] / lib / classes / content / export / exportable_items / exportable_filearea.php
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/>.
17 /**
18  * The definition of a set of files in a filearea to be exported.
19  *
20  * @package     core
21  * @copyright   2020 Andrew Nicols <andrew@nicols.co.uk>
22  * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
25 declare(strict_types=1);
27 namespace core\content\export\exportable_items;
29 use context;
30 use core\content\export\exportable_item;
31 use core\content\export\exported_item;
32 use core\content\export\zipwriter;
33 use moodle_url;
34 use stored_file;
36 /**
37  * The definition of a set of files in a filearea to be exported.
38  *
39  * All files mustbe in a single filearea and itemid combination.
40  *
41  * @copyright   2020 Andrew Nicols <andrew@nicols.co.uk>
42  * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
43  */
44 class exportable_filearea extends exportable_item {
46     /** @var string The destination path of the text content */
47     protected $folderpath;
49     /** @var string $filearea The file to be exported */
50     protected $filearea;
52     /** @var bool|int The itemid in the Files API */
53     protected $itemid;
55     /** @var int The itemid to use in the pluginfile URL */
56     protected $pluginfileitemid;
58     /**
59      * Create a new exportable_item instance.
60      *
61      * If no filearea or itemid  is specified the no attempt will be made to export files.
62      *
63      * @param   context $context The context that this content belongs to
64      * @param   string $component
65      * @param   string $uservisiblename The name displayed to the user when filtering
66      * @param   string $filearea The file area in the Files API where these files are located
67      * @param   int $itemid The itemid in the Files API where these files are located
68      * @param   null|int $pluginfileitemid The itemid as used in the Pluginfile URL
69      * @param   string $folderpath Any sub-directory to place files in
70      */
71     public function __construct(
72         context $context,
73         string $component,
74         string $uservisiblename,
75         string $filearea,
76         int $itemid,
77         ?int $pluginfileitemid = null,
78         string $folderpath = ''
79     ) {
80         parent::__construct($context, $component, $uservisiblename);
82         $this->filearea = $filearea;
83         $this->itemid = $itemid;
84         $this->pluginfileitemid = $pluginfileitemid;
85         $this->folderpath = $folderpath;
86     }
88     /**
89      * Add the content to the archive.
90      *
91      * @param   zipwriter $archive
92      */
93     public function add_to_archive(zipwriter $archive): ?exported_item {
94         $fs = get_file_storage();
96         $files = $fs->get_area_files($this->context->id, $this->component, $this->filearea, $this->itemid);
98         $exporteditem = new exported_item();
99         $exporteditem->set_title($this->get_user_visible_name());
101         foreach ($files as $file) {
102             if ($file->is_directory()) {
103                 // Skip folders. The zipwriter cannot handle them.
104                 continue;
105             }
106             // Export the content to [contextpath]/[filepath].
107             $relativefilepath = $this->get_filepath_for_file($file);
109             $archive->add_file_from_stored_file(
110                 $this->get_context(),
111                 $relativefilepath,
112                 $file
113             );
115             if ($archive->is_file_in_archive($this->context, $relativefilepath)) {
116                 // The file was successfully added to the archive.
117                 $exporteditem->add_file($relativefilepath, false);
118             } else {
119                 // The file was not added. Link to the live version instead.
120                 $exporteditem->add_file(
121                     $relativefilepath,
122                     false,
123                     self::get_pluginfile_url_for_stored_file($file, $this->pluginfileitemid)
124                 );
125             }
126         }
128         return $exporteditem;
129     }
131     /**
132      * Get the filepath for the specified stored_file.
133      *
134      * @param   stored_file $file The file to get a filepath for
135      * @return  string The generated filepath
136      */
137     protected function get_filepath_for_file(stored_file $file): string {
138         $folderpath = rtrim($this->folderpath);
140         if (!empty($folderpath)) {
141             $folderpath .= '/';
142         }
143         return sprintf(
144             '%s%s%s%s',
145             $folderpath,
146             $file->get_filearea(),
147             $file->get_filepath(),
148             $file->get_filename()
149         );
150     }
152     /**
153      * Get the pluginfile URL for a stored file.
154      *
155      * Note: The itemid in the pluginfile may be omitted in some URLs, despite an itemid being present in the database.
156      * Equally, the itemid in the URL may not match the itemid in the files table.
157      *
158      * The pluginfileitemid argument provided to this function is the variant in the URL, and not the one in the files
159      * table.
160      *
161      * @param   stored_file $file The file whose link will be generated
162      * @param   null|int $pluginfileitemid The itemid of the file in pluginfile URL.
163      *
164      */
165     protected static function get_pluginfile_url_for_stored_file(stored_file $file, ?int $pluginfileitemid): string {
166         $link = moodle_url::make_pluginfile_url(
167             $file->get_contextid(),
168             $file->get_component(),
169             $file->get_filearea(),
170             $pluginfileitemid,
171             $file->get_filepath(),
172             $file->get_filename(),
173             true,
174             true
175         );
177         return $link->out(false);
178     }