Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 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 39 and 310] [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 and 403]

   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 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          // This is to be implemented when the Hub client is used.
  80          return [];
  81      }
  82  
  83      /**
  84       * Gets recently used libraries for the current author
  85       *
  86       * @return array machine names. The first element in the array is the
  87       * most recently used.
  88       */
  89      public function getAuthorsRecentlyUsedLibraries(): array {
  90          // This is to be implemented when the Hub client is used.
  91          return [];
  92      }
  93  
  94      /**
  95       * Checks if the provided token is valid for this endpoint.
  96       *
  97       * @param string $token The token that will be validated for.
  98       *
  99       * @return bool True if successful validation
 100       */
 101      public function validateEditorToken($token): bool {
 102          return core::validToken(self::EDITOR_AJAX_TOKEN, $token);
 103      }
 104  
 105      /**
 106       * Get translations in one language for a list of libraries.
 107       *
 108       * @param array $libraries An array of libraries, in the form "<machineName> <majorVersion>.<minorVersion>
 109       * @param string $languagecode Language code
 110       *
 111       * @return array Translations in $languagecode available for libraries $libraries
 112       */
 113      public function getTranslations($libraries, $languagecode): array {
 114          $translations = [];
 115          $langcache = \cache::make('core', 'h5p_content_type_translations');
 116  
 117          $missing = [];
 118          foreach ($libraries as $libstring) {
 119              // Check if this library has been saved previously into the cache.
 120              $librarykey = helper::get_cache_librarykey($libstring);
 121              $cachekey = "{$librarykey}/{$languagecode}";
 122              $libtranslation = $langcache->get($cachekey);
 123              if ($libtranslation) {
 124                  // The library has this language stored into the cache.
 125                  $translations[$libstring] = $libtranslation;
 126              } else {
 127                  // This language for the library hasn't been stored previously into the cache, so we need to get it from DB.
 128                  $missing[] = $libstring;
 129              }
 130          }
 131  
 132          // Get all language files for libraries which aren't stored into the cache and merge them with the cache ones.
 133          return array_merge(
 134              $translations,
 135              $this->get_missing_translations($missing, $languagecode)
 136          );
 137      }
 138  
 139      /**
 140       * Get translation for $language for libraries in $missing.
 141       *
 142       * @param  array  $missing  An array of libraries, in the form "<machineName> <majorVersion>.<minorVersion>
 143       * @param  string $language Language code
 144       * @return array  Translations in $language available for libraries $missing
 145       */
 146      protected function get_missing_translations(array $missing, string $language): array {
 147          global $DB;
 148  
 149          if (empty($missing)) {
 150              return [];
 151          }
 152  
 153          $wheres = [];
 154          $params = [
 155              file_storage::COMPONENT,
 156              file_storage::LIBRARY_FILEAREA,
 157          ];
 158          $sqllike = $DB->sql_like('f.filepath', '?');
 159          $params[] = '%language%';
 160  
 161          foreach ($missing as $library) {
 162              $librarydata = core::libraryFromString($library);
 163              $wheres[] = '(h.machinename = ? AND h.majorversion = ? AND h.minorversion = ?)';
 164              $params[] = $librarydata['machineName'];
 165              $params[] = $librarydata['majorVersion'];
 166              $params[] = $librarydata['minorVersion'];
 167          }
 168          $params[] = "{$language}.json";
 169          $wheresql = implode(' OR ', $wheres);
 170  
 171          $filestable = new dml_table('files', 'f', 'f_');
 172          $filestableselect = $filestable->get_field_select();
 173  
 174          $libtable = new dml_table('h5p_libraries', 'h', 'h_');
 175          $libtableselect = $libtable->get_field_select();
 176  
 177          $sql = "SELECT {$filestableselect}, {$libtableselect}
 178                    FROM {h5p_libraries} h
 179               LEFT JOIN {files} f
 180                      ON h.id = f.itemid AND f.component = ?
 181                     AND f.filearea = ? AND $sqllike
 182                   WHERE ($wheresql) AND f.filename = ?";
 183  
 184          // Get the content of all these language files and put them into the translations array.
 185          $langcache = \cache::make('core', 'h5p_content_type_translations');
 186          $fs = get_file_storage();
 187          $translations = [];
 188          $results = $DB->get_recordset_sql($sql, $params);
 189          $toset = [];
 190          foreach ($results as $result) {
 191              $file = $fs->get_file_instance($filestable->extract_from_result($result));
 192              $library = $libtable->extract_from_result($result);
 193              $libstring = core::record_to_string($library);
 194              $librarykey = helper::get_cache_librarykey($libstring);
 195              $translations[$libstring] = $file->get_content();
 196              $cachekey = "{$librarykey}/{$language}";
 197              $toset[$cachekey] = $translations[$libstring];
 198          }
 199          $langcache->set_many($toset);
 200  
 201          $results->close();
 202  
 203          return $translations;
 204      }
 205  }