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.
   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   * Node (base class) used to construct a tree of availability conditions.
  19   *
  20   * @package core_availability
  21   * @copyright 2014 The Open University
  22   * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  namespace core_availability;
  26  
  27  defined('MOODLE_INTERNAL') || die();
  28  
  29  /**
  30   * Node (base class) used to construct a tree of availability conditions.
  31   *
  32   * @package core_availability
  33   * @copyright 2014 The Open University
  34   * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  35   */
  36  abstract class tree_node {
  37  
  38      /** @var int Counter to be used in {@link tree_node::unique_sql_parameter()}. */
  39      protected static $uniquesqlparametercounter = 1;
  40  
  41      /**
  42       * Determines whether this particular item is currently available
  43       * according to the availability criteria.
  44       *
  45       * - This does not include the 'visible' setting (i.e. this might return
  46       *   true even if visible is false); visible is handled independently.
  47       * - This does not take account of the viewhiddenactivities capability.
  48       *   That should apply later.
  49       *
  50       * The $not option is potentially confusing. This option always indicates
  51       * the 'real' value of NOT. For example, a condition inside a 'NOT AND'
  52       * group will get this called with $not = true, but if you put another
  53       * 'NOT OR' group inside the first group, then a condition inside that will
  54       * be called with $not = false. We need to use the real values, rather than
  55       * the more natural use of the current value at this point inside the tree,
  56       * so that the information displayed to users makes sense.
  57       *
  58       * @param bool $not Set true if we are inverting the condition
  59       * @param \core_availability\info $info Item we're checking
  60       * @param bool $grabthelot Performance hint: if true, caches information
  61       *   required for all course-modules, to make the front page and similar
  62       *   pages work more quickly (works only for current user)
  63       * @param int $userid User ID to check availability for
  64       * @return result Availability check result
  65       */
  66      public abstract function check_available($not,
  67              \core_availability\info $info, $grabthelot, $userid);
  68  
  69      /**
  70       * Checks whether this condition is actually going to be available for
  71       * all users under normal circumstances.
  72       *
  73       * Normally, if there are any conditions, then it may be hidden. However
  74       * in the case of date conditions there are some conditions which will
  75       * definitely not result in it being hidden for anyone.
  76       *
  77       * @param bool $not Set true if we are inverting the condition
  78       * @return bool True if condition will return available for everyone
  79       */
  80      public abstract function is_available_for_all($not = false);
  81  
  82      /**
  83       * Saves tree data back to a structure object.
  84       *
  85       * @return \stdClass Structure object (ready to be made into JSON format)
  86       */
  87      public abstract function save();
  88  
  89      /**
  90       * Checks whether this node should be included after restore or not. The
  91       * node may be removed depending on restore settings, which you can get from
  92       * the $task object.
  93       *
  94       * By default nodes are still included after restore.
  95       *
  96       * @param string $restoreid Restore ID
  97       * @param int $courseid ID of target course
  98       * @param \base_logger $logger Logger for any warnings
  99       * @param string $name Name of this item (for use in warning messages)
 100       * @param \base_task $task Current restore task
 101       * @return bool True if there was any change
 102       */
 103      public function include_after_restore($restoreid, $courseid, \base_logger $logger, $name,
 104              \base_task $task) {
 105          return true;
 106      }
 107  
 108      /**
 109       * Updates this node after restore, returning true if anything changed.
 110       * The default behaviour is simply to return false. If there is a problem
 111       * with the update, $logger can be used to output a warning.
 112       *
 113       * Note: If you need information about the date offset, call
 114       * \core_availability\info::get_restore_date_offset($restoreid). For
 115       * information on the restoring task and its settings, call
 116       * \core_availability\info::get_restore_task($restoreid).
 117       *
 118       * @param string $restoreid Restore ID
 119       * @param int $courseid ID of target course
 120       * @param \base_logger $logger Logger for any warnings
 121       * @param string $name Name of this item (for use in warning messages)
 122       * @return bool True if there was any change
 123       */
 124      public function update_after_restore($restoreid, $courseid, \base_logger $logger, $name) {
 125          return false;
 126      }
 127  
 128      /**
 129       * Updates this node if it contains any references (dependencies) to the
 130       * given table and id.
 131       *
 132       * @param string $table Table name e.g. 'course_modules'
 133       * @param int $oldid Previous ID
 134       * @param int $newid New ID
 135       * @return bool True if it changed, otherwise false
 136       */
 137      public abstract function update_dependency_id($table, $oldid, $newid);
 138  
 139      /**
 140       * Checks whether this condition applies to user lists. The default is
 141       * false (the condition is used to control access, but does not prevent
 142       * the student from appearing in lists).
 143       *
 144       * For example, group conditions apply to user lists: we do not want to
 145       * include a student in a list of users if they are prohibited from
 146       * accessing the activity because they don't belong to a relevant group.
 147       * However, date conditions do not apply - we still want to show users
 148       * in a list of people who might have submitted an assignment, even if they
 149       * are no longer able to access the assignment in question because there is
 150       * a date restriction.
 151       *
 152       * The general idea is that conditions which are likely to be permanent
 153       * (group membership, user profile) apply to user lists. Conditions which
 154       * are likely to be temporary (date, grade requirement) do not.
 155       *
 156       * Conditions which do apply to user lists must implement the
 157       * filter_user_list function.
 158       *
 159       * @return bool True if this condition applies to user lists
 160       */
 161      public function is_applied_to_user_lists() {
 162          return false;
 163      }
 164  
 165      /**
 166       * Tests this condition against a user list. Users who do not meet the
 167       * condition will be removed from the list, unless they have the ability
 168       * to view hidden activities/sections.
 169       *
 170       * This function must be implemented if is_applied_to_user_lists returns
 171       * true. Otherwise it will not be called.
 172       *
 173       * The function must operate efficiently, e.g. by using a fixed number of
 174       * database queries regardless of how many users are in the list.
 175       *
 176       * Within this function, if you need to check capabilities, please use
 177       * the provided checker which caches results where possible.
 178       *
 179       * Conditions do not need to check the viewhiddenactivities or
 180       * viewhiddensections capabilities. These are handled by
 181       * core_availability\info::filter_user_list.
 182       *
 183       * @param array $users Array of userid => object
 184       * @param bool $not True if this condition is applying in negative mode
 185       * @param \core_availability\info $info Item we're checking
 186       * @param capability_checker $checker
 187       * @return array Filtered version of input array
 188       * @throws \coding_exception If called on a condition that doesn't apply to user lists
 189       */
 190      public function filter_user_list(array $users, $not,
 191              \core_availability\info $info, capability_checker $checker) {
 192          throw new \coding_exception('Not implemented (do not call unless '.
 193                  'is_applied_to_user_lists is true)');
 194      }
 195  
 196      /**
 197       * Obtains SQL that returns a list of enrolled users that has been filtered
 198       * by the conditions applied in the availability API, similar to calling
 199       * get_enrolled_users and then filter_user_list. As for filter_user_list,
 200       * this ONLY filters out users with conditions that are marked as applying
 201       * to user lists. For example, group conditions are included but date
 202       * conditions are not included.
 203       *
 204       * The returned SQL is a query that returns a list of user IDs. It does not
 205       * include brackets, so you neeed to add these to make it into a subquery.
 206       * You would normally use it in an SQL phrase like "WHERE u.id IN ($sql)".
 207       *
 208       * The SQL will be complex and may be slow. It uses named parameters (sorry,
 209       * I know they are annoying, but it was unavoidable here).
 210       *
 211       * If there are no conditions, the returned result is array('', array()).
 212       *
 213       * Conditions do not need to check the viewhiddenactivities or
 214       * viewhiddensections capabilities. These are handled by
 215       * core_availability\info::get_user_list_sql.
 216       *
 217       * @param bool $not True if this condition is applying in negative mode
 218       * @param \core_availability\info $info Item we're checking
 219       * @param bool $onlyactive If true, only returns active enrolments
 220       * @return array Array with two elements: SQL subquery and parameters array
 221       * @throws \coding_exception If called on a condition that doesn't apply to user lists
 222       */
 223      public function get_user_list_sql($not, \core_availability\info $info, $onlyactive) {
 224          if (!$this->is_applied_to_user_lists()) {
 225              throw new \coding_exception('Not implemented (do not call unless '.
 226                      'is_applied_to_user_lists is true)');
 227          }
 228  
 229          // Handle situation where plugin does not implement this, by returning a
 230          // default (all enrolled users). This ensures compatibility with 2.7
 231          // plugins and behaviour. Plugins should be updated to support this
 232          // new function (if they return true to is_applied_to_user_lists).
 233          debugging('Availability plugins that return true to is_applied_to_user_lists ' .
 234                  'should also now implement get_user_list_sql: ' . get_class($this),
 235                  DEBUG_DEVELOPER);
 236          return get_enrolled_sql($info->get_context(), '', 0, $onlyactive);
 237      }
 238  
 239      /**
 240       * Utility function for generating SQL parameters (because we can't use ?
 241       * parameters because get_enrolled_sql has infected us with horrible named
 242       * parameters).
 243       *
 244       * @param array $params Params array (value will be added to this array)
 245       * @param string|int $value Value
 246       * @return SQL code for the parameter, e.g. ':pr1234'
 247       */
 248      protected static function unique_sql_parameter(array &$params, $value) {
 249  
 250          // Note we intentionally do not use self:: here.
 251          $count = tree_node::$uniquesqlparametercounter++;
 252          $unique = 'usp' . $count;
 253          $params[$unique] = $value;
 254          return ':' . $unique;
 255      }
 256  }