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