Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.2.x will end 22 April 2024 (12 months).
  • Bug fixes for security issues in 4.2.x will end 7 October 2024 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.1.x is supported too.

Differences Between: [Versions 310 and 402] [Versions 311 and 402] [Versions 39 and 402] [Versions 400 and 402] [Versions 401 and 402]

   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   * Tour 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  use tool_usertours\local\clientside_filter\clientside_filter;
  28  
  29  defined('MOODLE_INTERNAL') || die();
  30  
  31  /**
  32   * Tour class.
  33   *
  34   * @copyright  2016 Andrew Nicols <andrew@nicols.co.uk>
  35   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  36   */
  37  class tour {
  38  
  39      /**
  40       * The tour is currently disabled
  41       *
  42       * @var DISABLED
  43       */
  44      const DISABLED = 0;
  45  
  46      /**
  47       * The tour is currently disabled
  48       *
  49       * @var DISABLED
  50       */
  51      const ENABLED = 1;
  52  
  53      /**
  54       * The user preference value to indicate the time of completion of the tour for a user.
  55       *
  56       * @var TOUR_LAST_COMPLETED_BY_USER
  57       */
  58      const TOUR_LAST_COMPLETED_BY_USER   = 'tool_usertours_tour_completion_time_';
  59  
  60      /**
  61       * The user preference value to indicate the time that a user last requested to see the tour.
  62       *
  63       * @var TOUR_REQUESTED_BY_USER
  64       */
  65      const TOUR_REQUESTED_BY_USER        = 'tool_usertours_tour_reset_time_';
  66  
  67      /**
  68       * @var $id The tour ID.
  69       */
  70      protected $id;
  71  
  72      /**
  73       * @var $name The tour name.
  74       */
  75      protected $name;
  76  
  77      /**
  78       * @var $description The tour description.
  79       */
  80      protected $description;
  81  
  82      /**
  83       * @var $pathmatch The tour pathmatch.
  84       */
  85      protected $pathmatch;
  86  
  87      /**
  88       * @var $enabled The tour enabled state.
  89       */
  90      protected $enabled;
  91  
  92      /**
  93       * @var $endtourlabel The end tour label.
  94       */
  95      protected $endtourlabel;
  96  
  97      /**
  98       * @var $sortorder The sort order.
  99       */
 100      protected $sortorder;
 101  
 102      /**
 103       * @var $dirty Whether the current view of the tour has been modified.
 104       */
 105      protected $dirty = false;
 106  
 107      /**
 108       * @var $config The configuration object for the tour.
 109       */
 110      protected $config;
 111  
 112      /**
 113       * @var $filtervalues The filter configuration object for the tour.
 114       */
 115      protected $filtervalues;
 116  
 117      /**
 118       * @var $steps  The steps in this tour.
 119       */
 120      protected $steps = [];
 121  
 122      /**
 123       * @var bool $displaystepnumbers Display the step numbers in this tour.
 124       */
 125      protected $displaystepnumbers = true;
 126  
 127      /**
 128       * Create an instance of the specified tour.
 129       *
 130       * @param   int         $id         The ID of the tour to load.
 131       * @return  tour
 132       */
 133      public static function instance($id) {
 134          $tour = new self();
 135          return $tour->fetch($id);
 136      }
 137  
 138      /**
 139       * Create an instance of tour from its provided DB record.
 140       *
 141       * @param   stdClass    $record     The record of the tour to load.
 142       * @param   boolean     $clean      Clean the values.
 143       * @return  tour
 144       */
 145      public static function load_from_record($record, $clean = false) {
 146          $tour = new self();
 147          return $tour->reload_from_record($record, $clean);
 148      }
 149  
 150      /**
 151       * Fetch the specified tour into the current object.
 152       *
 153       * @param   int         $id         The ID of the tour to fetch.
 154       * @return  tour
 155       */
 156      protected function fetch($id) {
 157          global $DB;
 158  
 159          return $this->reload_from_record(
 160              $DB->get_record('tool_usertours_tours', array('id' => $id), '*', MUST_EXIST)
 161          );
 162      }
 163  
 164      /**
 165       * Reload the current tour from database.
 166       *
 167       * @return  tour
 168       */
 169      protected function reload() {
 170          return $this->fetch($this->id);
 171      }
 172  
 173      /**
 174       * Reload the tour into the current object.
 175       *
 176       * @param   stdClass    $record     The record to reload.
 177       * @param   boolean     $clean      Clean the values.
 178       * @return  tour
 179       */
 180      protected function reload_from_record($record, $clean = false) {
 181          $this->id           = $record->id;
 182          if (!property_exists($record, 'description')) {
 183              if (property_exists($record, 'comment')) {
 184                  $record->description = $record->comment;
 185                  unset($record->comment);
 186              }
 187          }
 188          if ($clean) {
 189              $this->name         = clean_param($record->name, PARAM_TEXT);
 190              $this->description  = clean_text($record->description);
 191          } else {
 192              $this->name         = $record->name;
 193              $this->description  = $record->description;
 194          }
 195          $this->pathmatch    = $record->pathmatch;
 196          $this->enabled      = $record->enabled;
 197          if (isset($record->sortorder)) {
 198              $this->sortorder = $record->sortorder;
 199          }
 200          $this->endtourlabel = $record->endtourlabel ?? null;
 201          $this->config       = json_decode($record->configdata);
 202          $this->dirty        = false;
 203          $this->steps        = [];
 204          $this->displaystepnumbers = !empty($record->displaystepnumbers);
 205  
 206          return $this;
 207      }
 208  
 209      /**
 210       * Fetch all steps in the tour.
 211       *
 212       * @return  step[]
 213       */
 214      public function get_steps() {
 215          if (empty($this->steps)) {
 216              $this->steps = helper::get_steps($this->id);
 217          }
 218  
 219          return $this->steps;
 220      }
 221  
 222      /**
 223       * Count the number of steps in the tour.
 224       *
 225       * @return  int
 226       */
 227      public function count_steps() {
 228          return count($this->get_steps());
 229      }
 230  
 231      /**
 232       * The ID of the tour.
 233       *
 234       * @return  int
 235       */
 236      public function get_id() {
 237          return $this->id;
 238      }
 239  
 240      /**
 241       * The name of the tour.
 242       *
 243       * @return  string
 244       */
 245      public function get_name() {
 246          return $this->name;
 247      }
 248  
 249      /**
 250       * Set the name of the tour to the specified value.
 251       *
 252       * @param   string      $value      The new name.
 253       * @return  $this
 254       */
 255      public function set_name($value) {
 256          $this->name = clean_param($value, PARAM_TEXT);
 257          $this->dirty = true;
 258  
 259          return $this;
 260      }
 261  
 262      /**
 263       * The description associated with the tour.
 264       *
 265       * @return  string
 266       */
 267      public function get_description() {
 268          return $this->description;
 269      }
 270  
 271      /**
 272       * Set the description of the tour to the specified value.
 273       *
 274       * @param   string      $value      The new description.
 275       * @return  $this
 276       */
 277      public function set_description($value) {
 278          $this->description = clean_text($value);
 279          $this->dirty = true;
 280  
 281          return $this;
 282      }
 283  
 284      /**
 285       * The path match for the tour.
 286       *
 287       * @return  string
 288       */
 289      public function get_pathmatch() {
 290          return $this->pathmatch;
 291      }
 292  
 293      /**
 294       * Set the patchmatch of the tour to the specified value.
 295       *
 296       * @param   string      $value      The new patchmatch.
 297       * @return  $this
 298       */
 299      public function set_pathmatch($value) {
 300          $this->pathmatch = $value;
 301          $this->dirty = true;
 302  
 303          return $this;
 304      }
 305  
 306      /**
 307       * The enabled state of the tour.
 308       *
 309       * @return  int
 310       */
 311      public function get_enabled() {
 312          return $this->enabled;
 313      }
 314  
 315      /**
 316       * Whether the tour is currently enabled.
 317       *
 318       * @return  boolean
 319       */
 320      public function is_enabled() {
 321          return ($this->enabled == self::ENABLED);
 322      }
 323  
 324      /**
 325       * Set the enabled state of the tour to the specified value.
 326       *
 327       * @param   boolean     $value      The new state.
 328       * @return  $this
 329       */
 330      public function set_enabled($value) {
 331          $this->enabled = $value;
 332          $this->dirty = true;
 333  
 334          return $this;
 335      }
 336  
 337      /**
 338       * The end tour label for the tour.
 339       *
 340       * @return string
 341       */
 342      public function get_endtourlabel(): string {
 343          if ($this->endtourlabel) {
 344              $label = helper::get_string_from_input($this->endtourlabel);
 345          } else if ($this->count_steps() == 1) {
 346              $label = get_string('endonesteptour', 'tool_usertours');
 347          } else {
 348              $label = get_string('endtour', 'tool_usertours');
 349          }
 350  
 351          return $label;
 352      }
 353  
 354      /**
 355       * Set the endtourlabel of the tour to the specified value.
 356       *
 357       * @param string $value
 358       * @return $this
 359       */
 360      public function set_endtourlabel(string $value): tour {
 361          $this->endtourlabel = $value;
 362          $this->dirty = true;
 363  
 364          return $this;
 365      }
 366  
 367      /**
 368       * The link to view this tour.
 369       *
 370       * @return  \moodle_url
 371       */
 372      public function get_view_link() {
 373          return helper::get_view_tour_link($this->id);
 374      }
 375  
 376      /**
 377       * The link to edit this tour.
 378       *
 379       * @return  \moodle_url
 380       */
 381      public function get_edit_link() {
 382          return helper::get_edit_tour_link($this->id);
 383      }
 384  
 385      /**
 386       * The link to reset the state of this tour for all users.
 387       *
 388       * @return  moodle_url
 389       */
 390      public function get_reset_link() {
 391          return helper::get_reset_tour_for_all_link($this->id);
 392      }
 393  
 394      /**
 395       * The link to export this tour.
 396       *
 397       * @return  moodle_url
 398       */
 399      public function get_export_link() {
 400          return helper::get_export_tour_link($this->id);
 401      }
 402  
 403      /**
 404       * The link to duplicate this tour.
 405       *
 406       * @return  moodle_url
 407       */
 408      public function get_duplicate_link() {
 409          return helper::get_duplicate_tour_link($this->id);
 410      }
 411  
 412      /**
 413       * The link to remove this tour.
 414       *
 415       * @return  moodle_url
 416       */
 417      public function get_delete_link() {
 418          return helper::get_delete_tour_link($this->id);
 419      }
 420  
 421      /**
 422       * Prepare this tour for saving to the database.
 423       *
 424       * @return  object
 425       */
 426      public function to_record() {
 427          return (object) array(
 428              'id'            => $this->id,
 429              'name'          => $this->name,
 430              'description'   => $this->description,
 431              'pathmatch'     => $this->pathmatch,
 432              'enabled'       => $this->enabled,
 433              'sortorder'     => $this->sortorder,
 434              'endtourlabel'  => $this->endtourlabel,
 435              'configdata'    => json_encode($this->config),
 436              'displaystepnumbers' => $this->displaystepnumbers,
 437          );
 438      }
 439  
 440      /**
 441       * Get the current sortorder for this tour.
 442       *
 443       * @return  int
 444       */
 445      public function get_sortorder() {
 446          return (int) $this->sortorder;
 447      }
 448  
 449      /**
 450       * Whether this tour is the first tour.
 451       *
 452       * @return  boolean
 453       */
 454      public function is_first_tour() {
 455          return ($this->get_sortorder() === 0);
 456      }
 457  
 458      /**
 459       * Whether this tour is the last tour.
 460       *
 461       * @param   int         $tourcount  The pre-fetched count of tours
 462       * @return  boolean
 463       */
 464      public function is_last_tour($tourcount = null) {
 465          if ($tourcount === null) {
 466              $tourcount = helper::count_tours();
 467          }
 468          return ($this->get_sortorder() === ($tourcount - 1));
 469      }
 470  
 471      /**
 472       * Set the sortorder for this tour.
 473       *
 474       * @param   int         $value      The new sortorder to use.
 475       * @return  $this
 476       */
 477      public function set_sortorder($value) {
 478          $this->sortorder = $value;
 479          $this->dirty = true;
 480  
 481          return $this;
 482      }
 483  
 484      /**
 485       * Calculate the next sort-order value.
 486       *
 487       * @return  int
 488       */
 489      protected function calculate_sortorder() {
 490          $this->sortorder = helper::count_tours();
 491  
 492          return $this;
 493      }
 494  
 495      /**
 496       * Get the link to move this tour up in the sortorder.
 497       *
 498       * @return  moodle_url
 499       */
 500      public function get_moveup_link() {
 501          return helper::get_move_tour_link($this->get_id(), helper::MOVE_UP);
 502      }
 503  
 504      /**
 505       * Get the link to move this tour down in the sortorder.
 506       *
 507       * @return  moodle_url
 508       */
 509      public function get_movedown_link() {
 510          return helper::get_move_tour_link($this->get_id(), helper::MOVE_DOWN);
 511      }
 512  
 513      /**
 514       * Get the value of the specified configuration item.
 515       *
 516       * @param   string      $key        The configuration key to set.
 517       * @param   mixed       $default    The default value to use if a value was not found.
 518       * @return  mixed
 519       */
 520      public function get_config($key = null, $default = null) {
 521          if ($this->config === null) {
 522              $this->config = (object) array();
 523          }
 524          if ($key === null) {
 525              return $this->config;
 526          }
 527  
 528          if (property_exists($this->config, $key)) {
 529              return $this->config->$key;
 530          }
 531  
 532          if ($default !== null) {
 533              return $default;
 534          }
 535  
 536          return configuration::get_default_value($key);
 537      }
 538  
 539      /**
 540       * Set the configuration item as specified.
 541       *
 542       * @param   string      $key        The configuration key to set.
 543       * @param   mixed       $value      The new value for the configuration item.
 544       * @return  $this
 545       */
 546      public function set_config($key, $value) {
 547          if ($this->config === null) {
 548              $this->config = (object) array();
 549          }
 550          $this->config->$key = $value;
 551          $this->dirty = true;
 552  
 553          return $this;
 554      }
 555  
 556      /**
 557       * Save the tour and it's configuration to the database.
 558       *
 559       * @param   boolean     $force      Whether to force writing to the database.
 560       * @return  $this
 561       */
 562      public function persist($force = false) {
 563          global $DB;
 564  
 565          if (!$this->dirty && !$force) {
 566              return $this;
 567          }
 568  
 569          if ($this->id) {
 570              $record = $this->to_record();
 571              $DB->update_record('tool_usertours_tours', $record);
 572          } else {
 573              $this->calculate_sortorder();
 574              $record = $this->to_record();
 575              unset($record->id);
 576              $this->id = $DB->insert_record('tool_usertours_tours', $record);
 577          }
 578  
 579          $this->reload();
 580  
 581          // Notify the cache that a tour has changed.
 582          cache::notify_tour_change();
 583  
 584          return $this;
 585      }
 586  
 587      /**
 588       * Remove this step.
 589       */
 590      public function remove() {
 591          global $DB;
 592  
 593          if ($this->id === null) {
 594              // Nothing to delete - this tour has not been persisted.
 595              return null;
 596          }
 597  
 598          // Delete all steps associated with this tour.
 599          // Note, although they are currently just DB records, there may be other components in the future.
 600          foreach ($this->get_steps() as $step) {
 601              $step->remove();
 602          }
 603  
 604          // Remove the configuration for the tour.
 605          $DB->delete_records('tool_usertours_tours', array('id' => $this->id));
 606          helper::reset_tour_sortorder();
 607  
 608          $this->remove_user_preferences();
 609  
 610          return null;
 611      }
 612  
 613      /**
 614       * Reset the sortorder for all steps in the tour.
 615       *
 616       * @return  $this
 617       */
 618      public function reset_step_sortorder() {
 619          global $DB;
 620          $steps = $DB->get_records('tool_usertours_steps', array('tourid' => $this->id), 'sortorder ASC', 'id');
 621  
 622          $index = 0;
 623          foreach ($steps as $step) {
 624              $DB->set_field('tool_usertours_steps', 'sortorder', $index, array('id' => $step->id));
 625              $index++;
 626          }
 627  
 628          // Notify of a change to the step configuration.
 629          // Note: Do not notify of a tour change here. This is only a step change for a tour.
 630          cache::notify_step_change($this->get_id());
 631  
 632          return $this;
 633      }
 634  
 635      /**
 636       * Remove stored user preferences for the tour
 637       */
 638      protected function remove_user_preferences(): void {
 639          global $DB;
 640  
 641          $DB->delete_records('user_preferences', ['name' => self::TOUR_LAST_COMPLETED_BY_USER . $this->get_id()]);
 642          $DB->delete_records('user_preferences', ['name' => self::TOUR_REQUESTED_BY_USER . $this->get_id()]);
 643      }
 644  
 645      /**
 646       * Whether this tour should be displayed to the user.
 647       *
 648       * @return  boolean
 649       */
 650      public function should_show_for_user() {
 651          if (!$this->is_enabled()) {
 652              // The tour is disabled - it should not be shown.
 653              return false;
 654          }
 655  
 656          if ($tourcompletiondate = get_user_preferences(self::TOUR_LAST_COMPLETED_BY_USER . $this->get_id(), null)) {
 657              if ($tourresetdate = get_user_preferences(self::TOUR_REQUESTED_BY_USER . $this->get_id(), null)) {
 658                  if ($tourresetdate >= $tourcompletiondate) {
 659                      return true;
 660                  }
 661              }
 662              $lastmajorupdate = $this->get_config('majorupdatetime', time());
 663              if ($tourcompletiondate > $lastmajorupdate) {
 664                  // The user has completed the tour since the last major update.
 665                  return false;
 666              }
 667          }
 668  
 669          return true;
 670      }
 671  
 672      /**
 673       * Get the key for this tour.
 674       * This is used in the session cookie to determine whether the user has seen this tour before.
 675       */
 676      public function get_tour_key() {
 677          global $USER;
 678  
 679          $tourtime = $this->get_config('majorupdatetime', null);
 680  
 681          if ($tourtime === null) {
 682              // This tour has no majorupdate time.
 683              // Set one now to prevent repeated displays to the user.
 684              $this->set_config('majorupdatetime', time());
 685              $this->persist();
 686              $tourtime = $this->get_config('majorupdatetime', null);
 687          }
 688  
 689          if ($userresetdate = get_user_preferences(self::TOUR_REQUESTED_BY_USER . $this->get_id(), null)) {
 690              $tourtime = max($tourtime, $userresetdate);
 691          }
 692  
 693          return sprintf('tool_usertours_%d_%d_%s', $USER->id, $this->get_id(), $tourtime);
 694      }
 695  
 696      /**
 697       * Reset the requested by user date.
 698       *
 699       * @return  $this
 700       */
 701      public function request_user_reset() {
 702          set_user_preference(self::TOUR_REQUESTED_BY_USER . $this->get_id(), time());
 703  
 704          return $this;
 705      }
 706  
 707      /**
 708       * Mark this tour as completed for this user.
 709       *
 710       * @return  $this
 711       */
 712      public function mark_user_completed() {
 713          set_user_preference(self::TOUR_LAST_COMPLETED_BY_USER . $this->get_id(), time());
 714  
 715          return $this;
 716      }
 717  
 718      /**
 719       * Update a tour giving it a new major update time.
 720       * This will ensure that it is displayed to all users, even those who have already seen it.
 721       *
 722       * @return  $this
 723       */
 724      public function mark_major_change() {
 725          // Clear old reset and completion notes.
 726          $this->remove_user_preferences();
 727  
 728          $this->set_config('majorupdatetime', time());
 729          $this->persist();
 730  
 731          return $this;
 732      }
 733  
 734      /**
 735       * Add the step configuration to the form.
 736       *
 737       * @param   MoodleQuickForm $mform      The form to add configuration to.
 738       * @return  $this
 739       */
 740      public function add_config_to_form(\MoodleQuickForm &$mform) {
 741          $options = configuration::get_placement_options();
 742          $mform->addElement('select', 'placement', get_string('placement', 'tool_usertours'), $options);
 743          $mform->addHelpButton('placement', 'placement', 'tool_usertours');
 744  
 745          $this->add_config_field_to_form($mform, 'orphan');
 746          $this->add_config_field_to_form($mform, 'backdrop');
 747          $this->add_config_field_to_form($mform, 'reflex');
 748  
 749          return $this;
 750      }
 751  
 752      /**
 753       * Add the specified step field configuration to the form.
 754       *
 755       * @param   MoodleQuickForm $mform      The form to add configuration to.
 756       * @param   string          $key        The key to add.
 757       * @return  $this
 758       */
 759      protected function add_config_field_to_form(\MoodleQuickForm &$mform, $key) {
 760          $options = [
 761              true    => get_string('yes'),
 762              false   => get_string('no'),
 763          ];
 764          $mform->addElement('select', $key, get_string($key, 'tool_usertours'), $options);
 765          $mform->setDefault($key, configuration::get_default_value($key));
 766          $mform->addHelpButton($key, $key, 'tool_usertours');
 767  
 768          return $this;
 769      }
 770  
 771      /**
 772       * Prepare the configuration data for the moodle form.
 773       *
 774       * @return  object
 775       */
 776      public function prepare_data_for_form() {
 777          $data = $this->to_record();
 778          foreach (configuration::get_defaultable_keys() as $key) {
 779              $data->$key = $this->get_config($key, configuration::get_default_value($key));
 780          }
 781  
 782          return $data;
 783      }
 784  
 785      /**
 786       * Get the configured filter values.
 787       *
 788       * @param   string      $filter     The filter to retrieve values for.
 789       * @return  array
 790       */
 791      public function get_filter_values($filter) {
 792          if ($allvalues = (array) $this->get_config('filtervalues')) {
 793              if (isset($allvalues[$filter])) {
 794                  return $allvalues[$filter];
 795              }
 796          }
 797  
 798          return [];
 799      }
 800  
 801      /**
 802       * Set the values for the specified filter.
 803       *
 804       * @param   string      $filter     The filter to set.
 805       * @param   array       $values     The values to set.
 806       * @return  $this
 807       */
 808      public function set_filter_values($filter, array $values = []) {
 809          $allvalues = (array) $this->get_config('filtervalues', []);
 810          $allvalues[$filter] = $values;
 811  
 812          return $this->set_config('filtervalues', $allvalues);
 813      }
 814  
 815      /**
 816       * Check whether this tour matches all filters.
 817       *
 818       * @param   \context     $context    The context to check.
 819       * @param   array|null   $filters    Optional array of filters.
 820       * @return  bool
 821       */
 822      public function matches_all_filters(\context $context, array $filters = null): bool {
 823          if (!$filters) {
 824              $filters = helper::get_all_filters();
 825          }
 826  
 827          // All filters must match.
 828          // If any one filter fails to match, we return false.
 829          foreach ($filters as $filterclass) {
 830              if (!$filterclass::filter_matches($this, $context)) {
 831                  return false;
 832              }
 833          }
 834  
 835          return true;
 836      }
 837  
 838      /**
 839       * Gets all filter values for use in client side filters.
 840       *
 841       * @param   array     $filters    Array of clientside filters.
 842       * @return  array
 843       */
 844      public function get_client_filter_values(array $filters): array {
 845          $results = [];
 846  
 847          foreach ($filters as $filter) {
 848              $results[$filter::get_filter_name()] = $filter::get_client_side_values($this);
 849          }
 850  
 851          return $results;
 852      }
 853  
 854      /**
 855       * Set the value for the display step numbers setting.
 856       *
 857       * @param bool $value True for enable.
 858       * @return $this
 859       */
 860      public function set_display_step_numbers(bool $value): tour {
 861          $this->displaystepnumbers = $value;
 862          $this->dirty = true;
 863  
 864          return $this;
 865      }
 866  
 867      /**
 868       * Get the value of the display step numbers setting.
 869       *
 870       * @return bool
 871       */
 872      public function get_display_step_numbers(): bool {
 873          return $this->displaystepnumbers;
 874      }
 875  }