Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.2.x will end 22 April 2024 (12 months).
  • Bug fixes for security issues in 4.2.x will end 7 October 2024 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.1.x is supported too.

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

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