PageRenderTime 57ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/pluginlib.php

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