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  
   3  /**
   4   * This is a data layer which uses the file system so it isn't specific to any framework.
   5   */
   6  class H5PDevelopment {
   7  
   8    const MODE_NONE = 0;
   9    const MODE_CONTENT = 1;
  10    const MODE_LIBRARY = 2;
  11  
  12    private $h5pF, $libraries, $language, $filesPath;
  13  
  14    /**
  15     * Constructor.
  16     *
  17     * @param H5PFrameworkInterface|object $H5PFramework
  18     *  The frameworks implementation of the H5PFrameworkInterface
  19     * @param string $filesPath
  20     *  Path to where H5P should store its files
  21     * @param $language
  22     * @param array $libraries Optional cache input.
  23     */
  24    public function __construct(H5PFrameworkInterface $H5PFramework, $filesPath, $language, $libraries = NULL) {
  25      $this->h5pF = $H5PFramework;
  26      $this->language = $language;
  27      $this->filesPath = $filesPath;
  28      if ($libraries !== NULL) {
  29        $this->libraries = $libraries;
  30      }
  31      else {
  32        $this->findLibraries($filesPath . '/development');
  33      }
  34    }
  35  
  36    /**
  37     * Get contents of file.
  38     *
  39     * @param string $file File path.
  40     * @return mixed String on success or NULL on failure.
  41     */
  42    private function getFileContents($file) {
  43      if (file_exists($file) === FALSE) {
  44        return NULL;
  45      }
  46  
  47      $contents = file_get_contents($file);
  48      if ($contents === FALSE) {
  49        return NULL;
  50      }
  51  
  52      return $contents;
  53    }
  54  
  55    /**
  56     * Scans development directory and find all libraries.
  57     *
  58     * @param string $path Libraries development folder
  59     */
  60    private function findLibraries($path) {
  61      $this->libraries = array();
  62  
  63      if (is_dir($path) === FALSE) {
  64        return;
  65      }
  66  
  67      $contents = scandir($path);
  68  
  69      for ($i = 0, $s = count($contents); $i < $s; $i++) {
  70        if ($contents[$i][0] === '.') {
  71          continue; // Skip hidden stuff.
  72        }
  73  
  74        $libraryPath = $path . '/' . $contents[$i];
  75        $libraryJSON = $this->getFileContents($libraryPath . '/library.json');
  76        if ($libraryJSON === NULL) {
  77          continue; // No JSON file, skip.
  78        }
  79  
  80        $library = json_decode($libraryJSON, TRUE);
  81        if ($library === NULL) {
  82          continue; // Invalid JSON.
  83        }
  84  
  85        // TODO: Validate props? Not really needed, is it? this is a dev site.
  86  
  87        $library['libraryId'] = $this->h5pF->getLibraryId($library['machineName'], $library['majorVersion'], $library['minorVersion']);
  88  
  89        // Convert metadataSettings values to boolean & json_encode it before saving
  90        $library['metadataSettings'] = isset($library['metadataSettings']) ?
  91          H5PMetadata::boolifyAndEncodeSettings($library['metadataSettings']) :
  92          NULL;
  93  
  94        // Save/update library.
  95        $this->h5pF->saveLibraryData($library, $library['libraryId'] === FALSE);
  96  
  97        // Need to decode it again, since it is served from here.
  98        $library['metadataSettings'] = json_decode($library['metadataSettings']);
  99  
 100        $library['path'] = 'development/' . $contents[$i];
 101        $this->libraries[H5PDevelopment::libraryToString($library['machineName'], $library['majorVersion'], $library['minorVersion'])] = $library;
 102      }
 103  
 104      // TODO: Should we remove libraries without files? Not really needed, but must be cleaned up some time, right?
 105  
 106      // Go trough libraries and insert dependencies. Missing deps. will just be ignored and not available. (I guess?!)
 107      $this->h5pF->lockDependencyStorage();
 108      foreach ($this->libraries as $library) {
 109        $this->h5pF->deleteLibraryDependencies($library['libraryId']);
 110        // This isn't optimal, but without it we would get duplicate warnings.
 111        // TODO: You might get PDOExceptions if two or more requests does this at the same time!!
 112        $types = array('preloaded', 'dynamic', 'editor');
 113        foreach ($types as $type) {
 114          if (isset($library[$type . 'Dependencies'])) {
 115            $this->h5pF->saveLibraryDependencies($library['libraryId'], $library[$type . 'Dependencies'], $type);
 116          }
 117        }
 118      }
 119      $this->h5pF->unlockDependencyStorage();
 120      // TODO: Deps must be inserted into h5p_nodes_libraries as well... ? But only if they are used?!
 121    }
 122  
 123    /**
 124     * @return array Libraries in development folder.
 125     */
 126    public function getLibraries() {
 127      return $this->libraries;
 128    }
 129  
 130    /**
 131     * Get library
 132     *
 133     * @param string $name of the library.
 134     * @param int $majorVersion of the library.
 135     * @param int $minorVersion of the library.
 136     * @return array library.
 137     */
 138    public function getLibrary($name, $majorVersion, $minorVersion) {
 139      $library = H5PDevelopment::libraryToString($name, $majorVersion, $minorVersion);
 140      return isset($this->libraries[$library]) === TRUE ? $this->libraries[$library] : NULL;
 141    }
 142  
 143    /**
 144     * Get semantics for the given library.
 145     *
 146     * @param string $name of the library.
 147     * @param int $majorVersion of the library.
 148     * @param int $minorVersion of the library.
 149     * @return string Semantics
 150     */
 151    public function getSemantics($name, $majorVersion, $minorVersion) {
 152      $library = H5PDevelopment::libraryToString($name, $majorVersion, $minorVersion);
 153      if (isset($this->libraries[$library]) === FALSE) {
 154        return NULL;
 155      }
 156      return $this->getFileContents($this->filesPath . $this->libraries[$library]['path'] . '/semantics.json');
 157    }
 158  
 159    /**
 160     * Get translations for the given library.
 161     *
 162     * @param string $name of the library.
 163     * @param int $majorVersion of the library.
 164     * @param int $minorVersion of the library.
 165     * @param $language
 166     * @return string Translation
 167     */
 168    public function getLanguage($name, $majorVersion, $minorVersion, $language) {
 169      $library = H5PDevelopment::libraryToString($name, $majorVersion, $minorVersion);
 170  
 171      if (isset($this->libraries[$library]) === FALSE) {
 172        return NULL;
 173      }
 174  
 175      return $this->getFileContents($this->filesPath . $this->libraries[$library]['path'] . '/language/' . $language . '.json');
 176    }
 177  
 178    /**
 179     * Writes library as string on the form "name majorVersion.minorVersion"
 180     *
 181     * @param string $name Machine readable library name
 182     * @param integer $majorVersion
 183     * @param $minorVersion
 184     * @return string Library identifier.
 185     */
 186    public static function libraryToString($name, $majorVersion, $minorVersion) {
 187      return $name . ' ' . $majorVersion . '.' . $minorVersion;
 188    }
 189  }