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