PageRenderTime 54ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/moodle/lib/pluginlib.php

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