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