PageRenderTime 44ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/backup/util/ui/restore_ui_components.php

http://github.com/moodle/moodle
PHP | 433 lines | 181 code | 47 blank | 205 comment | 12 complexity | 7297a331a36101aecda4ae0f4da49992 MD5 | raw file
Possible License(s): MIT, AGPL-3.0, MPL-2.0-no-copyleft-exception, LGPL-3.0, GPL-3.0, Apache-2.0, LGPL-2.1, BSD-3-Clause
  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. * This file contains components used by the restore UI
  18. *
  19. * @package core_backup
  20. * @copyright 2010 Sam Hemelryk
  21. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  22. */
  23. /**
  24. * A base class that can be used to build a specific search upon
  25. *
  26. * @package core_backup
  27. * @copyright 2010 Sam Hemelryk
  28. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  29. */
  30. abstract class restore_search_base implements renderable {
  31. /**
  32. * The default values for this components params
  33. */
  34. const DEFAULT_SEARCH = '';
  35. /**
  36. * The param used to convey the current search string
  37. * @var string
  38. */
  39. static $VAR_SEARCH = 'search';
  40. /**
  41. * The current search string
  42. * @var string|null
  43. */
  44. private $search = null;
  45. /**
  46. * The URL for this page including required params to return to it
  47. * @var moodle_url
  48. */
  49. private $url = null;
  50. /**
  51. * The results of the search
  52. * @var array|null
  53. */
  54. private $results = null;
  55. /**
  56. * The total number of results available
  57. * @var int
  58. */
  59. private $totalcount = null;
  60. /**
  61. * Array of capabilities required for each item in the search
  62. * @var array
  63. */
  64. private $requiredcapabilities = array();
  65. /**
  66. * Max number of courses to return in a search.
  67. * @var int
  68. */
  69. private $maxresults = null;
  70. /**
  71. * Indicates if we have more than maxresults found.
  72. * @var boolean
  73. */
  74. private $hasmoreresults = false;
  75. /**
  76. * Constructor
  77. * @param array $config Config options
  78. */
  79. public function __construct(array $config = array()) {
  80. $this->search = optional_param($this->get_varsearch(), self::DEFAULT_SEARCH, PARAM_NOTAGS);
  81. $this->maxresults = get_config('backup', 'import_general_maxresults');
  82. foreach ($config as $name => $value) {
  83. $method = 'set_'.$name;
  84. if (method_exists($this, $method)) {
  85. $this->$method($value);
  86. }
  87. }
  88. }
  89. /**
  90. * The URL for this search
  91. * @global moodle_page $PAGE
  92. * @return moodle_url The URL for this page
  93. */
  94. final public function get_url() {
  95. global $PAGE;
  96. $params = array(
  97. $this->get_varsearch() => $this->get_search()
  98. );
  99. return ($this->url !== null) ? new moodle_url($this->url, $params) : new moodle_url($PAGE->url, $params);
  100. }
  101. /**
  102. * The current search string
  103. * @return string
  104. */
  105. final public function get_search() {
  106. return ($this->search !== null) ? $this->search : self::DEFAULT_SEARCH;
  107. }
  108. /**
  109. * The total number of results
  110. * @return int
  111. */
  112. final public function get_count() {
  113. if ($this->totalcount === null) {
  114. $this->search();
  115. }
  116. return $this->totalcount;
  117. }
  118. /**
  119. * Returns an array of results from the search
  120. * @return array
  121. */
  122. final public function get_results() {
  123. if ($this->results === null) {
  124. $this->search();
  125. }
  126. return $this->results;
  127. }
  128. /**
  129. * Sets the page URL
  130. * @param moodle_url $url
  131. */
  132. final public function set_url(moodle_url $url) {
  133. $this->url = $url;
  134. }
  135. /**
  136. * Invalidates the results collected so far
  137. */
  138. final public function invalidate_results() {
  139. $this->results = null;
  140. $this->totalcount = null;
  141. }
  142. /**
  143. * Adds a required capability which all results will be checked against
  144. * @param string $capability
  145. * @param int|null $user
  146. */
  147. final public function require_capability($capability, $user = null) {
  148. if (!is_int($user)) {
  149. $user = null;
  150. }
  151. $this->requiredcapabilities[] = array(
  152. 'capability' => $capability,
  153. 'user' => $user
  154. );
  155. }
  156. /**
  157. * Executes the search
  158. *
  159. * @global moodle_database $DB
  160. * @return int The number of results
  161. */
  162. final public function search() {
  163. global $DB;
  164. if (!is_null($this->results)) {
  165. return $this->results;
  166. }
  167. $this->results = array();
  168. $this->totalcount = 0;
  169. $contextlevel = $this->get_itemcontextlevel();
  170. list($sql, $params) = $this->get_searchsql();
  171. // Get total number, to avoid some incorrect iterations.
  172. $countsql = preg_replace('/ORDER BY.*/', '', $sql);
  173. $totalcourses = $DB->count_records_sql("SELECT COUNT(*) FROM ($countsql) sel", $params);
  174. if ($totalcourses > 0) {
  175. // User to be checked is always the same (usually null, get it from first element).
  176. $firstcap = reset($this->requiredcapabilities);
  177. $userid = isset($firstcap['user']) ? $firstcap['user'] : null;
  178. // Extract caps to check, this saves us a bunch of iterations.
  179. $requiredcaps = array();
  180. foreach ($this->requiredcapabilities as $cap) {
  181. $requiredcaps[] = $cap['capability'];
  182. }
  183. // Iterate while we have records and haven't reached $this->maxresults.
  184. $resultset = $DB->get_recordset_sql($sql, $params);
  185. foreach ($resultset as $result) {
  186. context_helper::preload_from_record($result);
  187. $classname = context_helper::get_class_for_level($contextlevel);
  188. $context = $classname::instance($result->id);
  189. if (count($requiredcaps) > 0) {
  190. if (!has_all_capabilities($requiredcaps, $context, $userid)) {
  191. continue;
  192. }
  193. }
  194. // Check if we are over the limit.
  195. if ($this->totalcount + 1 > $this->maxresults) {
  196. $this->hasmoreresults = true;
  197. break;
  198. }
  199. // If not, then continue.
  200. $this->totalcount++;
  201. $this->results[$result->id] = $result;
  202. }
  203. $resultset->close();
  204. }
  205. return $this->totalcount;
  206. }
  207. /**
  208. * Returns true if there are more search results.
  209. * @return bool
  210. */
  211. final public function has_more_results() {
  212. if ($this->results === null) {
  213. $this->search();
  214. }
  215. return $this->hasmoreresults;
  216. }
  217. /**
  218. * Returns an array containing the SQL for the search and the params
  219. * @return array
  220. */
  221. abstract protected function get_searchsql();
  222. /**
  223. * Gets the context level associated with this components items
  224. * @return CONTEXT_*
  225. */
  226. abstract protected function get_itemcontextlevel();
  227. /**
  228. * Formats the results
  229. */
  230. abstract protected function format_results();
  231. /**
  232. * Gets the string used to transfer the search string for this compontents requests
  233. * @return string
  234. */
  235. abstract public function get_varsearch();
  236. }
  237. /**
  238. * A course search component
  239. *
  240. * @package core_backup
  241. * @copyright 2010 Sam Hemelryk
  242. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  243. */
  244. class restore_course_search extends restore_search_base {
  245. /**
  246. * @var string
  247. */
  248. static $VAR_SEARCH = 'search';
  249. /**
  250. * The current course id.
  251. * @var int
  252. */
  253. protected $currentcourseid = null;
  254. /**
  255. * Determines if the current course is included in the results.
  256. * @var bool
  257. */
  258. protected $includecurrentcourse;
  259. /**
  260. * Constructor
  261. * @param array $config
  262. * @param int $currentcouseid The current course id so it can be ignored
  263. */
  264. public function __construct(array $config = array(), $currentcouseid = null) {
  265. parent::__construct($config);
  266. $this->setup_restrictions();
  267. $this->currentcourseid = $currentcouseid;
  268. $this->includecurrentcourse = false;
  269. }
  270. /**
  271. * Sets up any access restrictions for the courses to be displayed in the search.
  272. *
  273. * This will typically call $this->require_capability().
  274. */
  275. protected function setup_restrictions() {
  276. $this->require_capability('moodle/restore:restorecourse');
  277. }
  278. /**
  279. * Get the search SQL.
  280. * @global moodle_database $DB
  281. * @return array
  282. */
  283. protected function get_searchsql() {
  284. global $DB;
  285. $ctxselect = ', ' . context_helper::get_preload_record_columns_sql('ctx');
  286. $ctxjoin = "LEFT JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :contextlevel)";
  287. $params = array(
  288. 'contextlevel' => CONTEXT_COURSE,
  289. 'fullnamesearch' => '%'.$this->get_search().'%',
  290. 'shortnamesearch' => '%'.$this->get_search().'%'
  291. );
  292. $select = " SELECT c.id, c.fullname, c.shortname, c.visible, c.sortorder ";
  293. $from = " FROM {course} c ";
  294. $where = " WHERE (".$DB->sql_like('c.fullname', ':fullnamesearch', false)." OR ".
  295. $DB->sql_like('c.shortname', ':shortnamesearch', false).")";
  296. $orderby = " ORDER BY c.sortorder";
  297. if ($this->currentcourseid !== null && !$this->includecurrentcourse) {
  298. $where .= " AND c.id <> :currentcourseid";
  299. $params['currentcourseid'] = $this->currentcourseid;
  300. }
  301. return array($select.$ctxselect.$from.$ctxjoin.$where.$orderby, $params);
  302. }
  303. /**
  304. * Gets the context level for the search result items.
  305. * @return CONTEXT_|int
  306. */
  307. protected function get_itemcontextlevel() {
  308. return CONTEXT_COURSE;
  309. }
  310. /**
  311. * Formats results.
  312. */
  313. protected function format_results() {}
  314. /**
  315. * Returns the name the search variable should use
  316. * @return string
  317. */
  318. public function get_varsearch() {
  319. return self::$VAR_SEARCH;
  320. }
  321. /**
  322. * Returns true if the current course should be included in the results.
  323. */
  324. public function set_include_currentcourse() {
  325. $this->includecurrentcourse = true;
  326. }
  327. }
  328. /**
  329. * A category search component
  330. *
  331. * @package core_backup
  332. * @copyright 2010 Sam Hemelryk
  333. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  334. */
  335. class restore_category_search extends restore_search_base {
  336. /**
  337. * The search variable to use.
  338. * @var string
  339. */
  340. static $VAR_SEARCH = 'catsearch';
  341. /**
  342. * Constructor
  343. * @param array $config
  344. */
  345. public function __construct(array $config = array()) {
  346. parent::__construct($config);
  347. $this->require_capability('moodle/course:create');
  348. }
  349. /**
  350. * Returns the search SQL.
  351. * @global moodle_database $DB
  352. * @return array
  353. */
  354. protected function get_searchsql() {
  355. global $DB;
  356. $ctxselect = ', ' . context_helper::get_preload_record_columns_sql('ctx');
  357. $ctxjoin = "LEFT JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :contextlevel)";
  358. $params = array(
  359. 'contextlevel' => CONTEXT_COURSECAT,
  360. 'namesearch' => '%'.$this->get_search().'%',
  361. );
  362. $select = " SELECT c.id, c.name, c.visible, c.sortorder, c.description, c.descriptionformat ";
  363. $from = " FROM {course_categories} c ";
  364. $where = " WHERE ".$DB->sql_like('c.name', ':namesearch', false);
  365. $orderby = " ORDER BY c.sortorder";
  366. return array($select.$ctxselect.$from.$ctxjoin.$where.$orderby, $params);
  367. }
  368. /**
  369. * Returns the context level of the search results.
  370. * @return CONTEXT_COURSECAT
  371. */
  372. protected function get_itemcontextlevel() {
  373. return CONTEXT_COURSECAT;
  374. }
  375. /**
  376. * Formats the results.
  377. */
  378. protected function format_results() {}
  379. /**
  380. * Returns the name to use for the search variable.
  381. * @return string
  382. */
  383. public function get_varsearch() {
  384. return self::$VAR_SEARCH;
  385. }
  386. }