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 311 and 401] [Versions 39 and 401] [Versions 400 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   * Provides the class that defines the form for the H5P authoring tool.
  19   *
  20   * @package    contenttype_h5p
  21   * @copyright  2020 Victor Deniz <victor@moodle.com>
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  namespace contenttype_h5p\form;
  26  
  27  use contenttype_h5p\content;
  28  use contenttype_h5p\contenttype;
  29  use core_contentbank\form\edit_content;
  30  use core_h5p\api;
  31  use core_h5p\editor as h5peditor;
  32  use core_h5p\factory;
  33  use core_h5p\helper;
  34  use stdClass;
  35  
  36  /**
  37   * Defines the form for editing an H5P content.
  38   *
  39   * @copyright 2020 Victor Deniz <victor@moodle.com>
  40   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  41   */
  42  class editor extends edit_content {
  43  
  44      /** @var $h5peditor H5P editor object */
  45      private $h5peditor;
  46  
  47      /** @var $content The content being edited */
  48      private $content;
  49  
  50      /**
  51       * Defines the form fields.
  52       */
  53      protected function definition() {
  54          global $DB, $OUTPUT;
  55  
  56          $mform = $this->_form;
  57          $errors = [];
  58          $notifications = [];
  59  
  60          // Id of the content to edit.
  61          $id = $this->_customdata['id'];
  62          // H5P content type to create.
  63          $library = optional_param('library', null, PARAM_TEXT);
  64  
  65          if (empty($id) && empty($library)) {
  66              $returnurl = new \moodle_url('/contentbank/index.php', ['contextid' => $this->_customdata['contextid']]);
  67              throw new \moodle_exception('invalidcontentid', 'error', $returnurl);
  68          }
  69  
  70          $this->h5peditor = new h5peditor();
  71  
  72          $this->set_display_vertical();
  73          $mform->addElement('html', $OUTPUT->heading($this->_customdata['heading'], 2));
  74  
  75          if ($id) {
  76              // The H5P editor needs the H5P content id (h5p table).
  77              $record = $DB->get_record('contentbank_content', ['id' => $id]);
  78              $this->content = new content($record);
  79              $file = $this->content->get_file();
  80  
  81              $h5p = api::get_content_from_pathnamehash($file->get_pathnamehash());
  82              if (!$h5p) {
  83                  // H5P content has not been deployed yet. Let's check why.
  84                  $factory = new \core_h5p\factory();
  85                  $factory->get_framework()->set_file($file);
  86  
  87                  $h5pid = helper::save_h5p($factory, $file, new stdClass());
  88                  $errors = $factory->get_framework()->getMessages('error');
  89                  $notifications = $factory->get_framework()->getMessages('info');
  90              } else {
  91                  $h5pid = $h5p->id;
  92              }
  93              if ($h5pid) {
  94                  $mform->addElement('hidden', 'h5pid', $h5pid);
  95                  $mform->setType('h5pid', PARAM_INT);
  96                  $this->h5peditor->set_content($h5pid);
  97              }
  98          } else {
  99              // The H5P editor needs the H5P content type library name for a new content.
 100              $mform->addElement('hidden', 'library', $library);
 101              $mform->setType('library', PARAM_TEXT);
 102              $this->h5peditor->set_library($library, $this->_customdata['contextid'], 'contentbank', 'public');
 103          }
 104  
 105          $mformid = 'coolh5peditor';
 106          $mform->setAttributes(array('id' => $mformid) + $mform->getAttributes());
 107  
 108          if ($errors || $notifications) {
 109              // Show the error messages and a Cancel button.
 110              foreach ($errors as $error) {
 111                  $mform->addElement('warning', $error->code, 'notify', $error->message);
 112              }
 113              foreach ($notifications as $key => $notification) {
 114                  $mform->addElement('warning', 'notification_'.$key, 'notify', $notification);
 115              }
 116              $mform->addElement('cancel', 'cancel', get_string('back'));
 117          } else {
 118              $this->h5peditor->add_editor_to_form($mform);
 119              $this->add_action_buttons();
 120          }
 121      }
 122  
 123      /**
 124       * Modify or create an H5P content from the form data.
 125       *
 126       * @param stdClass $data Form data to create or modify an H5P content.
 127       *
 128       * @return int The id of the edited or created content.
 129       */
 130      public function save_content(stdClass $data): int {
 131          global $DB;
 132  
 133          // The H5P libraries expect data->id as the H5P content id.
 134          // The method H5PCore::saveContent throws an error if id is set but empty.
 135          if (empty($data->id)) {
 136              unset($data->id);
 137          } else {
 138              // The H5P libraries save in $data->id the H5P content id (h5p table), so the content id is saved in another var.
 139              $contentid = $data->id;
 140          }
 141  
 142          $h5pcontentid = $this->h5peditor->save_content($data);
 143  
 144          $factory = new factory();
 145          $h5pfs = $factory->get_framework();
 146  
 147          // Needs the H5P file id to create or update the content bank record.
 148          $h5pcontent = $h5pfs->loadContent($h5pcontentid);
 149          $fs = get_file_storage();
 150          $file = $fs->get_file_by_hash($h5pcontent['pathnamehash']);
 151          // Creating new content.
 152          if (!isset($data->h5pid)) {
 153              // The initial name of the content is the title of the H5P content.
 154              $cbrecord = new stdClass();
 155              $cbrecord->name = json_decode($data->h5pparams)->metadata->title;
 156              $context = \context::instance_by_id($data->contextid, MUST_EXIST);
 157              // Create entry in content bank.
 158              $contenttype = new contenttype($context);
 159              $newcontent = $contenttype->create_content($cbrecord);
 160              if ($file && $newcontent) {
 161                  $updatedfilerecord = new stdClass();
 162                  $updatedfilerecord->id = $file->get_id();
 163                  $updatedfilerecord->itemid = $newcontent->get_id();
 164                  // As itemid changed, the pathnamehash has to be updated in the file table.
 165                  $pathnamehash = \file_storage::get_pathname_hash($file->get_contextid(), $file->get_component(),
 166                      $file->get_filearea(), $updatedfilerecord->itemid, $file->get_filepath(), $file->get_filename());
 167                  $updatedfilerecord->pathnamehash = $pathnamehash;
 168                  $DB->update_record('files', $updatedfilerecord);
 169                  // The pathnamehash in the h5p table must match the file pathnamehash.
 170                  $h5pfs->updateContentFields($h5pcontentid, ['pathnamehash' => $pathnamehash]);
 171              }
 172          } else {
 173              // Update content.
 174              $this->content->update_content();
 175          }
 176  
 177          return $contentid ?? $newcontent->get_id();
 178      }
 179  }