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