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.
   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   * The definition of an item which can be exported.
  19   *
  20   * @package     core
  21   * @copyright   2020 Andrew Nicols <andrew@nicols.co.uk>
  22   * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  declare(strict_types=1);
  26  
  27  namespace core\content\export\exportable_items;
  28  
  29  use context;
  30  use core\content\export\exportable_item;
  31  use core\content\export\exported_item;
  32  use core\content\export\zipwriter;
  33  use moodle_url;
  34  use stored_file;
  35  
  36  /**
  37   * An object used to represent content which can be served.
  38   *
  39   * @copyright   2020 Andrew Nicols <andrew@nicols.co.uk>
  40   * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  41   */
  42  class exportable_stored_file extends exportable_item {
  43  
  44      /** @var string The destination path of the text content */
  45      protected $folderpath;
  46  
  47      /** @var stored_file The file to be exported */
  48      protected $file;
  49  
  50      /** @var int The itemid to use in the pluginfile URL */
  51      protected $pluginfileitemid;
  52  
  53      /**
  54       * Create a new exportable_item instance.
  55       *
  56       * If no filearea or itemid  is specified the no attempt will be made to export files.
  57       *
  58       * @param   context $context The context that this content belongs to
  59       * @param   string $component
  60       * @param   string $uservisiblename The name displayed to the user when filtering
  61       * @param   stored_file $file
  62       * @param   null|int $pluginfileitemid The itemid as used in the pluginfile URL.
  63       *          If no itemid is used, then a null value can be provided
  64       * @param   string $folderpath Any sub-directory to place files in
  65       */
  66      public function __construct(
  67          context $context,
  68          string $component,
  69          string $uservisiblename,
  70          stored_file $file,
  71          ?int $pluginfileitemid = null,
  72          string $folderpath = ''
  73      ) {
  74          parent::__construct($context, $component, $uservisiblename);
  75  
  76          $this->file = $file;
  77          $this->folderpath = $folderpath;
  78          $this->pluginfileitemid = $pluginfileitemid;
  79      }
  80  
  81      /**
  82       * Create a set of exportable_items from a set of area paramaters as passed to get_areas_files().
  83       *
  84       * If no filearea or itemid  is specified the no attempt will be made to export files.
  85       *
  86       * @param   context $context The context that this content belongs to
  87       * @param   string $component
  88       * @param   string $filearea
  89       * @param   null|int $itemid
  90       * @param   null|int $pluginfileitemid The itemid as used in the pluginfile URL.
  91       *          If no itemid is used, then a null value can be provided
  92       * @param   string $folderpath Any sub-directory to place files in
  93       * @return  array
  94       */
  95      public static function create_from_area_params(
  96          context $context,
  97          string $component,
  98          string $filearea,
  99          ?int $itemid,
 100          ?int $pluginfileitemid = null,
 101          string $folderpath = ''
 102      ): array {
 103          $fs = get_file_storage();
 104          if ($itemid === null) {
 105              $itemid = false;
 106          }
 107  
 108          $exportables = [];
 109          foreach ($fs->get_area_files($context->id, $component, $filearea, $itemid) as $file) {
 110              if ($file->is_directory()) {
 111                  // Do not export directories.
 112                  // If they contain file contents the directory structure will be created in the zip file.
 113                  continue;
 114              }
 115              $filepath = $file->get_filepath() . $file->get_filename();
 116              $exportables[] = new self($context, $component, $filepath, $file, $pluginfileitemid, $folderpath);
 117          }
 118  
 119          return $exportables;
 120      }
 121  
 122      /**
 123       * Add the content to the archive.
 124       *
 125       * @param   zipwriter $archive
 126       */
 127      public function add_to_archive(zipwriter $archive): ?exported_item {
 128          // Export the content to [contextpath]/[filepath].
 129          $relativefilepath = $this->get_filepath_for_file();
 130  
 131          $archive->add_file_from_stored_file(
 132              $this->get_context(),
 133              $relativefilepath,
 134              $this->file
 135          );
 136  
 137          $exporteditem = new exported_item();
 138          $exporteditem->set_title($this->get_user_visible_name());
 139  
 140          if ($archive->is_file_in_archive($this->context, $relativefilepath)) {
 141              // The file was successfully added to the archive.
 142              $exporteditem->add_file($relativefilepath, false);
 143          } else {
 144              // The file was not added. Link to the live version instead.
 145              $exporteditem->add_file(
 146                  $relativefilepath,
 147                  false,
 148                  self::get_pluginfile_url_for_stored_file($this->file, $this->pluginfileitemid)
 149              );
 150          }
 151  
 152          return $exporteditem;
 153      }
 154  
 155      /**
 156       * Get the filepath for the specified stored_file.
 157       *
 158       * @return  string
 159       */
 160      protected function get_filepath_for_file(): string {
 161          $folderpath = rtrim($this->folderpath);
 162  
 163          if (!empty($folderpath)) {
 164              $folderpath .= '/';
 165          }
 166          return sprintf(
 167              '%s%s%s%s',
 168              $folderpath,
 169              $this->file->get_filearea(),
 170              $this->file->get_filepath(),
 171              $this->file->get_filename()
 172          );
 173      }
 174  
 175      /**
 176       * Get the pluginfile URL for a stored file.
 177       *
 178       * Note: The itemid in the pluginfile may be omitted in some URLs, despite an itemid being present in the database.
 179       * Equally, the itemid in the URL may not match the itemid in the files table.
 180       *
 181       * The pluginfileitemid argument provided to this function is the variant in the URL, and not the one in the files
 182       * table.
 183       *
 184       * @param   stored_file $file The file whose link will be generated
 185       * @param   null|int $pluginfileitemid The itemid of the file in pluginfile URL.
 186       *
 187       */
 188      protected static function get_pluginfile_url_for_stored_file(stored_file $file, ?int $pluginfileitemid): string {
 189          $link = moodle_url::make_pluginfile_url(
 190              $file->get_contextid(),
 191              $file->get_component(),
 192              $file->get_filearea(),
 193              $pluginfileitemid,
 194              $file->get_filepath(),
 195              $file->get_filename(),
 196              true,
 197              true
 198          );
 199  
 200          return $link->out(false);
 201      }
 202  }