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