weekly release 3.9dev+
[moodle.git] / h5p / classes / editor_framework.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  * Class \core_h5p\editor_framework
19  *
20  * @package    core_h5p
21  * @copyright  2020 Victor Deniz <victor@moodle.com>, base on code by Joubel AS
22  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
25 namespace core_h5p;
27 use H5peditorStorage;
28 use stdClass;
30 /**
31  * Moodle's implementation of the H5P Editor storage interface.
32  *
33  * Makes it possible for the editor's core library to communicate with the
34  * database used by Moodle.
35  *
36  * @package    core_h5p
37  * @copyright  2020 Victor Deniz <victor@moodle.com>, base on code by Joubel AS
38  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
39  */
40 class editor_framework implements H5peditorStorage {
42     /**
43      * Load language file(JSON).
44      * Used to translate the editor fields(title, description etc.)
45      *
46      * @param string $name The machine readable name of the library(content type)
47      * @param int $major Major part of version number
48      * @param int $minor Minor part of version number
49      * @param string $lang Language code
50      *
51      * @return string|boolean Translation in JSON format if available, false otherwise
52      */
53     public function getLanguage($name, $major, $minor, $lang) {
54         global $DB;
56         // Check if this information has been saved previously into the cache.
57         $langcache = \cache::make('core', 'h5p_content_type_translations');
58         $library = new stdClass();
59         $library->machinename = $name;
60         $library->majorversion = $major;
61         $library->minorversion = $minor;
62         $librarykey = helper::get_cache_librarykey(core::record_to_string($library));
63         $cachekey = "{$librarykey}/{$lang}";
64         $translation = $langcache->get($cachekey);
65         if ($translation) {
66             return $translation;
67         }
69         // Get the language file for this library.
70         $params = [
71             file_storage::COMPONENT,
72             file_storage::LIBRARY_FILEAREA,
73         ];
74         $sqllike = $DB->sql_like('f.filepath', '?');
75         $params[] = '%language%';
77         $sql = "SELECT hl.id, f.pathnamehash
78                   FROM {h5p_libraries} hl
79              LEFT JOIN {files} f
80                     ON hl.id = f.itemid AND f.component = ? AND f.filearea = ? AND $sqllike
81                  WHERE ((hl.machinename = ? AND hl.majorversion = ? AND hl.minorversion = ?)
82                    AND f.filename = ?)
83               ORDER BY hl.patchversion DESC";
84         $params[] = $name;
85         $params[] = $major;
86         $params[] = $minor;
87         $params[] = $lang.'.json';
89         $result = $DB->get_record_sql($sql, $params);
91         if (!empty($result)) {
92             // If the JS language file exists, its content should be returned.
93             $fs = get_file_storage();
94             $file = $fs->get_file_by_hash($result->pathnamehash);
95             $translation = $file->get_content();
96         }
98         // Save translation into the cache (even if there is no translation for this language).
99         $langcache->set($cachekey, $translation);
101         return $translation;
102     }
104     /**
105      * Load a list of available language codes.
106      *
107      * Until translations is implemented, only returns the "en" language.
108      *
109      * @param string $machinename The machine readable name of the library(content type)
110      * @param int $major Major part of version number
111      * @param int $minor Minor part of version number
112      *
113      * @return array List of possible language codes
114      */
115     public function getAvailableLanguages($machinename, $major, $minor): array {
116         global $DB;
118         // Check if this information has been saved previously into the cache.
119         $langcache = \cache::make('core', 'h5p_content_type_translations');
120         $library = new stdClass();
121         $library->machinename = $machinename;
122         $library->majorversion = $major;
123         $library->minorversion = $minor;
124         $librarykey = helper::get_cache_librarykey(core::record_to_string($library));
125         $languages = $langcache->get($librarykey);
126         if ($languages) {
127             // This contains a list of all of the available languages for the library.
128             return $languages;
129         }
131         // Get the language files for this library.
132         $params = [
133             file_storage::COMPONENT,
134             file_storage::LIBRARY_FILEAREA,
135         ];
136         $filepathsqllike = $DB->sql_like('f.filepath', '?');
137         $params[] = '%language%';
138         $filenamesqllike = $DB->sql_like('f.filename', '?');
139         $params[] = '%.json';
141         $sql = "SELECT DISTINCT f.filename
142                            FROM {h5p_libraries} hl
143                       LEFT JOIN {files} f
144                              ON hl.id = f.itemid AND f.component = ? AND f.filearea = ?
145                             AND $filepathsqllike AND $filenamesqllike
146                           WHERE hl.machinename = ? AND hl.majorversion = ? AND hl.minorversion = ?";
147         $params[] = $machinename;
148         $params[] = $major;
149         $params[] = $minor;
151         $defaultcode = 'en';
152         $languages = [];
154         $results = $DB->get_recordset_sql($sql, $params);
155         if ($results->valid()) {
156             // Extract the code language from the JS language files.
157             foreach ($results as $result) {
158                 if (!empty($result->filename)) {
159                     $lang = substr($result->filename, 0, -5);
160                     $languages[$lang] = $languages;
161                 }
162             }
163             $results->close();
165             // Semantics is 'en' by default. It has to be added always.
166             if (!array_key_exists($defaultcode, $languages)) {
167                 $languages = array_keys($languages);
168                 array_unshift($languages, $defaultcode);
169             }
170         } else {
171             $results->close();
172             $params = [
173                 'machinename' => $machinename,
174                 'majorversion' => $major,
175                 'minorversion' => $minor,
176             ];
177             if ($DB->record_exists('h5p_libraries', $params)) {
178                 // If the library exists (but it doesn't contain any language file), at least defaultcode should be returned.
179                 $languages[] = $defaultcode;
180             }
181         }
183         // Save available languages into the cache.
184         $langcache->set($librarykey, $languages);
186         return $languages;
187     }
189     /**
190      * "Callback" for mark the given file as a permanent file.
191      *
192      * Used when saving content that has new uploaded files.
193      *
194      * @param int $fileid
195      */
196     public function keepFile($fileid): void {
197         // Temporal files will be removed on a task when they are in the "editor" file area and and are at least one day older.
198     }
200     /**
201      * Return libraries details.
202      *
203      * Two use cases:
204      * 1. No input, will list all the available content types.
205      * 2. Libraries supported are specified, load additional data and verify
206      * that the content types are available. Used by e.g. the Presentation Tool
207      * Editor that already knows which content types are supported in its
208      * slides.
209      *
210      * @param array $libraries List of library names + version to load info for.
211      *
212      * @return array List of all libraries loaded.
213      */
214     public function getLibraries($libraries = null): ?array {
216         if ($libraries !== null) {
217             // Get details for the specified libraries.
218             $librariesin = [];
219             $fields = 'title, runnable';
221             foreach ($libraries as $library) {
222                 $params = [
223                     'machinename' => $library->name,
224                     'majorversion' => $library->majorVersion,
225                     'minorversion' => $library->minorVersion
226                 ];
228                 $details = api::get_library_details($params, true, $fields);
230                 if ($details) {
231                     $library->title = $details->title;
232                     $library->runnable = $details->runnable;
233                     $librariesin[] = $library;
234                 }
235             }
236         } else {
237             $fields = 'id, machinename as name, title, majorversion, minorversion';
238             $librariesin = api::get_contenttype_libraries($fields);
239         }
241         return $librariesin;
242     }
244     /**
245      * Allow for other plugins to decide which styles and scripts are attached.
246      *
247      * This is useful for adding and/or modifying the functionality and look of
248      * the content types.
249      *
250      * @param array $files List of files as objects with path and version as properties.
251      * @param array $libraries List of libraries indexed by machineName with objects as values. The objects have majorVersion and
252      *     minorVersion as properties.
253      */
254     public function alterLibraryFiles(&$files, $libraries): void {
255         // This is to be implemented when the renderer is used.
256     }
258     /**
259      * Saves a file or moves it temporarily.
260      *
261      * This is often necessary in order to validate and store uploaded or fetched H5Ps.
262      *
263      * @param string $data Uri of data that should be saved as a temporary file.
264      * @param bool $movefile Can be set to TRUE to move the data instead of saving it.
265      *
266      * @return bool|object Returns false if saving failed or an object with path
267      * of the directory and file that is temporarily saved.
268      */
269     public static function saveFileTemporarily($data, $movefile = false) {
270         // This is to be implemented when the Hub client is used to upload libraries.
271         return false;
272     }
274     /**
275      * Marks a file for later cleanup.
276      *
277      * Useful when files are not instantly cleaned up. E.g. for files that are uploaded through the editor.
278      *
279      * @param int $file Id of file that should be cleaned up
280      * @param int|null $contentid Content id of file
281      */
282     public static function markFileForCleanup($file, $contentid = null): ?int {
283         // Temporal files will be removed on a task when they are in the "editor" file area and and are at least one day older.
284         return null;
285     }
287     /**
288      * Clean up temporary files
289      *
290      * @param string $filepath Path to file or directory
291      */
292     public static function removeTemporarilySavedFiles($filepath): void {
293         // This is to be implemented when the Hub client is used to upload libraries.
294     }