Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 310 and 401] [Versions 39 and 401]

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