Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403] [Versions 39 and 310]

   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   * Class \core_h5p\editor_ajax
  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   */
  24  
  25  namespace core_h5p;
  26  
  27  use Moodle\H5PEditorAjaxInterface;
  28  use core\dml\table as dml_table;
  29  
  30  /**
  31   * Moodle's implementation of the H5P Editor Ajax interface.
  32   *
  33   * Makes it possible for the editor's core ajax functionality 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_ajax implements H5PEditorAjaxInterface {
  41  
  42      /** The component for H5P. */
  43      public const EDITOR_AJAX_TOKEN = 'editorajax';
  44  
  45      /**
  46       * Gets latest library versions that exists locally
  47       *
  48       * @return array Latest version of all local libraries
  49       */
  50      public function getLatestLibraryVersions(): array {
  51          global $DB;
  52  
  53          $sql = "SELECT hl2.id, hl2.machinename as machine_name, hl2.title, hl2.majorversion as major_version,
  54                         hl2.minorversion AS minor_version, hl2.patchversion as patch_version, '' as has_icon, 0 as restricted
  55                    FROM {h5p_libraries} hl2
  56               LEFT JOIN {h5p_libraries} hl1
  57                          ON hl1.machinename = hl2.machinename
  58                          AND (hl2.majorversion < hl1.majorversion
  59                               OR (hl2.majorversion = hl1.majorversion
  60                                   AND hl2.minorversion < hl1.minorversion)
  61                              )
  62                   WHERE hl2.runnable = 1
  63                         AND hl1.majorversion is null
  64                ORDER BY hl2.title";
  65  
  66          return $DB->get_records_sql($sql);
  67      }
  68  
  69      /**
  70       * Get locally stored Content Type Cache.
  71       *
  72       * If machine name is provided it will only get the given content type from the cache.
  73       *
  74       * @param null|string $machinename
  75       *
  76       * @return mixed|null Returns results from querying the database
  77       */
  78      public function getContentTypeCache($machinename = null) {
  79          global $DB;
  80  
  81          // Added some extra fields to the result because they are expected by functions calling this. They have been
  82          // taken from method getCachedLibsMap() in h5peditor.class.php.
  83          $sql = "SELECT l.id, l.machinename AS machine_name, l.majorversion AS major_version,
  84                         l.minorversion AS minor_version, l.patchversion AS patch_version, l.coremajor AS h5p_major_version,
  85                         l.coreminor AS h5p_minor_version, l.title, l.tutorial, l.example,
  86                         '' AS summary, '' AS description, '' AS icon, 0 AS created_at, 0 AS updated_at, 0 AS is_recommended,
  87                         0 AS popularity, '' AS screenshots, '' AS license, '' AS owner
  88                    FROM {h5p_libraries} l";
  89          $params = [];
  90          if (!empty($machinename)) {
  91              $sql .= ' WHERE l.machinename = :machine_name';
  92              $params = ['machine_name' => $machinename];
  93          }
  94  
  95          return $DB->get_records_sql($sql, $params);
  96      }
  97  
  98      /**
  99       * Gets recently used libraries for the current author
 100       *
 101       * @return array machine names. The first element in the array is the
 102       * most recently used.
 103       */
 104      public function getAuthorsRecentlyUsedLibraries(): array {
 105          // This is to be implemented when the Hub client is used.
 106          return [];
 107      }
 108  
 109      /**
 110       * Checks if the provided token is valid for this endpoint.
 111       *
 112       * @param string $token The token that will be validated for.
 113       *
 114       * @return bool True if successful validation
 115       */
 116      public function validateEditorToken($token): bool {
 117          return core::validToken(self::EDITOR_AJAX_TOKEN, $token);
 118      }
 119  
 120      /**
 121       * Get translations in one language for a list of libraries.
 122       *
 123       * @param array $libraries An array of libraries, in the form "<machineName> <majorVersion>.<minorVersion>
 124       * @param string $languagecode Language code
 125       *
 126       * @return array Translations in $languagecode available for libraries $libraries
 127       */
 128      public function getTranslations($libraries, $languagecode): array {
 129          $translations = [];
 130          $langcache = \cache::make('core', 'h5p_content_type_translations');
 131  
 132          $missing = [];
 133          foreach ($libraries as $libstring) {
 134              // Check if this library has been saved previously into the cache.
 135              $librarykey = helper::get_cache_librarykey($libstring);
 136              $cachekey = "{$librarykey}/{$languagecode}";
 137              $libtranslation = $langcache->get($cachekey);
 138              if ($libtranslation) {
 139                  // The library has this language stored into the cache.
 140                  $translations[$libstring] = $libtranslation;
 141              } else {
 142                  // This language for the library hasn't been stored previously into the cache, so we need to get it from DB.
 143                  $missing[] = $libstring;
 144              }
 145          }
 146  
 147          // Get all language files for libraries which aren't stored into the cache and merge them with the cache ones.
 148          return array_merge(
 149              $translations,
 150              $this->get_missing_translations($missing, $languagecode)
 151          );
 152      }
 153  
 154      /**
 155       * Get translation for $language for libraries in $missing.
 156       *
 157       * @param  array  $missing  An array of libraries, in the form "<machineName> <majorVersion>.<minorVersion>
 158       * @param  string $language Language code
 159       * @return array  Translations in $language available for libraries $missing
 160       */
 161      protected function get_missing_translations(array $missing, string $language): array {
 162          global $DB;
 163  
 164          if (empty($missing)) {
 165              return [];
 166          }
 167  
 168          $wheres = [];
 169          $params = [
 170              file_storage::COMPONENT,
 171              file_storage::LIBRARY_FILEAREA,
 172          ];
 173          $sqllike = $DB->sql_like('f.filepath', '?');
 174          $params[] = '%language%';
 175  
 176          foreach ($missing as $library) {
 177              $librarydata = core::libraryFromString($library);
 178              $wheres[] = '(h.machinename = ? AND h.majorversion = ? AND h.minorversion = ?)';
 179              $params[] = $librarydata['machineName'];
 180              $params[] = $librarydata['majorVersion'];
 181              $params[] = $librarydata['minorVersion'];
 182          }
 183          $params[] = "{$language}.json";
 184          $wheresql = implode(' OR ', $wheres);
 185  
 186          $filestable = new dml_table('files', 'f', 'f_');
 187          $filestableselect = $filestable->get_field_select();
 188  
 189          $libtable = new dml_table('h5p_libraries', 'h', 'h_');
 190          $libtableselect = $libtable->get_field_select();
 191  
 192          $sql = "SELECT {$filestableselect}, {$libtableselect}
 193                    FROM {h5p_libraries} h
 194               LEFT JOIN {files} f
 195                      ON h.id = f.itemid AND f.component = ?
 196                     AND f.filearea = ? AND $sqllike
 197                   WHERE ($wheresql) AND f.filename = ?";
 198  
 199          // Get the content of all these language files and put them into the translations array.
 200          $langcache = \cache::make('core', 'h5p_content_type_translations');
 201          $fs = get_file_storage();
 202          $translations = [];
 203          $results = $DB->get_recordset_sql($sql, $params);
 204          $toset = [];
 205          foreach ($results as $result) {
 206              $file = $fs->get_file_instance($filestable->extract_from_result($result));
 207              $library = $libtable->extract_from_result($result);
 208              $libstring = core::record_to_string($library);
 209              $librarykey = helper::get_cache_librarykey($libstring);
 210              $translations[$libstring] = $file->get_content();
 211              $cachekey = "{$librarykey}/{$language}";
 212              $toset[$cachekey] = $translations[$libstring];
 213          }
 214          $langcache->set_many($toset);
 215  
 216          $results->close();
 217  
 218          return $translations;
 219      }
 220  }