Search moodle.org's
Developer Documentation

  • Bug fixes for general core bugs in 3.11.x will end 9 May 2022 (12 months).
  • Bug fixes for security issues in 3.11.x will end 14 November 2022 (18 months).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.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   * Step class.
      19   *
      20   * @package    tool_usertours
      21   * @copyright  2016 Andrew Nicols <andrew@nicols.co.uk>
      22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
      23   */
      24  
      25  namespace tool_usertours;
      26  
      27  defined('MOODLE_INTERNAL') || die();
      28  
      29  /**
      30   * Step class.
      31   *
      32   * @copyright  2016 Andrew Nicols <andrew@nicols.co.uk>
      33   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
      34   */
      35  class step {
      36  
      37      /**
      38       * @var     int     $id         The id of the step.
      39       */
      40      protected $id;
      41  
      42      /**
      43       * @var     int     $tourid     The id of the tour that this step belongs to.
      44       */
      45      protected $tourid;
      46  
      47      /**
      48       * @var     tour    $tour       The tour class that this step belongs to.
      49       */
      50      protected $tour;
      51  
      52      /**
      53       * @var     string  $title      The title of the step.
      54       */
      55      protected $title;
      56  
      57      /**
      58       * @var     string  $content    The content of this step.
      59       */
      60      protected $content;
      61  
      62      /**
      63       * @var     int     $targettype The type of target.
      64       */
      65      protected $targettype;
      66  
      67      /**
      68       * @var     string  $targetvalue    The value for this type of target.
      69       */
      70      protected $targetvalue;
      71  
      72      /**
      73       * @var     int     $sortorder  The sort order.
      74       */
      75      protected $sortorder;
      76  
      77      /**
      78       * @var     object  $config     The configuration as an object.
      79       */
      80      protected $config;
      81  
      82      /**
      83       * @var     bool    $dirty      Whether the step has been changed since it was loaded
      84       */
      85      protected $dirty = false;
      86  
      87      /**
      88       * Fetch the step instance.
      89       *
      90       * @param   int             $id         The id of the step to be retrieved.
      91       * @return  step
      92       */
      93      public static function instance($id) {
      94          $step = new step();
      95          return $step->fetch($id);
      96      }
      97  
      98      /**
      99       * Load the step instance.
     100       *
     101       * @param   stdClass        $record     The step record to be loaded.
     102       * @param   boolean         $clean      Clean the values.
     103       * @return  step
     104       */
     105      public static function load_from_record($record, $clean = false) {
     106          $step = new self();
     107          return $step->reload_from_record($record, $clean);
     108      }
     109  
     110      /**
     111       * Fetch the step instance.
     112       *
     113       * @param   int             $id         The id of the step to be retrieved.
     114       * @return  step
     115       */
     116      protected function fetch($id) {
     117          global $DB;
     118  
     119          return $this->reload_from_record(
     120              $DB->get_record('tool_usertours_steps', array('id' => $id))
     121          );
     122      }
     123  
     124      /**
     125       * Refresh the current step from the datbase.
     126       *
     127       * @return  step
     128       */
     129      protected function reload() {
     130          return $this->fetch($this->id);
     131      }
     132  
     133      /**
     134       * Reload the current step from the supplied record.
     135       *
     136       * @param   stdClass        $record     The step record to be loaded.
     137       * @param   boolean         $clean      Clean the values.
     138       * @return  step
     139       */
     140      protected function reload_from_record($record, $clean = false) {
     141          $this->id           = $record->id;
     142          $this->tourid       = $record->tourid;
     143          if ($clean) {
     144              $this->title    = clean_param($record->title, PARAM_TEXT);
     145              $this->content  = clean_text($record->content);
     146          } else {
     147              $this->title    = $record->title;
     148              $this->content  = $record->content;
     149          }
     150          $this->targettype   = $record->targettype;
     151          $this->targetvalue  = $record->targetvalue;
     152          $this->sortorder    = $record->sortorder;
     153          $this->config       = json_decode($record->configdata);
     154          $this->dirty        = false;
     155  
     156          return $this;
     157      }
     158  
     159      /**
     160       * Get the ID of the step.
     161       *
     162       * @return  int
     163       */
     164      public function get_id() {
     165          return $this->id;
     166      }
     167  
     168      /**
     169       * Get the Tour ID of the step.
     170       *
     171       * @return  int
     172       */
     173      public function get_tourid() {
     174          return $this->tourid;
     175      }
     176  
     177      /**
     178       * Get the Tour instance that this step belongs to.
     179       *
     180       * @return  tour
     181       */
     182      public function get_tour() {
     183          if ($this->tour === null) {
     184              $this->tour = tour::instance($this->tourid);
     185          }
     186          return $this->tour;
     187      }
     188  
     189      /**
     190       * Set the id of the tour.
     191       *
     192       * @param   int             $value      The id of the tour.
     193       * @return  self
     194       */
     195      public function set_tourid($value) {
     196          $this->tourid = $value;
     197          $this->tour = null;
     198          $this->dirty = true;
     199  
     200          return $this;
     201      }
     202  
     203      /**
     204       * Get the Title of the step.
     205       *
     206       * @return  string
     207       */
     208      public function get_title() {
     209          return $this->title;
     210      }
     211  
     212      /**
     213       * Set the title for this step.
     214       *
     215       * @param   string      $value      The new title to use.
     216       * @return  $this
     217       */
     218      public function set_title($value) {
     219          $this->title = clean_text($value);
     220          $this->dirty = true;
     221  
     222          return $this;
     223      }
     224  
     225      /**
     226       * Get the body content of the step.
     227       *
     228       * @return  string
     229       */
     230      public function get_content() {
     231          return $this->content;
     232      }
     233  
     234      /**
     235       * Set the content value for this step.
     236       *
     237       * @param   string      $value      The new content to use.
     238       * @return  $this
     239       */
     240      public function set_content($value) {
     241          $this->content = clean_text($value);
     242          $this->dirty = true;
     243  
     244          return $this;
     245      }
     246  
     247      /**
     248       * Get the content value for this step.
     249       *
     250       * @return  string
     251       */
     252      public function get_targettype() {
     253          return $this->targettype;
     254      }
     255  
     256      /**
     257       * Set the type of target for this step.
     258       *
     259       * @param   string      $value      The new target to use.
     260       * @return  $this
     261       */
     262      public function set_targettype($value) {
     263          $this->targettype = $value;
     264          $this->dirty = true;
     265  
     266          return $this;
     267      }
     268  
     269      /**
     270       * Get the target value for this step.
     271       *
     272       * @return  string
     273       */
     274      public function get_targetvalue() {
     275          return $this->targetvalue;
     276      }
     277  
     278      /**
     279       * Set the target value for this step.
     280       *
     281       * @param   string      $value      The new target value to use.
     282       * @return  $this
     283       */
     284      public function set_targetvalue($value) {
     285          $this->targetvalue = $value;
     286          $this->dirty = true;
     287  
     288          return $this;
     289      }
     290  
     291      /**
     292       * Get the target instance for this step.
     293       *
     294       * @return  target
     295       */
     296      public function get_target() {
     297          return target::get_target_instance($this);
     298      }
     299  
     300      /**
     301       * Get the current sortorder for this step.
     302       *
     303       * @return  int
     304       */
     305      public function get_sortorder() {
     306          return (int) $this->sortorder;
     307      }
     308  
     309      /**
     310       * Whether this step is the first step in the tour.
     311       *
     312       * @return  boolean
     313       */
     314      public function is_first_step() {
     315          return ($this->get_sortorder() === 0);
     316      }
     317  
     318      /**
     319       * Whether this step is the last step in the tour.
     320       *
     321       * @return  boolean
     322       */
     323      public function is_last_step() {
     324          $stepcount = $this->get_tour()->count_steps();
     325          return ($this->get_sortorder() === $stepcount - 1);
     326      }
     327  
     328      /**
     329       * Set the sortorder for this step.
     330       *
     331       * @param   int         $value      The new sortorder to use.
     332       * @return  $this
     333       */
     334      public function set_sortorder($value) {
     335          $this->sortorder = $value;
     336          $this->dirty = true;
     337  
     338          return $this;
     339      }
     340  
     341      /**
     342       * Get the link to move this step up in the sortorder.
     343       *
     344       * @return  moodle_url
     345       */
     346      public function get_moveup_link() {
     347          return helper::get_move_step_link($this->get_id(), helper::MOVE_UP);
     348      }
     349  
     350      /**
     351       * Get the link to move this step down in the sortorder.
     352       *
     353       * @return  moodle_url
     354       */
     355      public function get_movedown_link() {
     356          return helper::get_move_step_link($this->get_id(), helper::MOVE_DOWN);
     357      }
     358  
     359      /**
     360       * Get the value of the specified configuration item.
     361       *
     362       * If notvalue was found, and no default was specified, the default for the tour will be used.
     363       *
     364       * @param   string      $key        The configuration key to set.
     365       * @param   mixed       $default    The default value to use if a value was not found.
     366       * @return  mixed
     367       */
     368      public function get_config($key = null, $default = null) {
     369          if ($this->config === null) {
     370              $this->config = (object) array();
     371          }
     372  
     373          if ($key === null) {
     374              return $this->config;
     375          }
     376  
     377          if ($this->get_targettype() !== null) {
     378              $target = $this->get_target();
     379              if ($target->is_setting_forced($key)) {
     380                  return $target->get_forced_setting_value($key);
     381              }
     382          }
     383  
     384          if (property_exists($this->config, $key)) {
     385              return $this->config->$key;
     386          }
     387  
     388          if ($default !== null) {
     389              return $default;
     390          }
     391  
     392          return $this->get_tour()->get_config($key);
     393      }
     394  
     395      /**
     396       * Set the configuration item as specified.
     397       *
     398       * @param   string      $key        The configuration key to set.
     399       * @param   mixed       $value      The new value for the configuration item.
     400       * @return  $this
     401       */
     402      public function set_config($key, $value) {
     403          if ($this->config === null) {
     404              $this->config = (object) array();
     405          }
     406  
     407          if ($value === null) {
     408              unset($this->config->$key);
     409          } else {
     410              $this->config->$key = $value;
     411          }
     412          $this->dirty = true;
     413  
     414          return $this;
     415      }
     416  
     417      /**
     418       * Get the edit link for this step.
     419       *
     420       * @return  moodle_url
     421       */
     422      public function get_edit_link() {
     423          return helper::get_edit_step_link($this->tourid, $this->id);
     424      }
     425  
     426      /**
     427       * Get the delete link for this step.
     428       *
     429       * @return  moodle_url
     430       */
     431      public function get_delete_link() {
     432          return helper::get_delete_step_link($this->id);
     433      }
     434  
     435      /**
     436       * Prepare this step for saving to the database.
     437       *
     438       * @return  object
     439       */
     440      public function to_record() {
     441          return (object) array(
     442              'id'            => $this->id,
     443              'tourid'        => $this->tourid,
     444              'title'         => $this->title,
     445              'content'       => $this->content,
     446              'targettype'    => $this->targettype,
     447              'targetvalue'   => $this->targetvalue,
     448              'sortorder'     => $this->sortorder,
     449              'configdata'    => json_encode($this->config),
     450          );
     451      }
     452  
     453      /**
     454       * Calculate the next sort-order value.
     455       *
     456       * @return  int
     457       */
     458      protected function calculate_sortorder() {
     459          $count = $this->get_tour()->count_steps();
     460          $this->sortorder = $count;
     461  
     462          return $this;
     463      }
     464  
     465      /**
     466       * Save the tour and it's configuration to the database.
     467       *
     468       * @param   boolean     $force      Whether to force writing to the database.
     469       * @return  $this
     470       */
     471      public function persist($force = false) {
     472          global $DB;
     473  
     474          if (!$this->dirty && !$force) {
     475              return $this;
     476          }
     477  
     478          if ($this->id) {
     479              $record = $this->to_record();
     480              $DB->update_record('tool_usertours_steps', $record);
     481          } else {
     482              $this->calculate_sortorder();
     483              $record = $this->to_record();
     484              unset($record->id);
     485              $this->id = $DB->insert_record('tool_usertours_steps', $record);
     486              $this->get_tour()->reset_step_sortorder();
     487          }
     488  
     489          $this->reload();
     490  
     491          // Notify of a change to the step configuration.
     492          // This must be done separately to tour change notifications.
     493          cache::notify_step_change($this->get_tourid());
     494  
     495          // Notify the cache that a tour has changed.
     496          // Tours are only stored in the cache if there are steps.
     497          // If there step count has changed for some reason, this will change the potential cache results.
     498          cache::notify_tour_change();
     499  
     500          return $this;
     501      }
     502  
     503      /**
     504       * Remove this step.
     505       */
     506      public function remove() {
     507          global $DB;
     508  
     509          if ($this->id === null) {
     510              return;
     511          }
     512  
     513          $DB->delete_records('tool_usertours_steps', array('id' => $this->id));
     514          $this->get_tour()->reset_step_sortorder();
     515  
     516          // Notify of a change to the step configuration.
     517          // This must be done separately to tour change notifications.
     518          cache::notify_step_change($this->get_id());
     519  
     520          // Notify the cache that a tour has changed.
     521          // Tours are only stored in the cache if there are steps.
     522          // If there step count has changed for some reason, this will change the potential cache results.
     523          cache::notify_tour_change();
     524      }
     525  
     526      /**
     527       * Get the list of possible placement options.
     528       *
     529       * @return  array
     530       */
     531      public function get_placement_options() {
     532          return configuration::get_placement_options(true);
     533      }
     534  
     535      /**
     536       * The list of possible configuration keys.
     537       *
     538       * @return  array
     539       */
     540      public static function get_config_keys() {
     541          return [
     542              'placement',
     543              'orphan',
     544              'backdrop',
     545              'reflex',
     546          ];
     547      }
     548  
     549      /**
     550       * Add the step configuration to the form.
     551       *
     552       * @param   MoodleQuickForm $mform      The form to add configuration to.
     553       * @return  $this
     554       */
     555      public function add_config_to_form(\MoodleQuickForm $mform) {
     556          $tour = $this->get_tour();
     557  
     558          $options = configuration::get_placement_options($tour->get_config('placement'));
     559          $mform->addElement('select', 'placement', get_string('placement', 'tool_usertours'), $options);
     560          $mform->addHelpButton('placement', 'placement', 'tool_usertours');
     561  
     562          $this->add_config_field_to_form($mform, 'orphan');
     563          $this->add_config_field_to_form($mform, 'backdrop');
     564          $this->add_config_field_to_form($mform, 'reflex');
     565  
     566          return $this;
     567      }
     568  
     569      /**
     570       * Add the specified step field configuration to the form.
     571       *
     572       * @param   MoodleQuickForm $mform      The form to add configuration to.
     573       * @param   string          $key        The key to add.
     574       * @return  $this
     575       */
     576      public function add_config_field_to_form(\MoodleQuickForm $mform, $key) {
     577          $tour = $this->get_tour();
     578  
     579          $default = (bool) $tour->get_config($key);
     580  
     581          $options = [
     582              true    => get_string('yes'),
     583              false   => get_string('no'),
     584          ];
     585  
     586          if (!isset($options[$default])) {
     587              $default = configuration::get_default_value($key);
     588          }
     589  
     590          $options = array_reverse($options, true);
     591          $options[configuration::TOURDEFAULT] = get_string('defaultvalue', 'tool_usertours', $options[$default]);
     592          $options = array_reverse($options, true);
     593  
     594          $mform->addElement('select', $key, get_string($key, 'tool_usertours'), $options);
     595          $mform->setDefault($key, configuration::TOURDEFAULT);
     596          $mform->addHelpButton($key, $key, 'tool_usertours');
     597  
     598          return $this;
     599      }
     600  
     601      /**
     602       * Prepare the configuration data for the moodle form.
     603       *
     604       * @return  object
     605       */
     606      public function prepare_data_for_form() {
     607          $data = $this->to_record();
     608          foreach (self::get_config_keys() as $key) {
     609              $data->$key = $this->get_config($key, configuration::get_step_default_value($key));
     610          }
     611  
     612          if ($this->get_targettype() !== null) {
     613              $this->get_target()->prepare_data_for_form($data);
     614          }
     615  
     616          return $data;
     617      }
     618  
     619      /**
     620       * Handle submission of the step editing form.
     621       *
     622       * @param   local\forms\editstep  $mform      The sumitted form.
     623       * @param   stdClass        $data       The submitted data.
     624       * @return  $this
     625       */
     626      public function handle_form_submission(local\forms\editstep &$mform, \stdClass $data) {
     627          $this->set_title($data->title);
     628          $this->set_content($data->content);
     629          $this->set_targettype($data->targettype);
     630  
     631          $this->set_targetvalue($this->get_target()->get_value_from_form($data));
     632  
     633          foreach (self::get_config_keys() as $key) {
     634              if (!$this->get_target()->is_setting_forced($key)) {
     635                  if (isset($data->$key)) {
     636                      $value = $data->$key;
     637                  } else {
     638                      $value = configuration::TOURDEFAULT;
     639                  }
     640                  if ($value === configuration::TOURDEFAULT) {
     641                      $this->set_config($key, null);
     642                  } else {
     643                      $this->set_config($key, $value);
     644                  }
     645              }
     646          }
     647  
     648          $this->persist();
     649  
     650          return $this;
     651      }
     652  
     653      /**
     654       * Attempt to fetch any matching langstring if the string is in the
     655       * format identifier,component.
     656       *
     657       * @param   string  $string
     658       * @return  string
     659       */
     660      public static function get_string_from_input($string) {
     661          $string = trim($string);
     662  
     663          if (preg_match('|^([a-zA-Z][a-zA-Z0-9\.:/_-]*),([a-zA-Z][a-zA-Z0-9\.:/_-]*)$|', $string, $matches)) {
     664              if ($matches[2] === 'moodle') {
     665                  $matches[2] = 'core';
     666              }
     667  
     668              if (get_string_manager()->string_exists($matches[1], $matches[2])) {
     669                  $string = get_string($matches[1], $matches[2]);
     670              }
     671          }
     672  
     673          return $string;
     674      }
     675  }