Commit | Line | Data |
---|---|---|
3acc9b81 SH |
1 | <?php |
2 | ||
3 | // This file is part of Moodle - http://moodle.org/ | |
4 | // | |
5 | // Moodle is free software: you can redistribute it and/or modify | |
6 | // it under the terms of the GNU General Public License as published by | |
7 | // the Free Software Foundation, either version 3 of the License, or | |
8 | // (at your option) any later version. | |
9 | // | |
10 | // Moodle is distributed in the hope that it will be useful, | |
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | // GNU General Public License for more details. | |
14 | // | |
15 | // You should have received a copy of the GNU General Public License | |
16 | // along with Moodle. If not, see <http://www.gnu.org/licenses/>. | |
17 | ||
18 | /** | |
19 | * This file contains components used by the restore UI | |
20 | * | |
21 | * @package moodlecore | |
22 | * @copyright 2010 Sam Hemelryk | |
23 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
24 | */ | |
25 | ||
26 | /** | |
27 | * A base class that can be used to build a specific search upon | |
28 | */ | |
29 | abstract class restore_search_base implements renderable { | |
30 | ||
31 | /** | |
32 | * The default values for this components params | |
33 | */ | |
3acc9b81 SH |
34 | const DEFAULT_SEARCH = ''; |
35 | ||
3acc9b81 SH |
36 | /** |
37 | * The param used to convey the current search string | |
38 | * @var string | |
39 | */ | |
40 | static $VAR_SEARCH = 'search'; | |
33d34b4b SH |
41 | |
42 | static $MAXRESULTS = 10; | |
3acc9b81 SH |
43 | /** |
44 | * The current search string | |
45 | * @var string|null | |
46 | */ | |
47 | private $search = null; | |
3acc9b81 SH |
48 | /** |
49 | * The URL for this page including required params to return to it | |
50 | * @var moodle_url | |
51 | */ | |
52 | private $url = null; | |
53 | /** | |
54 | * The results of the search | |
55 | * @var array|null | |
56 | */ | |
57 | private $results = null; | |
58 | /** | |
59 | * The total number of results available | |
60 | * @var int | |
61 | */ | |
62 | private $totalcount = null; | |
63 | /** | |
64 | * Array of capabilities required for each item in the search | |
65 | * @var array | |
66 | */ | |
67 | private $requiredcapabilities = array(); | |
68 | ||
69 | /** | |
70 | * Constructor | |
71 | * @param array $config Config options | |
72 | */ | |
73 | public function __construct(array $config=array()) { | |
74 | ||
858d100f | 75 | $this->search = optional_param($this->get_varsearch(), self::DEFAULT_SEARCH, PARAM_NOTAGS); |
3acc9b81 SH |
76 | |
77 | foreach ($config as $name=>$value) { | |
78 | $method = 'set_'.$name; | |
79 | if (method_exists($this, $method)) { | |
80 | $this->$method($value); | |
81 | } | |
82 | } | |
83 | } | |
3acc9b81 SH |
84 | /** |
85 | * The URL for this search | |
86 | * @global moodle_page $PAGE | |
87 | * @return moodle_url The URL for this page | |
88 | */ | |
89 | final public function get_url() { | |
90 | global $PAGE; | |
91 | $params = array( | |
3acc9b81 SH |
92 | $this->get_varsearch() => $this->get_search() |
93 | ); | |
94 | return ($this->url !== null)?new moodle_url($this->url, $params):new moodle_url($PAGE->url, $params); | |
95 | } | |
96 | /** | |
97 | * The current search string | |
98 | * @return string | |
99 | */ | |
100 | final public function get_search() { | |
101 | return ($this->search !== null)?$this->search:self::DEFAULT_SEARCH; | |
102 | } | |
103 | /** | |
104 | * The total number of results | |
105 | * @return int | |
106 | */ | |
33d34b4b | 107 | final public function get_count() { |
3acc9b81 SH |
108 | if ($this->totalcount === null) { |
109 | $this->search(); | |
110 | } | |
111 | return $this->totalcount; | |
112 | } | |
3acc9b81 SH |
113 | /** |
114 | * Returns an array of results from the search | |
115 | * @return array | |
116 | */ | |
117 | final public function get_results() { | |
118 | if ($this->results === null) { | |
119 | $this->search(); | |
120 | } | |
121 | return $this->results; | |
122 | } | |
3acc9b81 SH |
123 | /** |
124 | * Sets the page URL | |
125 | * @param moodle_url $url | |
126 | */ | |
127 | final public function set_url(moodle_url $url) { | |
128 | $this->url = $url; | |
129 | } | |
130 | /** | |
131 | * Invalidates the results collected so far | |
132 | */ | |
133 | final public function invalidate_results() { | |
134 | $this->results = null; | |
165b7bd9 | 135 | $this->totalcount = null; |
3acc9b81 SH |
136 | } |
137 | /** | |
138 | * Adds a required capability which all results will be checked against | |
139 | * @param string $capability | |
140 | * @param int|null $user | |
141 | */ | |
142 | final public function require_capability($capability, $user=null) { | |
143 | if (!is_int($user)) { | |
144 | $user = null; | |
145 | } | |
146 | $this->requiredcapabilities[] = array( | |
147 | 'capability' => $capability, | |
148 | 'user' => $user | |
149 | ); | |
150 | } | |
151 | /** | |
152 | * Executes the search | |
153 | * | |
154 | * @global moodle_database $DB | |
155 | * @return int The number of results | |
156 | */ | |
157 | final public function search() { | |
158 | global $DB; | |
159 | if (!is_null($this->results)) { | |
160 | return $this->results; | |
161 | } | |
3acc9b81 | 162 | |
33d34b4b SH |
163 | $this->results = array(); |
164 | $this->totalcount = 0; | |
165 | $contextlevel = $this->get_itemcontextlevel(); | |
166 | list($sql, $params) = $this->get_searchsql(); | |
d0c94a1e TL |
167 | $blocksz = 5000; |
168 | $offs = 0; | |
cb7fc350 EL |
169 | // Get total number, to avoid some incorrect iterations |
170 | $countsql = preg_replace('/ORDER BY.*/', '', $sql); | |
171 | $totalcourses = $DB->count_records_sql("SELECT COUNT(*) FROM ($countsql) sel", $params); | |
172 | // User to be checked is always the same (usually null, get it form first element) | |
173 | $firstcap = reset($this->requiredcapabilities); | |
174 | $userid = isset($firstcap['user']) ? $firstcap['user'] : null; | |
175 | // Extract caps to check, this saves us a bunch of iterations | |
176 | $requiredcaps = array(); | |
177 | foreach ($this->requiredcapabilities as $cap) { | |
178 | $requiredcaps[] = $cap['capability']; | |
179 | } | |
180 | // Iterate while we have records and haven't reached MAXRESULTS | |
181 | while ($totalcourses > $offs and $this->totalcount < self::$MAXRESULTS) { | |
182 | $resultset = $DB->get_records_sql($sql, $params, $offs, $blocksz); | |
d0c94a1e TL |
183 | foreach ($resultset as $result) { |
184 | context_instance_preload($result); | |
185 | $context = get_context_instance($contextlevel, $result->id); | |
cb7fc350 EL |
186 | if (count($requiredcaps) > 0) { |
187 | if (!has_all_capabilities($requiredcaps, $context, $userid)) { | |
188 | continue; | |
3acc9b81 SH |
189 | } |
190 | } | |
d0c94a1e TL |
191 | $this->results[$result->id] = $result; |
192 | $this->totalcount++; | |
193 | if ($this->totalcount >= self::$MAXRESULTS) { | |
cb7fc350 | 194 | break; |
d0c94a1e | 195 | } |
3acc9b81 | 196 | } |
d0c94a1e | 197 | $offs += $blocksz; |
3acc9b81 SH |
198 | } |
199 | ||
33d34b4b SH |
200 | return $this->totalcount; |
201 | } | |
3acc9b81 | 202 | |
33d34b4b SH |
203 | final public function has_more_results() { |
204 | return $this->get_count() >= self::$MAXRESULTS; | |
3acc9b81 | 205 | } |
33d34b4b | 206 | |
3acc9b81 SH |
207 | /** |
208 | * Returns an array containing the SQL for the search and the params | |
209 | * @return array | |
210 | */ | |
211 | abstract protected function get_searchsql(); | |
3acc9b81 SH |
212 | /** |
213 | * Gets the context level associated with this components items | |
214 | * @return CONTEXT_* | |
215 | */ | |
216 | abstract protected function get_itemcontextlevel(); | |
217 | /** | |
218 | * Formats the results | |
219 | */ | |
220 | abstract protected function format_results(); | |
3acc9b81 SH |
221 | /** |
222 | * Gets the string used to transfer the search string for this compontents requests | |
223 | * @return string | |
224 | */ | |
225 | abstract public function get_varsearch(); | |
226 | } | |
227 | ||
228 | /** | |
229 | * A course search component | |
230 | */ | |
231 | class restore_course_search extends restore_search_base { | |
232 | ||
3acc9b81 SH |
233 | static $VAR_SEARCH = 'search'; |
234 | ||
10618448 | 235 | protected $currentcourseid = null; |
165b7bd9 | 236 | protected $includecurrentcourse; |
10618448 SH |
237 | |
238 | /** | |
239 | * @param array $config | |
240 | * @param int $currentcouseid The current course id so it can be ignored | |
241 | */ | |
242 | public function __construct(array $config=array(), $currentcouseid = null) { | |
3acc9b81 | 243 | parent::__construct($config); |
96576a2a | 244 | $this->setup_restrictions(); |
10618448 | 245 | $this->currentcourseid = $currentcouseid; |
165b7bd9 | 246 | $this->includecurrentcourse = false; |
01d6182f | 247 | } |
96576a2a HB |
248 | /** |
249 | * Sets up any access restrictions for the courses to be displayed in the search. | |
01d6182f | 250 | * |
96576a2a HB |
251 | * This will typically call $this->require_capability(). |
252 | */ | |
253 | protected function setup_restrictions() { | |
254 | $this->require_capability('moodle/restore:restorecourse'); | |
3acc9b81 SH |
255 | } |
256 | /** | |
257 | * | |
258 | * @global moodle_database $DB | |
259 | */ | |
260 | protected function get_searchsql() { | |
261 | global $DB; | |
262 | ||
263 | list($ctxselect, $ctxjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx'); | |
3acc9b81 | 264 | $params = array( |
33d34b4b | 265 | 'fullnamesearch' => '%'.$this->get_search().'%', |
10618448 SH |
266 | 'shortnamesearch' => '%'.$this->get_search().'%', |
267 | 'siteid' => SITEID | |
3acc9b81 SH |
268 | ); |
269 | ||
270 | $select = " SELECT c.id,c.fullname,c.shortname,c.visible,c.sortorder "; | |
271 | $from = " FROM {course} c "; | |
10618448 | 272 | $where = " WHERE (".$DB->sql_like('c.fullname', ':fullnamesearch', false)." OR ".$DB->sql_like('c.shortname', ':shortnamesearch', false).") AND c.id <> :siteid"; |
3acc9b81 SH |
273 | $orderby = " ORDER BY c.sortorder"; |
274 | ||
165b7bd9 | 275 | if ($this->currentcourseid !== null && !$this->includecurrentcourse) { |
10618448 SH |
276 | $where .= " AND c.id <> :currentcourseid"; |
277 | $params['currentcourseid'] = $this->currentcourseid; | |
278 | } | |
279 | ||
3acc9b81 SH |
280 | return array($select.$ctxselect.$from.$ctxjoin.$where.$orderby, $params); |
281 | } | |
3acc9b81 SH |
282 | protected function get_itemcontextlevel() { |
283 | return CONTEXT_COURSE; | |
284 | } | |
285 | protected function format_results() {} | |
3acc9b81 SH |
286 | public function get_varsearch() { |
287 | return self::$VAR_SEARCH; | |
288 | } | |
165b7bd9 EL |
289 | public function set_include_currentcourse() { |
290 | $this->includecurrentcourse = true; | |
291 | } | |
3acc9b81 SH |
292 | } |
293 | ||
294 | /** | |
295 | * A category search component | |
296 | */ | |
297 | class restore_category_search extends restore_search_base { | |
298 | ||
3acc9b81 SH |
299 | static $VAR_SEARCH = 'catsearch'; |
300 | ||
301 | public function __construct(array $config=array()) { | |
302 | parent::__construct($config); | |
303 | $this->require_capability('moodle/course:create'); | |
304 | } | |
305 | /** | |
306 | * | |
307 | * @global moodle_database $DB | |
308 | */ | |
309 | protected function get_searchsql() { | |
310 | global $DB; | |
311 | ||
312 | list($ctxselect, $ctxjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSECAT, 'ctx'); | |
3acc9b81 | 313 | $params = array( |
33d34b4b | 314 | 'namesearch' => '%'.$this->get_search().'%', |
3acc9b81 SH |
315 | ); |
316 | ||
317 | $select = " SELECT c.id,c.name,c.visible,c.sortorder,c.description,c.descriptionformat "; | |
318 | $from = " FROM {course_categories} c "; | |
88bb11eb | 319 | $where = " WHERE ".$DB->sql_like('c.name', ':namesearch', false); |
3acc9b81 SH |
320 | $orderby = " ORDER BY c.sortorder"; |
321 | ||
322 | return array($select.$ctxselect.$from.$ctxjoin.$where.$orderby, $params); | |
323 | } | |
3acc9b81 SH |
324 | protected function get_itemcontextlevel() { |
325 | return CONTEXT_COURSECAT; | |
326 | } | |
327 | protected function format_results() {} | |
3acc9b81 SH |
328 | public function get_varsearch() { |
329 | return self::$VAR_SEARCH; | |
330 | } | |
331 | } | |
332 |