Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 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   * 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  }