Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 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 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 and 403] [Versions 39 and 310]

   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;
  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              print_error('invalidcontentid', 'error', $returnurl);
  68          }
  69  
  70          $this->h5peditor = new h5peditor();
  71  
  72          if ($id) {
  73              // The H5P editor needs the H5P content id (h5p table).
  74              $record = $DB->get_record('contentbank_content', ['id' => $id]);
  75              $this->content = new content($record);
  76              $file = $this->content->get_file();
  77  
  78              $h5p = api::get_content_from_pathnamehash($file->get_pathnamehash());
  79              if (!$h5p) {
  80                  // H5P content has not been deployed yet. Let's check why.
  81                  $factory = new \core_h5p\factory();
  82                  $factory->get_framework()->set_file($file);
  83  
  84                  $h5pid = helper::save_h5p($factory, $file, new stdClass());
  85                  $errors = $factory->get_framework()->getMessages('error');
  86                  $notifications = $factory->get_framework()->getMessages('info');
  87              } else {
  88                  $h5pid = $h5p->id;
  89              }
  90              if ($h5pid) {
  91                  $mform->addElement('hidden', 'h5pid', $h5pid);
  92                  $mform->setType('h5pid', PARAM_INT);
  93                  $this->h5peditor->set_content($h5pid);
  94              }
  95          } else {
  96              // The H5P editor needs the H5P content type library name for a new content.
  97              $mform->addElement('hidden', 'library', $library);
  98              $mform->setType('library', PARAM_TEXT);
  99              $this->h5peditor->set_library($library, $this->_customdata['contextid'], 'contentbank', 'public');
 100          }
 101  
 102          $mformid = 'coolh5peditor';
 103          $mform->setAttributes(array('id' => $mformid) + $mform->getAttributes());
 104  
 105          if ($errors || $notifications) {
 106              // Show the error messages and a Cancel button.
 107              foreach ($errors as $error) {
 108                  $mform->addElement('warning', $error->code, 'notify', $error->message);
 109              }
 110              foreach ($notifications as $key => $notification) {
 111                  $mform->addElement('warning', 'notification_'.$key, 'notify', $notification);
 112              }
 113              $mform->addElement('cancel', 'cancel', get_string('back'));
 114          } else {
 115              $this->add_action_buttons();
 116              $this->h5peditor->add_editor_to_form($mform);
 117              $this->add_action_buttons();
 118          }
 119      }
 120  
 121      /**
 122       * Modify or create an H5P content from the form data.
 123       *
 124       * @param stdClass $data Form data to create or modify an H5P content.
 125       *
 126       * @return int The id of the edited or created content.
 127       */
 128      public function save_content(stdClass $data): int {
 129          global $DB;
 130  
 131          // The H5P libraries expect data->id as the H5P content id.
 132          // The method H5PCore::saveContent throws an error if id is set but empty.
 133          if (empty($data->id)) {
 134              unset($data->id);
 135          } else {
 136              // The H5P libraries save in $data->id the H5P content id (h5p table), so the content id is saved in another var.
 137              $contentid = $data->id;
 138          }
 139  
 140          $h5pcontentid = $this->h5peditor->save_content($data);
 141  
 142          $factory = new factory();
 143          $h5pfs = $factory->get_framework();
 144  
 145          // Needs the H5P file id to create or update the content bank record.
 146          $h5pcontent = $h5pfs->loadContent($h5pcontentid);
 147          $fs = get_file_storage();
 148          $file = $fs->get_file_by_hash($h5pcontent['pathnamehash']);
 149          // Creating new content.
 150          if (!isset($data->h5pid)) {
 151              // The initial name of the content is the title of the H5P content.
 152              $cbrecord = new stdClass();
 153              $cbrecord->name = json_decode($data->h5pparams)->metadata->title;
 154              $context = \context::instance_by_id($data->contextid, MUST_EXIST);
 155              // Create entry in content bank.
 156              $contenttype = new contenttype($context);
 157              $newcontent = $contenttype->create_content($cbrecord);
 158              if ($file && $newcontent) {
 159                  $updatedfilerecord = new stdClass();
 160                  $updatedfilerecord->id = $file->get_id();
 161                  $updatedfilerecord->itemid = $newcontent->get_id();
 162                  // As itemid changed, the pathnamehash has to be updated in the file table.
 163                  $pathnamehash = \file_storage::get_pathname_hash($file->get_contextid(), $file->get_component(),
 164                      $file->get_filearea(), $updatedfilerecord->itemid, $file->get_filepath(), $file->get_filename());
 165                  $updatedfilerecord->pathnamehash = $pathnamehash;
 166                  $DB->update_record('files', $updatedfilerecord);
 167                  // The pathnamehash in the h5p table must match the file pathnamehash.
 168                  $h5pfs->updateContentFields($h5pcontentid, ['pathnamehash' => $pathnamehash]);
 169              }
 170          } else {
 171              // Update content.
 172              $this->content->update_content();
 173          }
 174  
 175          return $contentid ?? $newcontent->get_id();
 176      }
 177  }