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.
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.

/**
 * Step class.
 *
 * @package    tool_usertours
 * @copyright  2016 Andrew Nicols <andrew@nicols.co.uk>
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */

namespace tool_usertours;

> use context_system; defined('MOODLE_INTERNAL') || die(); > use stdClass; >
/** * Step class. * * @copyright 2016 Andrew Nicols <andrew@nicols.co.uk> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class step { /** * @var int $id The id of the step. */ protected $id; /** * @var int $tourid The id of the tour that this step belongs to. */ protected $tourid; /** * @var tour $tour The tour class that this step belongs to. */ protected $tour; /** * @var string $title The title of the step. */ protected $title; /** * @var string $content The content of this step. */ protected $content; /**
> * @var int $contentformat The content format: FORMAT_MOODLE/FORMAT_HTML/FORMAT_PLAIN/FORMAT_MARKDOWN. * @var int $targettype The type of target. > */ */ > protected $contentformat; protected $targettype; > > /**
/** * @var string $targetvalue The value for this type of target. */ protected $targetvalue; /** * @var int $sortorder The sort order. */ protected $sortorder; /** * @var object $config The configuration as an object. */ protected $config; /** * @var bool $dirty Whether the step has been changed since it was loaded */ protected $dirty = false; /**
> * @var bool $isimporting Whether the step is being imported or not. * Fetch the step instance. > */ * > protected $isimporting; * @param int $id The id of the step to be retrieved. > * @return step > /** */ > * @var stdClass[] $files The list of attached files for this step. public static function instance($id) { > */ $step = new step(); > protected $files = []; return $step->fetch($id); > } > /**
/** * Load the step instance. * * @param stdClass $record The step record to be loaded.
< * @param boolean $clean Clean the values.
> * @param bool $clean Clean the values. > * @param bool $isimporting Whether the step is being imported or not.
* @return step */
< public static function load_from_record($record, $clean = false) {
> public static function load_from_record($record, $clean = false, bool $isimporting = false) {
$step = new self();
> $step->set_importing($isimporting);
return $step->reload_from_record($record, $clean); } /** * Fetch the step instance. * * @param int $id The id of the step to be retrieved. * @return step */ protected function fetch($id) { global $DB; return $this->reload_from_record( $DB->get_record('tool_usertours_steps', array('id' => $id)) ); } /** * Refresh the current step from the datbase. * * @return step */ protected function reload() { return $this->fetch($this->id); } /** * Reload the current step from the supplied record. * * @param stdClass $record The step record to be loaded.
< * @param boolean $clean Clean the values.
> * @param bool $clean Clean the values.
* @return step */ protected function reload_from_record($record, $clean = false) { $this->id = $record->id; $this->tourid = $record->tourid; if ($clean) { $this->title = clean_param($record->title, PARAM_TEXT); $this->content = clean_text($record->content); } else { $this->title = $record->title; $this->content = $record->content; }
> $this->contentformat = isset($record->contentformat) ? $record->contentformat : FORMAT_MOODLE;
$this->targettype = $record->targettype; $this->targetvalue = $record->targetvalue; $this->sortorder = $record->sortorder; $this->config = json_decode($record->configdata); $this->dirty = false;
> if ($this->isimporting && isset($record->files)) { return $this; > // We are importing/exporting the step. } > $this->files = $record->files; > } /** >
* Get the ID of the step.
> * Set the import state for the step. * > * * @return int > * @param bool $isimporting True if the step is imported, otherwise false. */ > * @return void public function get_id() { > */ return $this->id; > protected function set_importing(bool $isimporting = false): void { } > $this->isimporting = $isimporting; > } /** > * Get the Tour ID of the step. > /**
* * @return int */ public function get_tourid() { return $this->tourid; } /** * Get the Tour instance that this step belongs to. * * @return tour */ public function get_tour() { if ($this->tour === null) { $this->tour = tour::instance($this->tourid); } return $this->tour; } /** * Set the id of the tour. * * @param int $value The id of the tour. * @return self */ public function set_tourid($value) { $this->tourid = $value; $this->tour = null; $this->dirty = true; return $this; } /** * Get the Title of the step. * * @return string */ public function get_title() { return $this->title; } /** * Set the title for this step. * * @param string $value The new title to use. * @return $this */ public function set_title($value) { $this->title = clean_text($value); $this->dirty = true; return $this; } /**
> * Get the content format of the step. * Get the body content of the step. > * * > * @return int * @return string > */ */ > public function get_contentformat(): int { public function get_content() { > return $this->contentformat; return $this->content; > } } > > /**
/** * Set the content value for this step. * * @param string $value The new content to use.
> * @param int $format The new format to use: FORMAT_MOODLE/FORMAT_HTML/FORMAT_PLAIN/FORMAT_MARKDOWN.
* @return $this */
< public function set_content($value) {
> public function set_content($value, $format = FORMAT_HTML) {
$this->content = clean_text($value);
> $this->contentformat = $format;
$this->dirty = true; return $this; } /** * Get the content value for this step. * * @return string */ public function get_targettype() { return $this->targettype; } /** * Set the type of target for this step. * * @param string $value The new target to use. * @return $this */ public function set_targettype($value) { $this->targettype = $value; $this->dirty = true; return $this; } /** * Get the target value for this step. * * @return string */ public function get_targetvalue() { return $this->targetvalue; } /** * Set the target value for this step. * * @param string $value The new target value to use. * @return $this */ public function set_targetvalue($value) { $this->targetvalue = $value; $this->dirty = true; return $this; } /** * Get the target instance for this step. * * @return target */ public function get_target() { return target::get_target_instance($this); } /** * Get the current sortorder for this step. * * @return int */ public function get_sortorder() { return (int) $this->sortorder; } /** * Whether this step is the first step in the tour. * * @return boolean */ public function is_first_step() { return ($this->get_sortorder() === 0); } /** * Whether this step is the last step in the tour. * * @return boolean */ public function is_last_step() { $stepcount = $this->get_tour()->count_steps(); return ($this->get_sortorder() === $stepcount - 1); } /** * Set the sortorder for this step. * * @param int $value The new sortorder to use. * @return $this */ public function set_sortorder($value) { $this->sortorder = $value; $this->dirty = true; return $this; } /** * Get the link to move this step up in the sortorder. * * @return moodle_url */ public function get_moveup_link() { return helper::get_move_step_link($this->get_id(), helper::MOVE_UP); } /** * Get the link to move this step down in the sortorder. * * @return moodle_url */ public function get_movedown_link() { return helper::get_move_step_link($this->get_id(), helper::MOVE_DOWN); } /** * Get the value of the specified configuration item. * * If notvalue was found, and no default was specified, the default for the tour will be used. * * @param string $key The configuration key to set. * @param mixed $default The default value to use if a value was not found. * @return mixed */ public function get_config($key = null, $default = null) { if ($this->config === null) { $this->config = (object) array(); } if ($key === null) { return $this->config; } if ($this->get_targettype() !== null) { $target = $this->get_target(); if ($target->is_setting_forced($key)) { return $target->get_forced_setting_value($key); } } if (property_exists($this->config, $key)) { return $this->config->$key; } if ($default !== null) { return $default; } return $this->get_tour()->get_config($key); } /** * Set the configuration item as specified. * * @param string $key The configuration key to set. * @param mixed $value The new value for the configuration item. * @return $this */ public function set_config($key, $value) { if ($this->config === null) { $this->config = (object) array(); } if ($value === null) { unset($this->config->$key); } else { $this->config->$key = $value; } $this->dirty = true; return $this; } /** * Get the edit link for this step. * * @return moodle_url */ public function get_edit_link() { return helper::get_edit_step_link($this->tourid, $this->id); } /** * Get the delete link for this step. * * @return moodle_url */ public function get_delete_link() { return helper::get_delete_step_link($this->id); } /**
> * Embed attached file to the json file for step. * Prepare this step for saving to the database. > * * > * @return array List of files. * @return object > */ */ > protected function embed_files(): array { public function to_record() { > $systemcontext = context_system::instance(); return (object) array( > $fs = get_file_storage(); 'id' => $this->id, > $areafiles = $fs->get_area_files($systemcontext->id, 'tool_usertours', 'stepcontent', $this->id); 'tourid' => $this->tourid, > $files = []; 'title' => $this->title, > foreach ($areafiles as $file) { 'content' => $this->content, > if ($file->is_directory()) { 'targettype' => $this->targettype, > continue; 'targetvalue' => $this->targetvalue, > } 'sortorder' => $this->sortorder, > $files[] = [ 'configdata' => json_encode($this->config), > 'name' => $file->get_filename(), ); > 'path' => $file->get_filepath(), } > 'content' => base64_encode($file->get_content()), > 'encode' => 'base64' /** > ]; * Calculate the next sort-order value. > } * > * @return int > return $files; */ > } protected function calculate_sortorder() { > $count = $this->get_tour()->count_steps(); > /** $this->sortorder = $count; > * Get the embed files information and create store_file for this step. > * return $this; > * @return void } > */ > protected function extract_files() { /** > $fs = get_file_storage(); * Save the tour and it's configuration to the database. > $systemcontext = context_system::instance(); * > foreach ($this->files as $file) { * @param boolean $force Whether to force writing to the database. > $filename = $file->name; * @return $this > $filepath = $file->path; */ > $filecontent = $file->content; public function persist($force = false) { > $filerecord = [ global $DB; > 'contextid' => $systemcontext->id, > 'component' => 'tool_usertours', if (!$this->dirty && !$force) { > 'filearea' => 'stepcontent', return $this; > 'itemid' => $this->get_id(), } > 'filepath' => $filepath, > 'filename' => $filename, if ($this->id) { > ]; $record = $this->to_record(); > $fs->create_file_from_string($filerecord, base64_decode($filecontent)); $DB->update_record('tool_usertours_steps', $record); > } } else { > } $this->calculate_sortorder(); > $record = $this->to_record(); > /**
unset($record->id);
> * @param bool $isexporting Whether the step is being exported or not.
< public function to_record() { < return (object) array(
> public function to_record(bool $isexporting = false) { > $record = [
}
> 'contentformat' => $this->contentformat,
< );
> ]; > if ($isexporting) { > // We are exporting the step, adding files node to the json record. > $record['files'] = $this->embed_files(); > } > return (object) $record;
$this->reload();
> $systemcontext = context_system::instance(); > if ($draftid = file_get_submitted_draft_itemid('content')) { // Notify of a change to the step configuration. > // Take any files added to the stepcontent draft file area and // This must be done separately to tour change notifications. > // convert them into the proper event description file area. Also cache::notify_step_change($this->get_tourid()); > // parse the content text and replace the URLs to the draft files > // with the @@PLUGIN_FILE@@ placeholder to be persisted in the DB. // Notify the cache that a tour has changed. > $this->content = file_save_draft_area_files( // Tours are only stored in the cache if there are steps. > $draftid, // If there step count has changed for some reason, this will change the potential cache results. > $systemcontext->id, cache::notify_tour_change(); > 'tool_usertours', > 'stepcontent', return $this; > $this->id, } > ['subdirs' => true], > $this->content /** > ); * Remove this step. > $DB->set_field('tool_usertours_steps', 'content', $this->content, ['id' => $this->id]); */ > } public function remove() { > global $DB; > if ($this->isimporting) { > // We are importing the step, we need to create store_file from the json record. if ($this->id === null) { > $this->extract_files(); return; > }
} $DB->delete_records('tool_usertours_steps', array('id' => $this->id)); $this->get_tour()->reset_step_sortorder(); // Notify of a change to the step configuration. // This must be done separately to tour change notifications. cache::notify_step_change($this->get_id()); // Notify the cache that a tour has changed. // Tours are only stored in the cache if there are steps. // If there step count has changed for some reason, this will change the potential cache results. cache::notify_tour_change(); } /** * Get the list of possible placement options. * * @return array */ public function get_placement_options() { return configuration::get_placement_options(true); } /** * The list of possible configuration keys. * * @return array */ public static function get_config_keys() { return [ 'placement', 'orphan', 'backdrop', 'reflex', ]; } /** * Add the step configuration to the form. * * @param MoodleQuickForm $mform The form to add configuration to. * @return $this */ public function add_config_to_form(\MoodleQuickForm $mform) { $tour = $this->get_tour(); $options = configuration::get_placement_options($tour->get_config('placement')); $mform->addElement('select', 'placement', get_string('placement', 'tool_usertours'), $options); $mform->addHelpButton('placement', 'placement', 'tool_usertours'); $this->add_config_field_to_form($mform, 'orphan'); $this->add_config_field_to_form($mform, 'backdrop'); $this->add_config_field_to_form($mform, 'reflex'); return $this; } /** * Add the specified step field configuration to the form. * * @param MoodleQuickForm $mform The form to add configuration to. * @param string $key The key to add. * @return $this */ public function add_config_field_to_form(\MoodleQuickForm $mform, $key) { $tour = $this->get_tour(); $default = (bool) $tour->get_config($key); $options = [ true => get_string('yes'), false => get_string('no'), ]; if (!isset($options[$default])) { $default = configuration::get_default_value($key); } $options = array_reverse($options, true); $options[configuration::TOURDEFAULT] = get_string('defaultvalue', 'tool_usertours', $options[$default]); $options = array_reverse($options, true); $mform->addElement('select', $key, get_string($key, 'tool_usertours'), $options); $mform->setDefault($key, configuration::TOURDEFAULT); $mform->addHelpButton($key, $key, 'tool_usertours'); return $this; } /** * Prepare the configuration data for the moodle form. * * @return object */ public function prepare_data_for_form() { $data = $this->to_record(); foreach (self::get_config_keys() as $key) { $data->$key = $this->get_config($key, configuration::get_step_default_value($key)); } if ($this->get_targettype() !== null) { $this->get_target()->prepare_data_for_form($data); }
> // Prepare content for editing in a form 'editor' field type. return $data; > $draftitemid = file_get_submitted_draft_itemid('tool_usertours'); } > $systemcontext = context_system::instance(); > $data->content = [ /** > 'format' => $data->contentformat, * Handle submission of the step editing form. > 'itemid' => $draftitemid, * > 'text' => file_prepare_draft_area( * @param local\forms\editstep $mform The sumitted form. > $draftitemid, * @param stdClass $data The submitted data. > $systemcontext->id, * @return $this > 'tool_usertours', */ > 'stepcontent', public function handle_form_submission(local\forms\editstep &$mform, \stdClass $data) { > $this->id, $this->set_title($data->title); > ['subdirs' => true], $this->set_content($data->content); > $data->content $this->set_targettype($data->targettype); > ), > ]; $this->set_targetvalue($this->get_target()->get_value_from_form($data)); >
< public function handle_form_submission(local\forms\editstep &$mform, \stdClass $data) {
> public function handle_form_submission(local\forms\editstep &$mform, stdClass $data) {
< $this->set_content($data->content);
> $this->set_content($data->content['text'], $data->content['format']);
if (!$this->get_target()->is_setting_forced($key)) { if (isset($data->$key)) { $value = $data->$key; } else { $value = configuration::TOURDEFAULT; } if ($value === configuration::TOURDEFAULT) { $this->set_config($key, null); } else { $this->set_config($key, $value); } } } $this->persist(); return $this; } /** * Attempt to fetch any matching langstring if the string is in the * format identifier,component. *
> * @deprecated since Moodle 4.0 MDL-72783. Please use helper::get_string_from_input() instead.
* @param string $string * @return string */ public static function get_string_from_input($string) {
< $string = trim($string); < < if (preg_match('|^([a-zA-Z][a-zA-Z0-9\.:/_-]*),([a-zA-Z][a-zA-Z0-9\.:/_-]*)$|', $string, $matches)) { < if ($matches[2] === 'moodle') { < $matches[2] = 'core';
> debugging('Use of ' . __FUNCTION__ . > '() have been deprecated, please update your code to use helper::get_string_from_input()', DEBUG_DEVELOPER); > return helper::get_string_from_input($string);
}
< if (get_string_manager()->string_exists($matches[1], $matches[2])) { < $string = get_string($matches[1], $matches[2]);
> /** > * Attempt to replace PIXICON placeholder with the correct images for tour step content. > * > * @param string $content Tour content > * @return string Processed tour content > */ > public static function get_step_image_from_input(string $content): string { > if (strpos($content, '@@PIXICON') === false) { > return $content;
}
> } > $content = preg_replace_callback('%@@PIXICON::(?P<identifier>([^::]*))::(?P<component>([^@@]*))@@%', > function(array $matches) { return $string; > global $OUTPUT; } > $component = $matches['component']; } > if ($component == 'moodle') { > $component = 'core';
> return \html_writer::img($OUTPUT->image_url($matches['identifier'], $component)->out(false), '', > ['class' => 'img-fluid']); > }, > $content > );
< return $string;
> return $content;