PageRenderTime 53ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/pluginlib.php

http://github.com/moodle/moodle
PHP | 1690 lines | 893 code | 251 blank | 546 comment | 131 complexity | 6cbc46e95e666de47f05e5b97a2e09dd 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. * Defines classes used for plugins management
  18. *
  19. * This library provides a unified interface to various plugin types in
  20. * Moodle. It is mainly used by the plugins management admin page and the
  21. * plugins check page during the upgrade.
  22. *
  23. * @package core
  24. * @subpackage admin
  25. * @copyright 2011 David Mudrak <david@moodle.com>
  26. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  27. */
  28. defined('MOODLE_INTERNAL') || die();
  29. /**
  30. * Singleton class providing general plugins management functionality
  31. */
  32. class plugin_manager {
  33. /** the plugin is shipped with standard Moodle distribution */
  34. const PLUGIN_SOURCE_STANDARD = 'std';
  35. /** the plugin is added extension */
  36. const PLUGIN_SOURCE_EXTENSION = 'ext';
  37. /** the plugin uses neither database nor capabilities, no versions */
  38. const PLUGIN_STATUS_NODB = 'nodb';
  39. /** the plugin is up-to-date */
  40. const PLUGIN_STATUS_UPTODATE = 'uptodate';
  41. /** the plugin is about to be installed */
  42. const PLUGIN_STATUS_NEW = 'new';
  43. /** the plugin is about to be upgraded */
  44. const PLUGIN_STATUS_UPGRADE = 'upgrade';
  45. /** the standard plugin is about to be deleted */
  46. const PLUGIN_STATUS_DELETE = 'delete';
  47. /** the version at the disk is lower than the one already installed */
  48. const PLUGIN_STATUS_DOWNGRADE = 'downgrade';
  49. /** the plugin is installed but missing from disk */
  50. const PLUGIN_STATUS_MISSING = 'missing';
  51. /** @var plugin_manager holds the singleton instance */
  52. protected static $singletoninstance;
  53. /** @var array of raw plugins information */
  54. protected $pluginsinfo = null;
  55. /** @var array of raw subplugins information */
  56. protected $subpluginsinfo = null;
  57. /**
  58. * Direct initiation not allowed, use the factory method {@link self::instance()}
  59. *
  60. * @todo we might want to specify just a single plugin type to work with
  61. */
  62. protected function __construct() {
  63. $this->get_plugins(true);
  64. }
  65. /**
  66. * Sorry, this is singleton
  67. */
  68. protected function __clone() {
  69. }
  70. /**
  71. * Factory method for this class
  72. *
  73. * @return plugin_manager the singleton instance
  74. */
  75. public static function instance() {
  76. global $CFG;
  77. if (is_null(self::$singletoninstance)) {
  78. self::$singletoninstance = new self();
  79. }
  80. return self::$singletoninstance;
  81. }
  82. /**
  83. * Returns a tree of known plugins and information about them
  84. *
  85. * @param bool $disablecache force reload, cache can be used otherwise
  86. * @return array 2D array. The first keys are plugin type names (e.g. qtype);
  87. * the second keys are the plugin local name (e.g. multichoice); and
  88. * the values are the corresponding {@link plugin_information} objects.
  89. */
  90. public function get_plugins($disablecache=false) {
  91. if ($disablecache or is_null($this->pluginsinfo)) {
  92. $this->pluginsinfo = array();
  93. $plugintypes = get_plugin_types();
  94. foreach ($plugintypes as $plugintype => $plugintyperootdir) {
  95. if (in_array($plugintype, array('base', 'general'))) {
  96. throw new coding_exception('Illegal usage of reserved word for plugin type');
  97. }
  98. if (class_exists('plugintype_' . $plugintype)) {
  99. $plugintypeclass = 'plugintype_' . $plugintype;
  100. } else {
  101. $plugintypeclass = 'plugintype_general';
  102. }
  103. if (!in_array('plugin_information', class_implements($plugintypeclass))) {
  104. throw new coding_exception('Class ' . $plugintypeclass . ' must implement plugin_information');
  105. }
  106. $plugins = call_user_func(array($plugintypeclass, 'get_plugins'), $plugintype, $plugintyperootdir, $plugintypeclass);
  107. $this->pluginsinfo[$plugintype] = $plugins;
  108. }
  109. }
  110. return $this->pluginsinfo;
  111. }
  112. /**
  113. * Returns list of plugins that define their subplugins and the information
  114. * about them from the db/subplugins.php file.
  115. *
  116. * At the moment, only activity modules can define subplugins.
  117. *
  118. * @param bool $disablecache force reload, cache can be used otherwise
  119. * @return array with keys like 'mod_quiz', and values the data from the
  120. * corresponding db/subplugins.php file.
  121. */
  122. public function get_subplugins($disablecache=false) {
  123. if ($disablecache or is_null($this->subpluginsinfo)) {
  124. $this->subpluginsinfo = array();
  125. $mods = get_plugin_list('mod');
  126. foreach ($mods as $mod => $moddir) {
  127. $modsubplugins = array();
  128. if (file_exists($moddir . '/db/subplugins.php')) {
  129. include($moddir . '/db/subplugins.php');
  130. foreach ($subplugins as $subplugintype => $subplugintyperootdir) {
  131. $subplugin = new stdClass();
  132. $subplugin->type = $subplugintype;
  133. $subplugin->typerootdir = $subplugintyperootdir;
  134. $modsubplugins[$subplugintype] = $subplugin;
  135. }
  136. $this->subpluginsinfo['mod_' . $mod] = $modsubplugins;
  137. }
  138. }
  139. }
  140. return $this->subpluginsinfo;
  141. }
  142. /**
  143. * Returns the name of the plugin that defines the given subplugin type
  144. *
  145. * If the given subplugin type is not actually a subplugin, returns false.
  146. *
  147. * @param string $subplugintype the name of subplugin type, eg. workshopform or quiz
  148. * @return false|string the name of the parent plugin, eg. mod_workshop
  149. */
  150. public function get_parent_of_subplugin($subplugintype) {
  151. $parent = false;
  152. foreach ($this->get_subplugins() as $pluginname => $subplugintypes) {
  153. if (isset($subplugintypes[$subplugintype])) {
  154. $parent = $pluginname;
  155. break;
  156. }
  157. }
  158. return $parent;
  159. }
  160. /**
  161. * Returns a localized name of a given plugin
  162. *
  163. * @param string $plugin name of the plugin, eg mod_workshop or auth_ldap
  164. * @return string
  165. */
  166. public function plugin_name($plugin) {
  167. list($type, $name) = normalize_component($plugin);
  168. return $this->pluginsinfo[$type][$name]->displayname;
  169. }
  170. /**
  171. * Returns a localized name of a plugin type in plural form
  172. *
  173. * Most plugin types define their names in core_plugin lang file. In case of subplugins,
  174. * we try to ask the parent plugin for the name. In the worst case, we will return
  175. * the value of the passed $type parameter.
  176. *
  177. * @param string $type the type of the plugin, e.g. mod or workshopform
  178. * @return string
  179. */
  180. public function plugintype_name_plural($type) {
  181. if (get_string_manager()->string_exists('type_' . $type . '_plural', 'core_plugin')) {
  182. // for most plugin types, their names are defined in core_plugin lang file
  183. return get_string('type_' . $type . '_plural', 'core_plugin');
  184. } else if ($parent = $this->get_parent_of_subplugin($type)) {
  185. // if this is a subplugin, try to ask the parent plugin for the name
  186. if (get_string_manager()->string_exists('subplugintype_' . $type . '_plural', $parent)) {
  187. return $this->plugin_name($parent) . ' / ' . get_string('subplugintype_' . $type . '_plural', $parent);
  188. } else {
  189. return $this->plugin_name($parent) . ' / ' . $type;
  190. }
  191. } else {
  192. return $type;
  193. }
  194. }
  195. /**
  196. * @param string $component frankenstyle component name.
  197. * @return plugin_information|null the corresponding plugin information.
  198. */
  199. public function get_plugin_info($component) {
  200. list($type, $name) = normalize_component($component);
  201. $plugins = $this->get_plugins();
  202. if (isset($plugins[$type][$name])) {
  203. return $plugins[$type][$name];
  204. } else {
  205. return null;
  206. }
  207. }
  208. /**
  209. * Get a list of any other pluings that require this one.
  210. * @param string $component frankenstyle component name.
  211. * @return array of frankensyle component names that require this one.
  212. */
  213. public function other_plugins_that_require($component) {
  214. $others = array();
  215. foreach ($this->get_plugins() as $type => $plugins) {
  216. foreach ($plugins as $plugin) {
  217. $required = $plugin->get_other_required_plugins();
  218. if (isset($required[$component])) {
  219. $others[] = $plugin->component;
  220. }
  221. }
  222. }
  223. return $others;
  224. }
  225. /**
  226. * Check a dependencies list against the list of installed plugins.
  227. * @param array $dependencies compenent name to required version or ANY_VERSION.
  228. * @return bool true if all the dependencies are satisfied.
  229. */
  230. public function are_dependencies_satisfied($dependencies) {
  231. foreach ($dependencies as $component => $requiredversion) {
  232. $otherplugin = $this->get_plugin_info($component);
  233. if (is_null($otherplugin)) {
  234. return false;
  235. }
  236. if ($requiredversion != ANY_VERSION and $otherplugin->versiondisk < $requiredversion) {
  237. return false;
  238. }
  239. }
  240. return true;
  241. }
  242. /**
  243. * Checks all dependencies for all installed plugins. Used by install and upgrade.
  244. * @param int $moodleversion the version from version.php.
  245. * @return bool true if all the dependencies are satisfied for all plugins.
  246. */
  247. public function all_plugins_ok($moodleversion) {
  248. foreach ($this->get_plugins() as $type => $plugins) {
  249. foreach ($plugins as $plugin) {
  250. if (!empty($plugin->versionrequires) && $plugin->versionrequires > $moodleversion) {
  251. return false;
  252. }
  253. if (!$this->are_dependencies_satisfied($plugin->get_other_required_plugins())) {
  254. return false;
  255. }
  256. }
  257. }
  258. return true;
  259. }
  260. /**
  261. * Defines a list of all plugins that were originally shipped in the standard Moodle distribution,
  262. * but are not anymore and are deleted during upgrades.
  263. *
  264. * The main purpose of this list is to hide missing plugins during upgrade.
  265. *
  266. * @param string $type plugin type
  267. * @param string $name plugin name
  268. * @return bool
  269. */
  270. public static function is_deleted_standard_plugin($type, $name) {
  271. static $plugins = array(
  272. // do not add 1.9-2.2 plugin removals here
  273. );
  274. if (!isset($plugins[$type])) {
  275. return false;
  276. }
  277. return in_array($name, $plugins[$type]);
  278. }
  279. /**
  280. * Defines a white list of all plugins shipped in the standard Moodle distribution
  281. *
  282. * @param string $type
  283. * @return false|array array of standard plugins or false if the type is unknown
  284. */
  285. public static function standard_plugins_list($type) {
  286. static $standard_plugins = array(
  287. 'assignment' => array(
  288. 'offline', 'online', 'upload', 'uploadsingle'
  289. ),
  290. 'auth' => array(
  291. 'cas', 'db', 'email', 'fc', 'imap', 'ldap', 'manual', 'mnet',
  292. 'nntp', 'nologin', 'none', 'pam', 'pop3', 'radius',
  293. 'shibboleth', 'webservice'
  294. ),
  295. 'block' => array(
  296. 'activity_modules', 'admin_bookmarks', 'blog_menu',
  297. 'blog_recent', 'blog_tags', 'calendar_month',
  298. 'calendar_upcoming', 'comments', 'community',
  299. 'completionstatus', 'course_list', 'course_overview',
  300. 'course_summary', 'feedback', 'glossary_random', 'html',
  301. 'login', 'mentees', 'messages', 'mnet_hosts', 'myprofile',
  302. 'navigation', 'news_items', 'online_users', 'participants',
  303. 'private_files', 'quiz_results', 'recent_activity',
  304. 'rss_client', 'search_forums', 'section_links',
  305. 'selfcompletion', 'settings', 'site_main_menu',
  306. 'social_activities', 'tag_flickr', 'tag_youtube', 'tags'
  307. ),
  308. 'coursereport' => array(
  309. //deprecated!
  310. ),
  311. 'datafield' => array(
  312. 'checkbox', 'date', 'file', 'latlong', 'menu', 'multimenu',
  313. 'number', 'picture', 'radiobutton', 'text', 'textarea', 'url'
  314. ),
  315. 'datapreset' => array(
  316. 'imagegallery'
  317. ),
  318. 'editor' => array(
  319. 'textarea', 'tinymce'
  320. ),
  321. 'enrol' => array(
  322. 'authorize', 'category', 'cohort', 'database', 'flatfile',
  323. 'guest', 'imsenterprise', 'ldap', 'manual', 'meta', 'mnet',
  324. 'paypal', 'self'
  325. ),
  326. 'filter' => array(
  327. 'activitynames', 'algebra', 'censor', 'emailprotect',
  328. 'emoticon', 'mediaplugin', 'multilang', 'tex', 'tidy',
  329. 'urltolink', 'data', 'glossary'
  330. ),
  331. 'format' => array(
  332. 'scorm', 'social', 'topics', 'weeks'
  333. ),
  334. 'gradeexport' => array(
  335. 'ods', 'txt', 'xls', 'xml'
  336. ),
  337. 'gradeimport' => array(
  338. 'csv', 'xml'
  339. ),
  340. 'gradereport' => array(
  341. 'grader', 'outcomes', 'overview', 'user'
  342. ),
  343. 'gradingform' => array(
  344. 'rubric'
  345. ),
  346. 'local' => array(
  347. ),
  348. 'message' => array(
  349. 'email', 'jabber', 'popup'
  350. ),
  351. 'mnetservice' => array(
  352. 'enrol'
  353. ),
  354. 'mod' => array(
  355. 'assignment', 'chat', 'choice', 'data', 'feedback', 'folder',
  356. 'forum', 'glossary', 'imscp', 'label', 'lesson', 'lti', 'page',
  357. 'quiz', 'resource', 'scorm', 'survey', 'url', 'wiki', 'workshop'
  358. ),
  359. 'plagiarism' => array(
  360. ),
  361. 'portfolio' => array(
  362. 'boxnet', 'download', 'flickr', 'googledocs', 'mahara', 'picasa'
  363. ),
  364. 'profilefield' => array(
  365. 'checkbox', 'datetime', 'menu', 'text', 'textarea'
  366. ),
  367. 'qbehaviour' => array(
  368. 'adaptive', 'adaptivenopenalty', 'deferredcbm',
  369. 'deferredfeedback', 'immediatecbm', 'immediatefeedback',
  370. 'informationitem', 'interactive', 'interactivecountback',
  371. 'manualgraded', 'missing'
  372. ),
  373. 'qformat' => array(
  374. 'aiken', 'blackboard', 'blackboard_six', 'examview', 'gift',
  375. 'learnwise', 'missingword', 'multianswer', 'webct',
  376. 'xhtml', 'xml'
  377. ),
  378. 'qtype' => array(
  379. 'calculated', 'calculatedmulti', 'calculatedsimple',
  380. 'description', 'essay', 'match', 'missingtype', 'multianswer',
  381. 'multichoice', 'numerical', 'random', 'randomsamatch',
  382. 'shortanswer', 'truefalse'
  383. ),
  384. 'quiz' => array(
  385. 'grading', 'overview', 'responses', 'statistics'
  386. ),
  387. 'quizaccess' => array(
  388. 'delaybetweenattempts', 'ipaddress', 'numattempts', 'openclosedate',
  389. 'password', 'safebrowser', 'securewindow', 'timelimit'
  390. ),
  391. 'report' => array(
  392. 'backups', 'completion', 'configlog', 'courseoverview',
  393. 'log', 'loglive', 'outline', 'participation', 'progress', 'questioninstances', 'security', 'stats'
  394. ),
  395. 'repository' => array(
  396. 'alfresco', 'boxnet', 'coursefiles', 'dropbox', 'filesystem',
  397. 'flickr', 'flickr_public', 'googledocs', 'local', 'merlot',
  398. 'picasa', 'recent', 's3', 'upload', 'url', 'user', 'webdav',
  399. 'wikimedia', 'youtube'
  400. ),
  401. 'scormreport' => array(
  402. 'basic',
  403. 'interactions'
  404. ),
  405. 'theme' => array(
  406. 'afterburner', 'anomaly', 'arialist', 'base', 'binarius',
  407. 'boxxie', 'brick', 'canvas', 'formal_white', 'formfactor',
  408. 'fusion', 'leatherbound', 'magazine', 'mymobile', 'nimble',
  409. 'nonzero', 'overlay', 'serenity', 'sky_high', 'splash',
  410. 'standard', 'standardold'
  411. ),
  412. 'tool' => array(
  413. 'bloglevelupgrade', 'capability', 'customlang', 'dbtransfer', 'generator',
  414. 'health', 'innodb', 'langimport', 'multilangupgrade', 'profiling',
  415. 'qeupgradehelper', 'replace', 'spamcleaner', 'timezoneimport', 'unittest',
  416. 'uploaduser', 'unsuproles', 'xmldb'
  417. ),
  418. 'webservice' => array(
  419. 'amf', 'rest', 'soap', 'xmlrpc'
  420. ),
  421. 'workshopallocation' => array(
  422. 'manual', 'random'
  423. ),
  424. 'workshopeval' => array(
  425. 'best'
  426. ),
  427. 'workshopform' => array(
  428. 'accumulative', 'comments', 'numerrors', 'rubric'
  429. )
  430. );
  431. if (isset($standard_plugins[$type])) {
  432. return $standard_plugins[$type];
  433. } else {
  434. return false;
  435. }
  436. }
  437. }
  438. /**
  439. * Interface for making information about a plugin available.
  440. *
  441. * Note that most of the useful information is made available in pubic fields,
  442. * which cannot be documented in this interface. See the field definitions on
  443. * {@link plugintype_base} to find out what information is available.
  444. *
  445. * @property-read string component the component name, type_name
  446. */
  447. interface plugin_information {
  448. /**
  449. * Gathers and returns the information about all plugins of the given type
  450. *
  451. * Passing the parameter $typeclass allows us to reach the same effect as with the
  452. * late binding in PHP 5.3. Once PHP 5.3 is required, we can refactor this to use
  453. * {@example $plugin = new static();} instead of {@example $plugin = new $typeclass()}
  454. *
  455. * @param string $type the name of the plugintype, eg. mod, auth or workshopform
  456. * @param string $typerootdir full path to the location of the plugin dir
  457. * @param string $typeclass the name of the actually called class
  458. * @return array of plugintype classes, indexed by the plugin name
  459. */
  460. public static function get_plugins($type, $typerootdir, $typeclass);
  461. /**
  462. * Sets $displayname property to a localized name of the plugin
  463. *
  464. * @return void
  465. */
  466. public function init_display_name();
  467. /**
  468. * Sets $versiondisk property to a numerical value representing the
  469. * version of the plugin's source code.
  470. *
  471. * If the value is null after calling this method, either the plugin
  472. * does not use versioning (typically does not have any database
  473. * data) or is missing from disk.
  474. *
  475. * @return void
  476. */
  477. public function load_disk_version();
  478. /**
  479. * Sets $versiondb property to a numerical value representing the
  480. * currently installed version of the plugin.
  481. *
  482. * If the value is null after calling this method, either the plugin
  483. * does not use versioning (typically does not have any database
  484. * data) or has not been installed yet.
  485. *
  486. * @return void
  487. */
  488. public function load_db_version();
  489. /**
  490. * Sets $versionrequires property to a numerical value representing
  491. * the version of Moodle core that this plugin requires.
  492. *
  493. * @return void
  494. */
  495. public function load_required_main_version();
  496. /**
  497. * Sets $source property to one of plugin_manager::PLUGIN_SOURCE_xxx
  498. * constants.
  499. *
  500. * If the property's value is null after calling this method, then
  501. * the type of the plugin has not been recognized and you should throw
  502. * an exception.
  503. *
  504. * @return void
  505. */
  506. public function init_is_standard();
  507. /**
  508. * Returns true if the plugin is shipped with the official distribution
  509. * of the current Moodle version, false otherwise.
  510. *
  511. * @return bool
  512. */
  513. public function is_standard();
  514. /**
  515. * Returns the status of the plugin
  516. *
  517. * @return string one of plugin_manager::PLUGIN_STATUS_xxx constants
  518. */
  519. public function get_status();
  520. /**
  521. * Get the list of other plugins that this plugin requires ot be installed.
  522. * @return array with keys the frankenstyle plugin name, and values either
  523. * a version string (like '2011101700') or the constant ANY_VERSION.
  524. */
  525. public function get_other_required_plugins();
  526. /**
  527. * Returns the information about plugin availability
  528. *
  529. * True means that the plugin is enabled. False means that the plugin is
  530. * disabled. Null means that the information is not available, or the
  531. * plugin does not support configurable availability or the availability
  532. * can not be changed.
  533. *
  534. * @return null|bool
  535. */
  536. public function is_enabled();
  537. /**
  538. * Returns the URL of the plugin settings screen
  539. *
  540. * Null value means that the plugin either does not have the settings screen
  541. * or its location is not available via this library.
  542. *
  543. * @return null|moodle_url
  544. */
  545. public function get_settings_url();
  546. /**
  547. * Returns the URL of the screen where this plugin can be uninstalled
  548. *
  549. * Visiting that URL must be safe, that is a manual confirmation is needed
  550. * for actual uninstallation of the plugin. Null value means that the
  551. * plugin either does not support uninstallation, or does not require any
  552. * database cleanup or the location of the screen is not available via this
  553. * library.
  554. *
  555. * @return null|moodle_url
  556. */
  557. public function get_uninstall_url();
  558. /**
  559. * Returns relative directory of the plugin with heading '/'
  560. *
  561. * @example /mod/workshop
  562. * @return string
  563. */
  564. public function get_dir();
  565. /**
  566. * Return the full path name of a file within the plugin.
  567. * No check is made to see if the file exists.
  568. * @param string $relativepath e.g. 'version.php'.
  569. * @return string e.g. $CFG->dirroot . '/mod/quiz/version.php'.
  570. */
  571. public function full_path($relativepath);
  572. }
  573. /**
  574. * Defines public properties that all plugintype classes must have
  575. * and provides default implementation of required methods.
  576. *
  577. * @property-read string component the component name, type_name
  578. */
  579. abstract class plugintype_base {
  580. /** @var string the plugintype name, eg. mod, auth or workshopform */
  581. public $type;
  582. /** @var string full path to the location of all the plugins of this type */
  583. public $typerootdir;
  584. /** @var string the plugin name, eg. assignment, ldap */
  585. public $name;
  586. /** @var string the localized plugin name */
  587. public $displayname;
  588. /** @var string the plugin source, one of plugin_manager::PLUGIN_SOURCE_xxx constants */
  589. public $source;
  590. /** @var fullpath to the location of this plugin */
  591. public $rootdir;
  592. /** @var int|string the version of the plugin's source code */
  593. public $versiondisk;
  594. /** @var int|string the version of the installed plugin */
  595. public $versiondb;
  596. /** @var int|float|string required version of Moodle core */
  597. public $versionrequires;
  598. /** @var array other plugins that this one depends on.
  599. * Lazy-loaded by {@link get_other_required_plugins()} */
  600. public $dependencies = null;
  601. /** @var int number of instances of the plugin - not supported yet */
  602. public $instances;
  603. /** @var int order of the plugin among other plugins of the same type - not supported yet */
  604. public $sortorder;
  605. /**
  606. * @see plugin_information::get_plugins()
  607. */
  608. public static function get_plugins($type, $typerootdir, $typeclass) {
  609. // get the information about plugins at the disk
  610. $plugins = get_plugin_list($type);
  611. $ondisk = array();
  612. foreach ($plugins as $pluginname => $pluginrootdir) {
  613. $plugin = new $typeclass();
  614. $plugin->type = $type;
  615. $plugin->typerootdir = $typerootdir;
  616. $plugin->name = $pluginname;
  617. $plugin->rootdir = $pluginrootdir;
  618. $plugin->init_display_name();
  619. $plugin->load_disk_version();
  620. $plugin->load_db_version();
  621. $plugin->load_required_main_version();
  622. $plugin->init_is_standard();
  623. $ondisk[$pluginname] = $plugin;
  624. }
  625. return $ondisk;
  626. }
  627. /**
  628. * @see plugin_information::init_display_name()
  629. */
  630. public function init_display_name() {
  631. if (!get_string_manager()->string_exists('pluginname', $this->component)) {
  632. $this->displayname = '[pluginname,' . $this->component . ']';
  633. } else {
  634. $this->displayname = get_string('pluginname', $this->component);
  635. }
  636. }
  637. /**
  638. * Magic method getter, redirects to read only values.
  639. * @param string $name
  640. * @return mixed
  641. */
  642. public function __get($name) {
  643. switch ($name) {
  644. case 'component': return $this->type . '_' . $this->name;
  645. default:
  646. debugging('Invalid plugin property accessed! '.$name);
  647. return null;
  648. }
  649. }
  650. /**
  651. * @see plugin_information::full_path()
  652. */
  653. public function full_path($relativepath) {
  654. if (empty($this->rootdir)) {
  655. return '';
  656. }
  657. return $this->rootdir . '/' . $relativepath;
  658. }
  659. /**
  660. * Load the data from version.php.
  661. * @return object the data object defined in version.php.
  662. */
  663. protected function load_version_php() {
  664. $versionfile = $this->full_path('version.php');
  665. $plugin = new stdClass();
  666. if (is_readable($versionfile)) {
  667. include($versionfile);
  668. }
  669. return $plugin;
  670. }
  671. /**
  672. * @see plugin_information::load_disk_version()
  673. */
  674. public function load_disk_version() {
  675. $plugin = $this->load_version_php();
  676. if (isset($plugin->version)) {
  677. $this->versiondisk = $plugin->version;
  678. }
  679. }
  680. /**
  681. * @see plugin_information::load_required_main_version()
  682. */
  683. public function load_required_main_version() {
  684. $plugin = $this->load_version_php();
  685. if (isset($plugin->requires)) {
  686. $this->versionrequires = $plugin->requires;
  687. }
  688. }
  689. /**
  690. * Initialise {@link $dependencies} to the list of other plugins (in any)
  691. * that this one requires to be installed.
  692. */
  693. protected function load_other_required_plugins() {
  694. $plugin = $this->load_version_php();
  695. if (!empty($plugin->dependencies)) {
  696. $this->dependencies = $plugin->dependencies;
  697. } else {
  698. $this->dependencies = array(); // By default, no dependencies.
  699. }
  700. }
  701. /**
  702. * @see plugin_information::get_other_required_plugins()
  703. */
  704. public function get_other_required_plugins() {
  705. if (is_null($this->dependencies)) {
  706. $this->load_other_required_plugins();
  707. }
  708. return $this->dependencies;
  709. }
  710. /**
  711. * @see plugin_information::load_db_version()
  712. */
  713. public function load_db_version() {
  714. if ($ver = self::get_version_from_config_plugins($this->component)) {
  715. $this->versiondb = $ver;
  716. }
  717. }
  718. /**
  719. * @see plugin_information::init_is_standard()
  720. */
  721. public function init_is_standard() {
  722. $standard = plugin_manager::standard_plugins_list($this->type);
  723. if ($standard !== false) {
  724. $standard = array_flip($standard);
  725. if (isset($standard[$this->name])) {
  726. $this->source = plugin_manager::PLUGIN_SOURCE_STANDARD;
  727. } else if (!is_null($this->versiondb) and is_null($this->versiondisk)
  728. and plugin_manager::is_deleted_standard_plugin($this->type, $this->name)) {
  729. $this->source = plugin_manager::PLUGIN_SOURCE_STANDARD; // to be deleted
  730. } else {
  731. $this->source = plugin_manager::PLUGIN_SOURCE_EXTENSION;
  732. }
  733. }
  734. }
  735. /**
  736. * @see plugin_information::is_standard()
  737. */
  738. public function is_standard() {
  739. return $this->source === plugin_manager::PLUGIN_SOURCE_STANDARD;
  740. }
  741. /**
  742. * @see plugin_information::get_status()
  743. */
  744. public function get_status() {
  745. if (is_null($this->versiondb) and is_null($this->versiondisk)) {
  746. return plugin_manager::PLUGIN_STATUS_NODB;
  747. } else if (is_null($this->versiondb) and !is_null($this->versiondisk)) {
  748. return plugin_manager::PLUGIN_STATUS_NEW;
  749. } else if (!is_null($this->versiondb) and is_null($this->versiondisk)) {
  750. if (plugin_manager::is_deleted_standard_plugin($this->type, $this->name)) {
  751. return plugin_manager::PLUGIN_STATUS_DELETE;
  752. } else {
  753. return plugin_manager::PLUGIN_STATUS_MISSING;
  754. }
  755. } else if ((string)$this->versiondb === (string)$this->versiondisk) {
  756. return plugin_manager::PLUGIN_STATUS_UPTODATE;
  757. } else if ($this->versiondb < $this->versiondisk) {
  758. return plugin_manager::PLUGIN_STATUS_UPGRADE;
  759. } else if ($this->versiondb > $this->versiondisk) {
  760. return plugin_manager::PLUGIN_STATUS_DOWNGRADE;
  761. } else {
  762. // $version = pi(); and similar funny jokes - hopefully Donald E. Knuth will never contribute to Moodle ;-)
  763. throw new coding_exception('Unable to determine plugin state, check the plugin versions');
  764. }
  765. }
  766. /**
  767. * @see plugin_information::is_enabled()
  768. */
  769. public function is_enabled() {
  770. return null;
  771. }
  772. /**
  773. * @see plugin_information::get_settings_url()
  774. */
  775. public function get_settings_url() {
  776. return null;
  777. }
  778. /**
  779. * @see plugin_information::get_uninstall_url()
  780. */
  781. public function get_uninstall_url() {
  782. return null;
  783. }
  784. /**
  785. * @see plugin_information::get_dir()
  786. */
  787. public function get_dir() {
  788. global $CFG;
  789. return substr($this->rootdir, strlen($CFG->dirroot));
  790. }
  791. /**
  792. * Provides access to plugin versions from {config_plugins}
  793. *
  794. * @param string $plugin plugin name
  795. * @param double $disablecache optional, defaults to false
  796. * @return int|false the stored value or false if not found
  797. */
  798. protected function get_version_from_config_plugins($plugin, $disablecache=false) {
  799. global $DB;
  800. static $pluginversions = null;
  801. if (is_null($pluginversions) or $disablecache) {
  802. try {
  803. $pluginversions = $DB->get_records_menu('config_plugins', array('name' => 'version'), 'plugin', 'plugin,value');
  804. } catch (dml_exception $e) {
  805. // before install
  806. $pluginversions = array();
  807. }
  808. }
  809. if (!array_key_exists($plugin, $pluginversions)) {
  810. return false;
  811. }
  812. return $pluginversions[$plugin];
  813. }
  814. }
  815. /**
  816. * General class for all plugin types that do not have their own class
  817. */
  818. class plugintype_general extends plugintype_base implements plugin_information {
  819. }
  820. /**
  821. * Class for page side blocks
  822. */
  823. class plugintype_block extends plugintype_base implements plugin_information {
  824. /**
  825. * @see plugin_information::get_plugins()
  826. */
  827. public static function get_plugins($type, $typerootdir, $typeclass) {
  828. // get the information about blocks at the disk
  829. $blocks = parent::get_plugins($type, $typerootdir, $typeclass);
  830. // add blocks missing from disk
  831. $blocksinfo = self::get_blocks_info();
  832. foreach ($blocksinfo as $blockname => $blockinfo) {
  833. if (isset($blocks[$blockname])) {
  834. continue;
  835. }
  836. $plugin = new $typeclass();
  837. $plugin->type = $type;
  838. $plugin->typerootdir = $typerootdir;
  839. $plugin->name = $blockname;
  840. $plugin->rootdir = null;
  841. $plugin->displayname = $blockname;
  842. $plugin->versiondb = $blockinfo->version;
  843. $plugin->init_is_standard();
  844. $blocks[$blockname] = $plugin;
  845. }
  846. return $blocks;
  847. }
  848. /**
  849. * @see plugin_information::init_display_name()
  850. */
  851. public function init_display_name() {
  852. if (get_string_manager()->string_exists('pluginname', 'block_' . $this->name)) {
  853. $this->displayname = get_string('pluginname', 'block_' . $this->name);
  854. } else if (($block = block_instance($this->name)) !== false) {
  855. $this->displayname = $block->get_title();
  856. } else {
  857. parent::init_display_name();
  858. }
  859. }
  860. /**
  861. * @see plugin_information::load_db_version()
  862. */
  863. public function load_db_version() {
  864. global $DB;
  865. $blocksinfo = self::get_blocks_info();
  866. if (isset($blocksinfo[$this->name]->version)) {
  867. $this->versiondb = $blocksinfo[$this->name]->version;
  868. }
  869. }
  870. /**
  871. * @see plugin_information::is_enabled()
  872. */
  873. public function is_enabled() {
  874. $blocksinfo = self::get_blocks_info();
  875. if (isset($blocksinfo[$this->name]->visible)) {
  876. if ($blocksinfo[$this->name]->visible) {
  877. return true;
  878. } else {
  879. return false;
  880. }
  881. } else {
  882. return parent::is_enabled();
  883. }
  884. }
  885. /**
  886. * @see plugin_information::get_settings_url()
  887. */
  888. public function get_settings_url() {
  889. if (($block = block_instance($this->name)) === false) {
  890. return parent::get_settings_url();
  891. } else if ($block->has_config()) {
  892. if (file_exists($this->full_path('settings.php'))) {
  893. return new moodle_url('/admin/settings.php', array('section' => 'blocksetting' . $this->name));
  894. } else {
  895. $blocksinfo = self::get_blocks_info();
  896. return new moodle_url('/admin/block.php', array('block' => $blocksinfo[$this->name]->id));
  897. }
  898. } else {
  899. return parent::get_settings_url();
  900. }
  901. }
  902. /**
  903. * @see plugin_information::get_uninstall_url()
  904. */
  905. public function get_uninstall_url() {
  906. $blocksinfo = self::get_blocks_info();
  907. return new moodle_url('/admin/blocks.php', array('delete' => $blocksinfo[$this->name]->id, 'sesskey' => sesskey()));
  908. }
  909. /**
  910. * Provides access to the records in {block} table
  911. *
  912. * @param bool $disablecache do not use internal static cache
  913. * @return array array of stdClasses
  914. */
  915. protected static function get_blocks_info($disablecache=false) {
  916. global $DB;
  917. static $blocksinfocache = null;
  918. if (is_null($blocksinfocache) or $disablecache) {
  919. try {
  920. $blocksinfocache = $DB->get_records('block', null, 'name', 'name,id,version,visible');
  921. } catch (dml_exception $e) {
  922. // before install
  923. $blocksinfocache = array();
  924. }
  925. }
  926. return $blocksinfocache;
  927. }
  928. }
  929. /**
  930. * Class for text filters
  931. */
  932. class plugintype_filter extends plugintype_base implements plugin_information {
  933. /**
  934. * @see plugin_information::get_plugins()
  935. */
  936. public static function get_plugins($type, $typerootdir, $typeclass) {
  937. global $CFG, $DB;
  938. $filters = array();
  939. // get the list of filters from both /filter and /mod location
  940. $installed = filter_get_all_installed();
  941. foreach ($installed as $filterlegacyname => $displayname) {
  942. $plugin = new $typeclass();
  943. $plugin->type = $type;
  944. $plugin->typerootdir = $typerootdir;
  945. $plugin->name = self::normalize_legacy_name($filterlegacyname);
  946. $plugin->rootdir = $CFG->dirroot . '/' . $filterlegacyname;
  947. $plugin->displayname = $displayname;
  948. $plugin->load_disk_version();
  949. $plugin->load_db_version();
  950. $plugin->load_required_main_version();
  951. $plugin->init_is_standard();
  952. $filters[$plugin->name] = $plugin;
  953. }
  954. $globalstates = self::get_global_states();
  955. if ($DB->get_manager()->table_exists('filter_active')) {
  956. // if we're upgrading from 1.9, the table does not exist yet
  957. // if it does, make sure that all installed filters are registered
  958. $needsreload = false;
  959. foreach (array_keys($installed) as $filterlegacyname) {
  960. if (!isset($globalstates[self::normalize_legacy_name($filterlegacyname)])) {
  961. filter_set_global_state($filterlegacyname, TEXTFILTER_DISABLED);
  962. $needsreload = true;
  963. }
  964. }
  965. if ($needsreload) {
  966. $globalstates = self::get_global_states(true);
  967. }
  968. }
  969. // make sure that all registered filters are installed, just in case
  970. foreach ($globalstates as $name => $info) {
  971. if (!isset($filters[$name])) {
  972. // oops, there is a record in filter_active but the filter is not installed
  973. $plugin = new $typeclass();
  974. $plugin->type = $type;
  975. $plugin->typerootdir = $typerootdir;
  976. $plugin->name = $name;
  977. $plugin->rootdir = $CFG->dirroot . '/' . $info->legacyname;
  978. $plugin->displayname = $info->legacyname;
  979. $plugin->load_db_version();
  980. if (is_null($plugin->versiondb)) {
  981. // this is a hack to stimulate 'Missing from disk' error
  982. // because $plugin->versiondisk will be null !== false
  983. $plugin->versiondb = false;
  984. }
  985. $filters[$plugin->name] = $plugin;
  986. }
  987. }
  988. return $filters;
  989. }
  990. /**
  991. * @see plugin_information::init_display_name()
  992. */
  993. public function init_display_name() {
  994. // do nothing, the name is set in self::get_plugins()
  995. }
  996. /**
  997. * @see plugintype_base::load_version_php().
  998. */
  999. protected function load_version_php() {
  1000. if (strpos($this->name, 'mod_') === 0) {
  1001. // filters bundled with modules do not have a version.php and so
  1002. // do not provide their own versioning information.
  1003. return new stdClass();
  1004. }
  1005. return parent::load_version_php();
  1006. }
  1007. /**
  1008. * @see plugin_information::is_enabled()
  1009. */
  1010. public function is_enabled() {
  1011. $globalstates = self::get_global_states();
  1012. foreach ($globalstates as $filterlegacyname => $info) {
  1013. $name = self::normalize_legacy_name($filterlegacyname);
  1014. if ($name === $this->name) {
  1015. if ($info->active == TEXTFILTER_DISABLED) {
  1016. return false;
  1017. } else {
  1018. // it may be 'On' or 'Off, but available'
  1019. return null;
  1020. }
  1021. }
  1022. }
  1023. return null;
  1024. }
  1025. /**
  1026. * @see plugin_information::get_settings_url()
  1027. */
  1028. public function get_settings_url() {
  1029. $globalstates = self::get_global_states();
  1030. $legacyname = $globalstates[$this->name]->legacyname;
  1031. if (filter_has_global_settings($legacyname)) {
  1032. return new moodle_url('/admin/settings.php', array('section' => 'filtersetting' . str_replace('/', '', $legacyname)));
  1033. } else {
  1034. return null;
  1035. }
  1036. }
  1037. /**
  1038. * @see plugin_information::get_uninstall_url()
  1039. */
  1040. public function get_uninstall_url() {
  1041. if (strpos($this->name, 'mod_') === 0) {
  1042. return null;
  1043. } else {
  1044. $globalstates = self::get_global_states();
  1045. $legacyname = $globalstates[$this->name]->legacyname;
  1046. return new moodle_url('/admin/filters.php', array('sesskey' => sesskey(), 'filterpath' => $legacyname, 'action' => 'delete'));
  1047. }
  1048. }
  1049. /**
  1050. * Convert legacy filter names like 'filter/foo' or 'mod/bar' into frankenstyle
  1051. *
  1052. * @param string $legacyfiltername legacy filter name
  1053. * @return string frankenstyle-like name
  1054. */
  1055. protected static function normalize_legacy_name($legacyfiltername) {
  1056. $name = str_replace('/', '_', $legacyfiltername);
  1057. if (strpos($name, 'filter_') === 0) {
  1058. $name = substr($name, 7);
  1059. if (empty($name)) {
  1060. throw new coding_exception('Unable to determine filter name: ' . $legacyfiltername);
  1061. }
  1062. }
  1063. return $name;
  1064. }
  1065. /**
  1066. * Provides access to the results of {@link filter_get_global_states()}
  1067. * but indexed by the normalized filter name
  1068. *
  1069. * The legacy filter name is available as ->legacyname property.
  1070. *
  1071. * @param bool $disablecache
  1072. * @return array
  1073. */
  1074. protected static function get_global_states($disablecache=false) {
  1075. global $DB;
  1076. static $globalstatescache = null;
  1077. if ($disablecache or is_null($globalstatescache)) {
  1078. if (!$DB->get_manager()->table_exists('filter_active')) {
  1079. // we're upgrading from 1.9 and the table used by {@link filter_get_global_states()}
  1080. // does not exist yet
  1081. $globalstatescache = array();
  1082. } else {
  1083. foreach (filter_get_global_states() as $legacyname => $info) {
  1084. $name = self::normalize_legacy_name($legacyname);
  1085. $filterinfo = new stdClass();
  1086. $filterinfo->legacyname = $legacyname;
  1087. $filterinfo->active = $info->active;
  1088. $filterinfo->sortorder = $info->sortorder;
  1089. $globalstatescache[$name] = $filterinfo;
  1090. }
  1091. }
  1092. }
  1093. return $globalstatescache;
  1094. }
  1095. }
  1096. /**
  1097. * Class for activity modules
  1098. */
  1099. class plugintype_mod extends plugintype_base implements plugin_information {
  1100. /**
  1101. * @see plugin_information::get_plugins()
  1102. */
  1103. public static function get_plugins($type, $typerootdir, $typeclass) {
  1104. // get the information about plugins at the disk
  1105. $modules = parent::get_plugins($type, $typerootdir, $typeclass);
  1106. // add modules missing from disk
  1107. $modulesinfo = self::get_modules_info();
  1108. foreach ($modulesinfo as $modulename => $moduleinfo) {
  1109. if (isset($modules[$modulename])) {
  1110. continue;
  1111. }
  1112. $plugin = new $typeclass();
  1113. $plugin->type = $type;
  1114. $plugin->typerootdir = $typerootdir;
  1115. $plugin->name = $modulename;
  1116. $plugin->rootdir = null;
  1117. $plugin->displayname = $modulename;
  1118. $plugin->versiondb = $moduleinfo->version;
  1119. $plugin->init_is_standard();
  1120. $modules[$modulename] = $plugin;
  1121. }
  1122. return $modules;
  1123. }
  1124. /**
  1125. * @see plugin_information::init_display_name()
  1126. */
  1127. public function init_display_name() {
  1128. if (get_string_manager()->string_exists('pluginname', $this->component)) {
  1129. $this->displayname = get_string('pluginname', $this->component);
  1130. } else {
  1131. $this->displayname = get_string('modulename', $this->component);
  1132. }
  1133. }
  1134. /**
  1135. * Load the data from version.php.
  1136. * @return object the data object defined in version.php.
  1137. */
  1138. protected function load_version_php() {
  1139. $versionfile = $this->full_path('version.php');
  1140. $module = new stdClass();
  1141. if (is_readable($versionfile)) {
  1142. include($versionfile);
  1143. }
  1144. return $module;
  1145. }
  1146. /**
  1147. * @see plugin_information::load_db_version()
  1148. */
  1149. public function load_db_version() {
  1150. global $DB;
  1151. $modulesinfo = self::get_modules_info();
  1152. if (isset($modulesinfo[$this->name]->version)) {
  1153. $this->versiondb = $modulesinfo[$this->name]->version;
  1154. }
  1155. }
  1156. /**
  1157. * @see plugin_information::is_enabled()
  1158. */
  1159. public function is_enabled() {
  1160. $modulesinfo = self::get_modules_info();
  1161. if (isset($modulesinfo[$this->name]->visible)) {
  1162. if ($modulesinfo[$this->name]->visible) {
  1163. return true;
  1164. } else {
  1165. return false;
  1166. }
  1167. } else {
  1168. return parent::is_enabled();
  1169. }
  1170. }
  1171. /**
  1172. * @see plugin_information::get_settings_url()
  1173. */
  1174. public function get_settings_url() {
  1175. if (file_exists($this->full_path('settings.php')) or file_exists($this->full_path('settingstree.php'))) {
  1176. return new moodle_url('/admin/settings.php', array('section' => 'modsetting' . $this->name));
  1177. } else {
  1178. return parent::get_settings_url();
  1179. }
  1180. }
  1181. /**
  1182. * @see plugin_information::get_uninstall_url()
  1183. */
  1184. public function get_uninstall_url() {
  1185. if ($this->name !== 'forum') {
  1186. return new moodle_url('/admin/modules.php', array('delete' => $this->name, 'sesskey' => sesskey()));
  1187. } else {
  1188. return null;
  1189. }
  1190. }
  1191. /**
  1192. * Provides access to the records in {modules} table
  1193. *
  1194. * @param bool $disablecache do not use internal static cache
  1195. * @return array array of stdClasses
  1196. */
  1197. protected static function get_modules_info($disablecache=false) {
  1198. global $DB;
  1199. static $modulesinfocache = null;
  1200. if (is_null($modulesinfocache) or $disablecache) {
  1201. try {
  1202. $modulesinfocache = $DB->get_records('modules', null, 'name', 'name,id,version,visible');
  1203. } catch (dml_exception $e) {
  1204. // before install
  1205. $modulesinfocache = array();
  1206. }
  1207. }
  1208. return $modulesinfocache;
  1209. }
  1210. }
  1211. /**
  1212. * Class for question behaviours.
  1213. */
  1214. class plugintype_qbehaviour extends plugintype_base implements plugin_information {
  1215. /**
  1216. * @see plugin_information::get_uninstall_url()
  1217. */
  1218. public function get_uninstall_url() {
  1219. return new moodle_url('/admin/qbehaviours.php',
  1220. array('delete' => $this->name, 'sesskey' => sesskey()));
  1221. }
  1222. }
  1223. /**
  1224. * Class for question types
  1225. */
  1226. class plugintype_qtype extends plugintype_base implements plugin_information {
  1227. /**
  1228. * @see plugin_information::get_uninstall_url()
  1229. */
  1230. public function get_uninstall_url() {
  1231. return new moodle_url('/admin/qtypes.php',
  1232. array('delete' => $this->name, 'sesskey' => sesskey()));
  1233. }
  1234. }
  1235. /**
  1236. * Class for authentication plugins
  1237. */
  1238. class plugintype_auth extends plugintype_base implements plugin_information {
  1239. /**
  1240. * @see plugin_information::is_enabled()
  1241. */
  1242. public function is_enabled() {
  1243. global $CFG;
  1244. /** @var null|array list of enabled authentication plugins */
  1245. static $enabled = null;
  1246. if (in_array($this->name, array('nologin', 'manual'))) {
  1247. // these two are always enabled and can't be disabled
  1248. return null;
  1249. }
  1250. if (is_null($enabled)) {
  1251. $enabled = explode(',', $CFG->auth);
  1252. }
  1253. return isset($enabled[$this->name]);
  1254. }
  1255. /**
  1256. * @see plugin_information::get_settings_url()
  1257. */
  1258. public function get_settings_url() {
  1259. if (file_exists($this->full_path('settings.php'))) {
  1260. return new moodle_url('/admin/settings.php', array('section' => 'authsetting' . $this->name));
  1261. } else {
  1262. return new moodle_url('/admin/auth_config.php', array('auth' => $this->name));
  1263. }
  1264. }
  1265. }
  1266. /**
  1267. * Class for enrolment plugins
  1268. */
  1269. class plugintype_enrol extends plugintype_base implements plugin_information {
  1270. /**
  1271. * We do not actually need whole enrolment classes here so we do not call
  1272. * {@link enrol_get_plugins()}. Note that this may produce slightly different
  1273. * results, for example if the enrolment plugin does not contain lib.php
  1274. * but it is listed in $CFG->enrol_plugins_enabled
  1275. *
  1276. * @see plugin_information::is_enabled()
  1277. */
  1278. public function is_enabled() {
  1279. global $CFG;
  1280. /** @var null|array list of enabled enrolment plugins */
  1281. static $enabled = null;
  1282. if (is_null($enabled)) {
  1283. $enabled = explode(',', $CFG->enrol_plugins_enabled);
  1284. }
  1285. return isset($enabled[$this->name]);
  1286. }
  1287. /**
  1288. * @see plugin_information::get_settings_url()
  1289. */
  1290. public function get_settings_url() {
  1291. if ($this->is_enabled() or file_exists($this->full_path('settings.php'))) {
  1292. return new moodle_url('/admin/settings.php', array('section' => 'enrolsettings' . $this->name));
  1293. } else {
  1294. return parent::get_settings_url();
  1295. }
  1296. }
  1297. /**
  1298. * @see plugin_information::get_uninstall_url()
  1299. */
  1300. public function get_uninstall_url() {
  1301. return new moodle_url('/admin/enrol.php', array('action' => 'uninstall', 'enrol' => $this->name, 'sesskey' => sesskey()));
  1302. }
  1303. }
  1304. /**
  1305. * Class for messaging processors
  1306. */
  1307. class plugintype_message extends plugintype_base implements plugin_information {
  1308. /**
  1309. * @see plugin_information::get_settings_url()
  1310. */
  1311. public function get_settings_url() {
  1312. if (file_exists($this->full_path('settings.php')) or file_exists($this->full_path('settingstree.php'))) {
  1313. return new moodle_url('/admin/settings.php', array('section' => 'messagesetting' . $this->name));
  1314. } else {
  1315. return parent::get_settings_url();
  1316. }
  1317. }
  1318. }
  1319. /**
  1320. * Class for repositories
  1321. */
  1322. class plugintype_repository extends plugintype_base implements plugin_information {
  1323. /**
  1324. * @see plugin_information::is_enabled()
  1325. */
  1326. public function is_enabled() {
  1327. $enabled = self::get_enabled_repositories();
  1328. return isset($enabled[$this->name]);
  1329. }
  1330. /**
  1331. * @see plugin_information::get_settings_url()
  1332. */
  1333. public function get_settings_url() {
  1334. if ($this->is_enabled()) {
  1335. return new moodle_url('/admin/repository.php', array('sesskey' => sesskey(), 'action' => 'edit', 'repos' => $this->name));
  1336. } else {
  1337. return parent::get_settings_url();
  1338. }
  1339. }
  1340. /**
  1341. * Provides access to the records in {repository} table
  1342. *
  1343. * @param bool $disablecache do not use internal static cache
  1344. * @return array array of stdClasses
  1345. */
  1346. protected static function get_enabled_repositories($disablecache=false) {
  1347. global $DB;
  1348. static $repositories = null;
  1349. if (is_null($repositories) or $disablecache) {
  1350. $repositories = $DB->get_records('repository', null, 'type', 'type,visible,sortorder');
  1351. }
  1352. return $repositories;
  1353. }
  1354. }
  1355. /**
  1356. * Class for portfolios
  1357. */
  1358. class plugintype_portfolio extends plugintype_base implements plugin_information {
  1359. /**
  1360. * @see plugin_information::is_enabled()
  1361. */
  1362. public function is_enabled() {
  1363. $enabled = self::get_enabled_portfolios();
  1364. return isset($enabled[$this->name]);
  1365. }
  1366. /**
  1367. * Provides access to the records in {portfolio_instance} table
  1368. *
  1369. * @param bool $disablecache do not use internal static cache
  1370. * @return array array of stdClasses
  1371. */
  1372. protected static function get_enabled_portfolios($disablecache=false) {
  1373. global $DB;
  1374. static $portfolios = null;
  1375. if (is_null($portfolios) or $disablecache) {
  1376. $portfolios = array();
  1377. $instances = $DB->get_recordset('portfolio_instance', null, 'plugin');
  1378. foreach ($instances as $instance) {
  1379. if (isset($portfolios[$instance->plugin])) {
  1380. if ($instance->visible) {
  1381. $portfolios[$instance->plugin]->visible = $instance->visible;
  1382. }
  1383. } else {
  1384. $portfolios[$instance->plugin] = $instance;
  1385. }
  1386. }
  1387. }
  1388. return $portfolios;
  1389. }
  1390. }
  1391. /**
  1392. * Class for themes
  1393. */
  1394. class plugintype_theme extends plugintype_base implements plugin_information {
  1395. /**
  1396. * @see plugin_information::is_enabled()
  1397. */
  1398. public function is_enabled() {
  1399. global $CFG;
  1400. if ((!empty($CFG->theme) and $CFG->theme === $this->name) or
  1401. (!empty($CFG->themelegacy) and $CFG->themelegacy === $this->name)) {
  1402. return true;
  1403. } else {
  1404. return parent::is_enabled();
  1405. }
  1406. }
  1407. }
  1408. /**
  1409. * Class representing an MNet service
  1410. */
  1411. class plugintype_mnetservice extends plugintype_base implements plugin_information {
  1412. /**
  1413. * @see plugin_information::is_enabled()
  1414. */
  1415. public function is_enabled() {
  1416. global $CFG;
  1417. if (empty($CFG->mnet_dispatcher_mode) || $CFG->mnet_dispatcher_mode !== 'strict') {
  1418. return false;
  1419. } else {
  1420. return parent::is_enabled();
  1421. }
  1422. }
  1423. }
  1424. /**
  1425. * Class for admin tool plugins
  1426. */
  1427. class plugintype_tool extends plugintype_base implements plugin_information {
  1428. public function get_uninstall_url() {
  1429. return new moodle_url('/admin/tools.php', array('delete' => $this->name, 'sesskey' => sesskey()));
  1430. }
  1431. }
  1432. /**
  1433. * Class for admin tool plugins
  1434. */
  1435. class plugintype_report extends plugintype_base implements plugin_information {
  1436. public function get_uninstall_url() {
  1437. return new moodle_url('/admin/reports.php', array('delete' => $this->name, 'sesskey' => sesskey()));
  1438. }
  1439. }