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  /**
  18   * The definition of a set of files in a filearea to 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   * The definition of a set of files in a filearea to be exported.
  38   *
  39   * All files mustbe in a single filearea and itemid combination.
  40   *
  41   * @copyright   2020 Andrew Nicols <andrew@nicols.co.uk>
  42   * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  43   */
  44  class exportable_filearea extends exportable_item {
  45  
  46      /** @var string The destination path of the text content */
  47      protected $folderpath;
  48  
  49      /** @var string $filearea The file to be exported */
  50      protected $filearea;
  51  
  52      /** @var bool|int The itemid in the Files API */
  53      protected $itemid;
  54  
  55      /** @var int The itemid to use in the pluginfile URL */
  56      protected $pluginfileitemid;
  57  
  58      /**
  59       * Create a new exportable_item instance.
  60       *
  61       * If no filearea or itemid  is specified the no attempt will be made to export files.
  62       *
  63       * @param   context $context The context that this content belongs to
  64       * @param   string $component
  65       * @param   string $uservisiblename The name displayed to the user when filtering
  66       * @param   string $filearea The file area in the Files API where these files are located
  67       * @param   int $itemid The itemid in the Files API where these files are located
  68       * @param   null|int $pluginfileitemid The itemid as used in the Pluginfile URL
  69       * @param   string $folderpath Any sub-directory to place files in
  70       */
  71      public function __construct(
  72          context $context,
  73          string $component,
  74          string $uservisiblename,
  75          string $filearea,
  76          int $itemid,
  77          ?int $pluginfileitemid = null,
  78          string $folderpath = ''
  79      ) {
  80          parent::__construct($context, $component, $uservisiblename);
  81  
  82          $this->filearea = $filearea;
  83          $this->itemid = $itemid;
  84          $this->pluginfileitemid = $pluginfileitemid;
  85          $this->folderpath = $folderpath;
  86      }
  87  
  88      /**
  89       * Add the content to the archive.
  90       *
  91       * @param   zipwriter $archive
  92       */
  93      public function add_to_archive(zipwriter $archive): ?exported_item {
  94          $fs = get_file_storage();
  95  
  96          $files = $fs->get_area_files($this->context->id, $this->component, $this->filearea, $this->itemid);
  97  
  98          $exporteditem = new exported_item();
  99          $exporteditem->set_title($this->get_user_visible_name());
 100  
 101          foreach ($files as $file) {
 102              if ($file->is_directory()) {
 103                  // Skip folders. The zipwriter cannot handle them.
 104                  continue;
 105              }
 106              // Export the content to [contextpath]/[filepath].
 107              $relativefilepath = $this->get_filepath_for_file($file);
 108  
 109              $archive->add_file_from_stored_file(
 110                  $this->get_context(),
 111                  $relativefilepath,
 112                  $file
 113              );
 114  
 115              if ($archive->is_file_in_archive($this->context, $relativefilepath)) {
 116                  // The file was successfully added to the archive.
 117                  $exporteditem->add_file($relativefilepath, false);
 118              } else {
 119                  // The file was not added. Link to the live version instead.
 120                  $exporteditem->add_file(
 121                      $relativefilepath,
 122                      false,
 123                      self::get_pluginfile_url_for_stored_file($file, $this->pluginfileitemid)
 124                  );
 125              }
 126          }
 127  
 128          return $exporteditem;
 129      }
 130  
 131      /**
 132       * Get the filepath for the specified stored_file.
 133       *
 134       * @param   stored_file $file The file to get a filepath for
 135       * @return  string The generated filepath
 136       */
 137      protected function get_filepath_for_file(stored_file $file): string {
 138          $folderpath = rtrim($this->folderpath);
 139  
 140          if (!empty($folderpath)) {
 141              $folderpath .= '/';
 142          }
 143          return sprintf(
 144              '%s%s%s%s',
 145              $folderpath,
 146              $file->get_filearea(),
 147              $file->get_filepath(),
 148              $file->get_filename()
 149          );
 150      }
 151  
 152      /**
 153       * Get the pluginfile URL for a stored file.
 154       *
 155       * Note: The itemid in the pluginfile may be omitted in some URLs, despite an itemid being present in the database.
 156       * Equally, the itemid in the URL may not match the itemid in the files table.
 157       *
 158       * The pluginfileitemid argument provided to this function is the variant in the URL, and not the one in the files
 159       * table.
 160       *
 161       * @param   stored_file $file The file whose link will be generated
 162       * @param   null|int $pluginfileitemid The itemid of the file in pluginfile URL.
 163       *
 164       */
 165      protected static function get_pluginfile_url_for_stored_file(stored_file $file, ?int $pluginfileitemid): string {
 166          $link = moodle_url::make_pluginfile_url(
 167              $file->get_contextid(),
 168              $file->get_component(),
 169              $file->get_filearea(),
 170              $pluginfileitemid,
 171              $file->get_filepath(),
 172              $file->get_filename(),
 173              true,
 174              true
 175          );
 176  
 177          return $link->out(false);
 178      }
 179  }