Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.
   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  namespace core\moodlenet;
  18  
  19  use backup_controller;
  20  use backup_root_task;
  21  use cm_info;
  22  use core\context\user;
  23  use stdClass;
  24  use stored_file;
  25  
  26  defined('MOODLE_INTERNAL') || die();
  27  
  28  require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
  29  
  30  /**
  31   * Base packager to prepare appropriate backup of a resource to share to MoodleNet.
  32   *
  33   * @package   core
  34   * @copyright 2023 Safat Shahin <safat.shahin@moodle.com>
  35   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  36   */
  37  abstract class resource_packager {
  38  
  39      /**
  40       * @var string $resourcefilename The filename for the resource.
  41       */
  42      protected string $resourcefilename = 'resource';
  43  
  44      /**
  45       * @var stdClass $course The course which the resource belongs to.
  46       */
  47      protected stdClass $course;
  48  
  49      /**
  50       * @var cm_info $cminfo The course module which the resource belongs to.
  51       */
  52      protected cm_info $cminfo;
  53  
  54      /**
  55       * @var int $userid The ID of the user performing the packaging.
  56       */
  57      protected int $userid;
  58  
  59      /**
  60       * Constructor for the base packager.
  61       *
  62       * @param stdClass|cm_info $resource The resource object
  63       * @param int $userid The user id
  64       */
  65      public function __construct(
  66          stdClass|cm_info $resource,
  67          int $userid,
  68          string $resourcefilename,
  69      ) {
  70          if ($resource instanceof cm_info) {
  71              $this->cminfo = $resource;
  72              $this->course = $resource->get_course();
  73          } else {
  74              $this->course = $resource;
  75          }
  76  
  77          $this->userid = $userid;
  78          $this->resourcefilename = $resourcefilename;
  79      }
  80  
  81      /**
  82       * Get the backup controller for the course.
  83       *
  84       * @return backup_controller The backup controller instance that will be used to package the resource.
  85       */
  86      abstract protected function get_backup_controller(): backup_controller;
  87  
  88      /**
  89       * Prepare the backup file using appropriate setting overrides and return relevant information.
  90       *
  91       * @return stored_file
  92       */
  93      public function get_package(): stored_file {
  94          $controller = $this->get_backup_controller();
  95          $alltasksettings = $this->get_all_task_settings($controller);
  96  
  97          // Override relevant settings to remove user data when packaging to share to MoodleNet.
  98          $this->override_task_setting($alltasksettings, 'setting_root_users', 0);
  99          $this->override_task_setting($alltasksettings, 'setting_root_role_assignments', 0);
 100          $this->override_task_setting($alltasksettings, 'setting_root_blocks', 0);
 101          $this->override_task_setting($alltasksettings, 'setting_root_comments', 0);
 102          $this->override_task_setting($alltasksettings, 'setting_root_badges', 0);
 103          $this->override_task_setting($alltasksettings, 'setting_root_userscompletion', 0);
 104          $this->override_task_setting($alltasksettings, 'setting_root_logs', 0);
 105          $this->override_task_setting($alltasksettings, 'setting_root_grade_histories', 0);
 106          $this->override_task_setting($alltasksettings, 'setting_root_groups', 0);
 107  
 108          $storedfile = $this->package($controller);
 109  
 110          $controller->destroy(); // We are done with the controller, destroy it.
 111  
 112          return $storedfile;
 113      }
 114  
 115      /**
 116       * Get all backup settings available for override.
 117       *
 118       * @return array the associative array of taskclass => settings instances.
 119       */
 120      protected function get_all_task_settings(backup_controller $controller): array {
 121          $tasksettings = [];
 122          foreach ($controller->get_plan()->get_tasks() as $task) {
 123              $taskclass = get_class($task);
 124              $tasksettings[$taskclass] = $task->get_settings();
 125          }
 126          return $tasksettings;
 127      }
 128  
 129      /**
 130       * Override a backup task setting with a given value.
 131       *
 132       * @param array $alltasksettings All task settings.
 133       * @param string $settingname The name of the setting to be overridden (task class name format).
 134       * @param int $settingvalue Value to be given to the setting.
 135       */
 136      protected function override_task_setting(array $alltasksettings, string $settingname, int $settingvalue): void {
 137          if (empty($rootsettings = $alltasksettings[backup_root_task::class])) {
 138              return;
 139          }
 140  
 141          foreach ($rootsettings as $setting) {
 142              $name = $setting->get_ui_name();
 143              if ($name == $settingname && $settingvalue != $setting->get_value()) {
 144                  $setting->set_value($settingvalue);
 145                  return;
 146              }
 147          }
 148      }
 149  
 150      /**
 151       * Package the resource identified by resource id into a new stored_file.
 152       *
 153       * @param backup_controller $controller The backup controller.
 154       * @return stored_file
 155       */
 156      protected function package(backup_controller $controller): stored_file {
 157          // Execute the backup and fetch the result.
 158          $controller->execute_plan();
 159          $result = $controller->get_results();
 160  
 161          if (!isset($result['backup_destination'])) {
 162              throw new \moodle_exception('Failed to package resource.');
 163          }
 164  
 165          $backupfile = $result['backup_destination'];
 166  
 167          if (!$backupfile->get_contenthash()) {
 168              throw new \moodle_exception('Failed to package resource (invalid file).');
 169          }
 170  
 171          // Create the location we want to copy this file to.
 172          $filerecord = [
 173              'contextid' => user::instance($this->userid)->id,
 174              'userid' => $this->userid,
 175              'component' => 'user',
 176              'filearea' => 'draft',
 177              'itemid' => file_get_unused_draft_itemid(),
 178              'filepath' => '/',
 179              'filename' => $this->resourcefilename . '_backup.mbz',
 180          ];
 181  
 182          // Create the local file based on the backup.
 183          $fs = get_file_storage();
 184          $file = $fs->create_file_from_storedfile($filerecord, $backupfile);
 185  
 186          // Delete the backup now it has been created in the file area.
 187          $backupfile->delete();
 188  
 189          return $file;
 190      }
 191  }