2 // This file is part of Moodle - http://moodle.org/
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.
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.
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/>.
18 * This file contains components used by the restore UI
20 * @package core_backup
21 * @copyright 2010 Sam Hemelryk
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 * A base class that can be used to build a specific search upon
28 * @package core_backup
29 * @copyright 2010 Sam Hemelryk
30 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
32 abstract class restore_search_base
implements renderable
{
35 * The default values for this components params
37 const DEFAULT_SEARCH
= '';
40 * The param used to convey the current search string
43 static $VAR_SEARCH = 'search';
46 * The current search string
49 private $search = null;
51 * The URL for this page including required params to return to it
56 * The results of the search
59 private $results = null;
61 * The total number of results available
64 private $totalcount = null;
66 * Array of capabilities required for each item in the search
69 private $requiredcapabilities = array();
71 * Max number of courses to return in a search.
74 private $maxresults = null;
76 * Indicates if we have more than maxresults found.
79 private $hasmoreresults = false;
83 * @param array $config Config options
85 public function __construct(array $config = array()) {
87 $this->search
= optional_param($this->get_varsearch(), self
::DEFAULT_SEARCH
, PARAM_NOTAGS
);
88 $this->search
= trim($this->search
);
89 $this->maxresults
= get_config('backup', 'import_general_maxresults');
91 foreach ($config as $name => $value) {
92 $method = 'set_'.$name;
93 if (method_exists($this, $method)) {
94 $this->$method($value);
100 * The URL for this search
101 * @global moodle_page $PAGE
102 * @return moodle_url The URL for this page
104 final public function get_url() {
107 $this->get_varsearch() => $this->get_search()
109 return ($this->url
!== null) ?
new moodle_url($this->url
, $params) : new moodle_url($PAGE->url
, $params);
113 * The current search string
116 final public function get_search() {
117 return ($this->search
!== null) ?
$this->search
: self
::DEFAULT_SEARCH
;
121 * The total number of results
124 final public function get_count() {
125 if ($this->totalcount
=== null) {
128 return $this->totalcount
;
132 * Returns an array of results from the search
135 final public function get_results() {
136 if ($this->results
=== null) {
139 return $this->results
;
144 * @param moodle_url $url
146 final public function set_url(moodle_url
$url) {
151 * Invalidates the results collected so far
153 final public function invalidate_results() {
154 $this->results
= null;
155 $this->totalcount
= null;
159 * Adds a required capability which all results will be checked against
160 * @param string $capability
161 * @param int|null $user
163 final public function require_capability($capability, $user = null) {
164 if (!is_int($user)) {
167 $this->requiredcapabilities
[] = array(
168 'capability' => $capability,
174 * Executes the search
176 * @global moodle_database $DB
177 * @return int The number of results
179 final public function search() {
181 if (!is_null($this->results
)) {
182 return $this->results
;
185 $this->results
= array();
186 $this->totalcount
= 0;
187 $contextlevel = $this->get_itemcontextlevel();
188 list($sql, $params) = $this->get_searchsql();
189 // Get total number, to avoid some incorrect iterations.
190 $countsql = preg_replace('/ORDER BY.*/', '', $sql);
191 $totalcourses = $DB->count_records_sql("SELECT COUNT(*) FROM ($countsql) sel", $params);
192 if ($totalcourses > 0) {
193 // User to be checked is always the same (usually null, get it from first element).
194 $firstcap = reset($this->requiredcapabilities
);
195 $userid = isset($firstcap['user']) ?
$firstcap['user'] : null;
196 // Extract caps to check, this saves us a bunch of iterations.
197 $requiredcaps = array();
198 foreach ($this->requiredcapabilities
as $cap) {
199 $requiredcaps[] = $cap['capability'];
201 // Iterate while we have records and haven't reached $this->maxresults.
202 $resultset = $DB->get_recordset_sql($sql, $params);
203 foreach ($resultset as $result) {
204 context_helper
::preload_from_record($result);
205 $classname = context_helper
::get_class_for_level($contextlevel);
206 $context = $classname::instance($result->id
);
207 if (count($requiredcaps) > 0) {
208 if (!has_all_capabilities($requiredcaps, $context, $userid)) {
212 // Check if we are over the limit.
213 if ($this->totalcount +
1 > $this->maxresults
) {
214 $this->hasmoreresults
= true;
217 // If not, then continue.
219 $this->results
[$result->id
] = $result;
224 return $this->totalcount
;
228 * Returns true if there are more search results.
231 final public function has_more_results() {
232 if ($this->results
=== null) {
235 return $this->hasmoreresults
;
239 * Returns an array containing the SQL for the search and the params
242 abstract protected function get_searchsql();
245 * Gets the context level associated with this components items
248 abstract protected function get_itemcontextlevel();
251 * Formats the results
253 abstract protected function format_results();
256 * Gets the string used to transfer the search string for this compontents requests
259 abstract public function get_varsearch();
263 * A course search component
265 * @package core_backup
266 * @copyright 2010 Sam Hemelryk
267 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
269 class restore_course_search
extends restore_search_base
{
274 static $VAR_SEARCH = 'search';
277 * The current course id.
280 protected $currentcourseid = null;
283 * Determines if the current course is included in the results.
286 protected $includecurrentcourse;
290 * @param array $config
291 * @param int $currentcouseid The current course id so it can be ignored
293 public function __construct(array $config = array(), $currentcouseid = null) {
294 parent
::__construct($config);
295 $this->setup_restrictions();
296 $this->currentcourseid
= $currentcouseid;
297 $this->includecurrentcourse
= false;
301 * Sets up any access restrictions for the courses to be displayed in the search.
303 * This will typically call $this->require_capability().
305 protected function setup_restrictions() {
306 $this->require_capability('moodle/restore:restorecourse');
310 * Get the search SQL.
311 * @global moodle_database $DB
314 protected function get_searchsql() {
317 $ctxselect = ', ' . context_helper
::get_preload_record_columns_sql('ctx');
318 $ctxjoin = "LEFT JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :contextlevel)";
320 'contextlevel' => CONTEXT_COURSE
,
321 'fullnamesearch' => '%'.$this->get_search().'%',
322 'shortnamesearch' => '%'.$this->get_search().'%'
325 $select = " SELECT c.id, c.fullname, c.shortname, c.visible, c.sortorder ";
326 $from = " FROM {course} c ";
327 $where = " WHERE (".$DB->sql_like('c.fullname', ':fullnamesearch', false)." OR ".
328 $DB->sql_like('c.shortname', ':shortnamesearch', false).")";
329 $orderby = " ORDER BY c.sortorder";
331 if ($this->currentcourseid
!== null && !$this->includecurrentcourse
) {
332 $where .= " AND c.id <> :currentcourseid";
333 $params['currentcourseid'] = $this->currentcourseid
;
336 return array($select.$ctxselect.$from.$ctxjoin.$where.$orderby, $params);
340 * Gets the context level for the search result items.
341 * @return CONTEXT_|int
343 protected function get_itemcontextlevel() {
344 return CONTEXT_COURSE
;
350 protected function format_results() {}
353 * Returns the name the search variable should use
356 public function get_varsearch() {
357 return self
::$VAR_SEARCH;
361 * Returns true if the current course should be included in the results.
363 public function set_include_currentcourse() {
364 $this->includecurrentcourse
= true;
368 * Get the current course id
372 public function get_current_course_id(): int {
373 return $this->currentcourseid
;
378 * A category search component
380 * @package core_backup
381 * @copyright 2010 Sam Hemelryk
382 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
384 class restore_category_search
extends restore_search_base
{
387 * The search variable to use.
390 static $VAR_SEARCH = 'catsearch';
394 * @param array $config
396 public function __construct(array $config = array()) {
397 parent
::__construct($config);
398 $this->require_capability('moodle/course:create');
401 * Returns the search SQL.
402 * @global moodle_database $DB
405 protected function get_searchsql() {
408 $ctxselect = ', ' . context_helper
::get_preload_record_columns_sql('ctx');
409 $ctxjoin = "LEFT JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :contextlevel)";
411 'contextlevel' => CONTEXT_COURSECAT
,
412 'namesearch' => '%'.$this->get_search().'%',
415 $select = " SELECT c.id, c.name, c.visible, c.sortorder, c.description, c.descriptionformat ";
416 $from = " FROM {course_categories} c ";
417 $where = " WHERE ".$DB->sql_like('c.name', ':namesearch', false);
418 $orderby = " ORDER BY c.sortorder";
420 return array($select.$ctxselect.$from.$ctxjoin.$where.$orderby, $params);
424 * Returns the context level of the search results.
425 * @return CONTEXT_COURSECAT
427 protected function get_itemcontextlevel() {
428 return CONTEXT_COURSECAT
;
432 * Formats the results.
434 protected function format_results() {}
437 * Returns the name to use for the search variable.
440 public function get_varsearch() {
441 return self
::$VAR_SEARCH;