Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.0.x will end 8 May 2023 (12 months).
  • Bug fixes for security issues in 4.0.x will end 13 November 2023 (18 months).
  • PHP version: minimum PHP 7.3.0 Note: the minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is also supported.

Differences Between: [Versions 400 and 402] [Versions 400 and 403]

   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 course exporter.
  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  namespace core\content\export\exporters;
  25  
  26  use context_course;
  27  use context_module;
  28  use core\content\export\exported_item;
  29  use core\content\export\zipwriter;
  30  use section_info;
  31  use stdClass;
  32  
  33  /**
  34   * The course exporter.
  35   *
  36   * @copyright   2020 Andrew Nicols <andrew@nicols.co.uk>
  37   * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  38   */
  39  class course_exporter extends component_exporter {
  40  
  41      /** @var stdClass The course being exported */
  42      protected $course;
  43  
  44      /** @var \course_modinfo The course_modinfo instnace for this course */
  45      protected $modinfo;
  46  
  47      /**
  48       * Constructor for the course exporter.
  49       *
  50       * @param   context_course $context The context of the course to export
  51       * @param   stdClass $user
  52       * @param   zipwriter $archive
  53       */
  54      public function __construct(context_course $context, stdClass $user, zipwriter $archive) {
  55          $this->course = get_course($context->instanceid);
  56          $this->modinfo = get_fast_modinfo($this->course, $user->id);
  57  
  58          parent::__construct($context, 'core_course', $user, $archive);
  59      }
  60  
  61      /**
  62       * Export the course.
  63       *
  64       * @param   context[] $exportedcontexts A list of contexts which were successfully exported
  65       */
  66      public function export_course(array $exportedcontexts): void {
  67          // A course export is composed of:
  68          // - Course summary (including inline files)
  69          // - Overview files
  70          // - Section:
  71          // -- Section name
  72          // -- Section summary (including inline files)
  73          // -- List of available activities.
  74  
  75          $aboutpagelink = $this->add_course_about_page();
  76          $templatedata = (object) [
  77              'aboutpagelink' => $aboutpagelink,
  78              'sections' => [],
  79          ];
  80  
  81          // Add all sections.
  82          foreach ($this->modinfo->get_section_info_all() as $number => $section) {
  83              $templatedata->sections[] = $this->get_course_section($exportedcontexts, $section);
  84          }
  85  
  86          $this->get_archive()->add_file_from_template(
  87              $this->get_context(),
  88              'index.html',
  89              'core/content/export/course_index',
  90              $templatedata
  91          );
  92      }
  93  
  94      /**
  95       * Add course about page.
  96       *
  97       * @return  null|string The URL to the about page if one was generated
  98       */
  99      protected function add_course_about_page(): ?string {
 100          $hascontent = false;
 101  
 102          $templatedata = (object) [
 103              'summary' => '',
 104              'overviewfiles' => [],
 105          ];
 106  
 107          // Fetch the course summary content.
 108          if ($this->course->summary) {
 109              $summarydata = $this->get_archive()->add_pluginfiles_for_content(
 110                  $this->get_context(),
 111                  '_course',
 112                  $this->course->summary,
 113                  'course',
 114                  'summary',
 115                  0,
 116                  null
 117              );
 118  
 119              if ($summarydata->has_any_data()) {
 120                  $hascontent = true;
 121                  $templatedata->summary = format_text($summarydata->get_content(), $this->course->summaryformat,
 122                      ['context' => $this->get_context()]);
 123              }
 124          }
 125  
 126          $files = $this->get_archive()->add_pluginfiles_for_content(
 127              $this->get_context(),
 128              '',
 129              '',
 130              'course',
 131              'overviewfiles',
 132              0,
 133              null
 134          )->get_noncontent_files();
 135  
 136          if (count($files)) {
 137              $templatedata->overviewfiles = $files;
 138              $hascontent = true;
 139          }
 140  
 141          if ($hascontent) {
 142              $this->get_archive()->add_file_from_template(
 143                  $this->get_context(),
 144                  'about.html',
 145                  'core/content/export/course_summary',
 146                  $templatedata
 147              );
 148  
 149              return $this->get_archive()->get_relative_context_path($this->get_context(), $this->get_context(), 'about.html');
 150          }
 151  
 152          return null;
 153      }
 154  
 155      /**
 156       * Fetch data for the specified course section.
 157       *
 158       * @param   context[] $exportedcontexts A list of contexts which were successfully exported
 159       * @param   section_info $section The section being exported
 160       * @return  stdClass
 161       */
 162      protected function get_course_section(array $exportedcontexts, section_info $section): stdClass {
 163          $sectiondata = (object) [
 164              'number' => $section->section,
 165              'title' => format_string($section->name, true, ['context' => $this->get_context()]),
 166              'summary' => '',
 167              'activities' => [],
 168          ];
 169  
 170          // Fetch the section summary content.
 171          if ($section->summary) {
 172              $summarydata = $this->get_archive()->add_pluginfiles_for_content(
 173                  $this->get_context(),
 174                  '_course',
 175                  $section->summary,
 176                  'course',
 177                  'section',
 178                  $section->id,
 179                  $section->id
 180              );
 181  
 182              if ($summarydata->has_any_data()) {
 183                  $sectiondata->summary = format_text($summarydata->get_content(), $section->summaryformat,
 184                      ['context' => $this->get_context()]);
 185              }
 186          }
 187  
 188          if (empty($this->modinfo->sections[$section->section])) {
 189              return $sectiondata;
 190          }
 191  
 192          foreach ($this->modinfo->sections[$section->section] as $cmid) {
 193              $cm = $this->modinfo->cms[$cmid];
 194              if (!$cm->uservisible) {
 195                  continue;
 196              }
 197  
 198              if (array_key_exists($cm->context->id, $exportedcontexts)) {
 199                  // This activity was exported.
 200                  // The link to it from the course index should be a relative link.
 201                  $url = $this->get_archive()->get_relative_context_path($this->get_context(), $cm->context, 'index.html');
 202              } else {
 203                  // This activity was not included in the export for some reason.
 204                  // Link to the live activity.
 205                  $url = $cm->url;
 206              }
 207              $sectiondata->activities[] = (object) [
 208                  'title' => $cm->get_formatted_name(),
 209                  'modname' => $cm->modfullname,
 210                  'link' => $url,
 211              ];
 212          }
 213  
 214          return $sectiondata;
 215      }
 216  
 217      /**
 218       * Export all exportable content for an activity module.
 219       *
 220       * @param   context_module $modcontect
 221       * @param   exportable_item[] $export_exportables
 222       */
 223      public function export_mod_content(context_module $modcontext, array $exportables): void {
 224          $cm = $this->modinfo->get_cm($modcontext->instanceid);
 225          $modname = $cm->modname;
 226  
 227          $templatedata = (object) [
 228              'modulelink' => $cm->url,
 229              'modulename' => $cm->get_formatted_name(),
 230              'intro' => null,
 231              'sections' => [],
 232          ];
 233  
 234          if (plugin_supports('mod', $modname, FEATURE_MOD_INTRO, true)) {
 235              $templatedata->intro = $this->get_mod_intro_data($modcontext);
 236          }
 237  
 238          $exporteditems = [];
 239          foreach ($exportables as $exportable) {
 240              $exporteditem = $exportable->add_to_archive($this->get_archive());
 241              $templatedata->sections[] = $exporteditem->get_template_data();
 242          }
 243  
 244          // Add the index to the archive.
 245          $this->get_archive()->add_file_from_template(
 246              $modcontext,
 247              'index.html',
 248              'core/content/export/module_index',
 249              $templatedata
 250          );
 251      }
 252  
 253      /**
 254       * Get the course_module introduction data.
 255       *
 256       * @param   context_module $modcontect
 257       * @return  null|string The content of the intro area
 258       */
 259      protected function get_mod_intro_data(context_module $modcontext): ?string {
 260          global $DB;
 261  
 262          $cm = $this->modinfo->get_cm($modcontext->instanceid);
 263          $modname = $cm->modname;
 264  
 265          $record = $DB->get_record($modname, ['id' => $cm->instance], 'intro, introformat');
 266  
 267          // Fetch the module intro content.
 268          if ($record->intro) {
 269              $exporteditem = $this->get_archive()->add_pluginfiles_for_content(
 270                  $modcontext,
 271                  '',
 272                  $record->intro,
 273                  "mod_{$modname}",
 274                  'intro',
 275                  0,
 276                  null
 277              );
 278  
 279              if ($exporteditem->has_any_data()) {
 280                  return format_text($exporteditem->get_content(), $record->introformat, ['context' => $modcontext]);
 281              }
 282          }
 283  
 284          return null;
 285      }
 286  }