Proyectos de Subversion Moodle

Rev

Rev 11 | Mostrar el archivo completo | | | Autoría | Ultima modificación | Ver Log |

Rev 11 Rev 1441
Línea 20... Línea 20...
20
 * @package    core
20
 * @package    core
21
 * @copyright  2013 Petr Skoda {@link http://skodak.org}
21
 * @copyright  2013 Petr Skoda {@link http://skodak.org}
22
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23
 */
23
 */
Línea -... Línea 24...
-
 
24
 
-
 
25
namespace core;
-
 
26
 
-
 
27
use core\exception\coding_exception;
-
 
28
use core\output\theme_config;
-
 
29
use stdClass;
-
 
30
use ArrayIterator;
-
 
31
use DirectoryIterator;
-
 
32
use Exception;
-
 
33
use RegexIterator;
24
 
34
 
Línea 25... Línea 35...
25
// Constants used in version.php files, these must exist when core_component executes.
35
// Constants used in version.php files, these must exist when core_component executes.
26
 
36
 
27
// We make use of error_log as debugging is not always available.
37
// We make use of error_log as debugging is not always available.
Línea 41... Línea 51...
41
define('ANY_VERSION', 'any');
51
define('ANY_VERSION', 'any');
Línea 42... Línea 52...
42
 
52
 
43
/**
53
/**
44
 * Collection of components related methods.
54
 * Collection of components related methods.
45
 */
55
 */
46
class core_component {
56
class component {
47
    /** @var array list of ignored directories in plugin type roots - watch out for auth/db exception */
57
    /** @var array list of ignored directories in plugin type roots - watch out for auth/db exception */
48
    protected static $ignoreddirs = [
58
    protected static $ignoreddirs = [
49
        'CVS' => true,
59
        'CVS' => true,
50
        '_vti_cnf' => true,
60
        '_vti_cnf' => true,
Línea 72... Línea 82...
72
    protected static $subsystems = null;
82
    protected static $subsystems = null;
73
    /** @var array subplugin type parents */
83
    /** @var array subplugin type parents */
74
    protected static $parents = null;
84
    protected static $parents = null;
75
    /** @var array subplugins */
85
    /** @var array subplugins */
76
    protected static $subplugins = null;
86
    protected static $subplugins = null;
-
 
87
    /** @var array deprecated plugins  */
-
 
88
    protected static $deprecatedplugins = null;
-
 
89
    /** @var array deleted plugins */
-
 
90
    protected static $deletedplugins = null;
-
 
91
    /** @var array deprecated plugin types */
-
 
92
    protected static $deprecatedplugintypes = null;
-
 
93
    /** @var array deleted plugin types */
-
 
94
    protected static $deletedplugintypes = null;
-
 
95
    /** @var array deprecated sub plugins */
-
 
96
    protected static $deprecatedsubplugins = null;
-
 
97
    /** @var array deleted sub plugins */
-
 
98
    protected static $deletedsubplugins = null;
77
    /** @var array cache of core APIs */
99
    /** @var array cache of core APIs */
78
    protected static $apis = null;
100
    protected static $apis = null;
79
    /** @var array list of all known classes that can be autoloaded */
101
    /** @var array list of all known classes that can be autoloaded */
80
    protected static $classmap = null;
102
    protected static $classmap = null;
81
    /** @var array list of all classes that have been renamed to be autoloaded */
103
    /** @var array list of all classes that have been renamed to be autoloaded */
Línea 87... Línea 109...
87
    /** @var array list of the files to map. */
109
    /** @var array list of the files to map. */
88
    protected static $filestomap = ['lib.php', 'settings.php'];
110
    protected static $filestomap = ['lib.php', 'settings.php'];
89
    /** @var array associative array of PSR-0 namespaces and corresponding paths. */
111
    /** @var array associative array of PSR-0 namespaces and corresponding paths. */
90
    protected static $psr0namespaces = [
112
    protected static $psr0namespaces = [
91
        'Mustache' => 'lib/mustache/src/Mustache',
113
        'Mustache' => 'lib/mustache/src/Mustache',
92
        'CFPropertyList' => 'lib/plist/classes/CFPropertyList',
-
 
93
    ];
114
    ];
94
    /** @var array<string|array<string>> associative array of PRS-4 namespaces and corresponding paths. */
115
    /** @var array<string|array<string>> associative array of PRS-4 namespaces and corresponding paths. */
95
    protected static $psr4namespaces = [
116
    protected static $psr4namespaces = [
96
        'MaxMind' => 'lib/maxmind/MaxMind',
117
        \Aws::class => 'lib/aws-sdk/src',
-
 
118
        \CFPropertyList::class => 'lib/plist/src/CFPropertyList',
-
 
119
        \Complex::class => 'lib/phpspreadsheet/markbaker/complex/classes/src',
-
 
120
        \Composer\Pcre::class => 'lib/composer/pcre/src',
-
 
121
        \DI::class => 'lib/php-di/php-di/src',
97
        'GeoIp2' => 'lib/maxmind/GeoIp2',
122
        \GeoIp2::class => 'lib/maxmind/GeoIp2/src',
-
 
123
        \FastRoute::class => 'lib/nikic/fast-route/src',
98
        'Sabberworm\\CSS' => 'lib/php-css-parser',
124
        \Firebase\JWT::class => 'lib/php-jwt/src',
-
 
125
        \GuzzleHttp::class => 'lib/guzzlehttp/guzzle/src',
-
 
126
        \GuzzleHttp\Promise::class => 'lib/guzzlehttp/promises/src',
-
 
127
        \GuzzleHttp\Psr7::class => 'lib/guzzlehttp/psr7/src',
99
        'MoodleHQ\\RTLCSS' => 'lib/rtlcss',
128
        \Html2Text::class => 'lib/html2text/src',
-
 
129
        \IMSGlobal\LTI::class => 'lib/ltiprovider/src',
-
 
130
        \Invoker::class => 'lib/php-di/invoker/src',
100
        'ScssPhp\\ScssPhp' => 'lib/scssphp',
131
        \JmesPath::class => 'lib/jmespath/src',
-
 
132
        \Kevinrob\GuzzleCache::class => 'lib/guzzlehttp/kevinrob/guzzlecache/src',
-
 
133
        \Laravel\SerializableClosure::class => 'lib/laravel/serializable-closure/src',
101
        'OpenSpout' => 'lib/openspout/src',
134
        \lbuchs\WebAuthn::class => 'lib/webauthn/src',
-
 
135
        \libphonenumber::class => 'lib/giggsey/libphonenumber-for-php-lite/src',
-
 
136
        \Matrix::class => 'lib/phpspreadsheet/markbaker/matrix/classes/src',
102
        'MatthiasMullie\\Minify' => 'lib/minify/matthiasmullie-minify/src/',
137
        \MatthiasMullie\Minify::class => 'lib/minify/matthiasmullie-minify/src',
103
        'MatthiasMullie\\PathConverter' => 'lib/minify/matthiasmullie-pathconverter/src/',
138
        \MatthiasMullie\PathConverter::class => 'lib/minify/matthiasmullie-pathconverter/src',
-
 
139
        \MaxMind\Db::class => 'lib/maxmind/MaxMind/src/MaxMind/Db',
104
        'IMSGlobal\LTI' => 'lib/ltiprovider/src',
140
        \Michelf::class => 'lib/markdown/Michelf',
-
 
141
        \MoodleHQ::class => [
-
 
142
            'lib/rtlcss/src/MoodleHQ',
-
 
143
        ],
105
        'Packback\\Lti1p3' => 'lib/lti1p3/src',
144
        \OpenSpout::class => 'lib/openspout/src',
106
        'Phpml' => 'lib/mlbackend/php/phpml/src/Phpml',
145
        \Packback\Lti1p3::class => 'lib/lti1p3/src',
107
        'PHPMailer\\PHPMailer' => 'lib/phpmailer/src',
146
        \PHPMailer\PHPMailer::class => 'lib/phpmailer/src',
108
        'RedeyeVentures\\GeoPattern' => 'lib/geopattern-php/GeoPattern',
147
        \PhpOffice\PhpSpreadsheet::class => 'lib/phpspreadsheet/phpspreadsheet/src/PhpSpreadsheet',
109
        'Firebase\\JWT' => 'lib/php-jwt/src',
148
        \PhpXmlRpc::class => 'lib/phpxmlrpc/src',
110
        'ZipStream' => 'lib/zipstream/src/',
149
        \Phpml::class => 'lib/mlbackend/php/phpml/src/Phpml',
111
        'MyCLabs\\Enum' => 'lib/php-enum/src',
150
        \Psr\Clock::class => 'lib/psr/clock/src',
112
        'PhpXmlRpc' => 'lib/phpxmlrpc',
151
        \Psr\Container::class => 'lib/psr/container/src',
113
        'Psr\\Http\\Client' => 'lib/psr/http-client/src',
152
        \Psr\EventDispatcher::class => 'lib/psr/event-dispatcher/src',
114
        'Psr\\Http\\Message' => [
153
        \Psr\Http\Client::class => 'lib/psr/http-client/src',
115
            'lib/psr/http-message/src',
154
        \Psr\Http\Message::class => [
116
            'lib/psr/http-factory/src',
155
            'lib/psr/http-factory/src',
-
 
156
            'lib/psr/http-message/src',
-
 
157
        ],
-
 
158
        \Psr\Http\Server::class => [
-
 
159
            "lib/psr/http-server-handler/src",
-
 
160
            "lib/psr/http-server-middleware/src",
117
        ],
161
        ],
-
 
162
        \Psr\Log::class => "lib/psr/log/src",
118
        'Psr\\EventDispatcher' => 'lib/psr/event-dispatcher/src',
163
        \Psr\SimpleCache::class => 'lib/psr/simple-cache/src',
119
        'Psr\\Clock' => 'lib/psr/clock/src',
164
        \RedeyeVentures::class => 'lib/geopattern-php/src',
120
        'Psr\\Container' => 'lib/psr/container/src',
165
        \Sabberworm\CSS::class => 'lib/php-css-parser/src',
121
        'GuzzleHttp\\Psr7' => 'lib/guzzlehttp/psr7/src',
166
        \ScssPhp\ScssPhp::class => 'lib/scssphp/src',
122
        'GuzzleHttp\\Promise' => 'lib/guzzlehttp/promises/src',
167
        \SimplePie::class => 'lib/simplepie/src',
123
        'GuzzleHttp' => 'lib/guzzlehttp/guzzle/src',
168
        \Slim::class => 'lib/slim/slim/Slim',
124
        'Kevinrob\\GuzzleCache' => 'lib/guzzlehttp/kevinrob/guzzlecache/src',
169
        \Spatie\Cloneable::class => 'lib/spatie/php-cloneable/src',
125
        'Aws' => 'lib/aws-sdk/src',
170
        \ZipStream::class => 'lib/zipstream/src',
-
 
171
    ];
-
 
172
 
-
 
173
    /**
-
 
174
     *  An array containing files which are normally in a package's composer/autoload.files section.
-
 
175
     *
-
 
176
     * PHP does not provide a mechanism for automatically including the files that methods are in.
-
 
177
     *
-
 
178
     * The Composer autoloader includes all files in this section of the composer.json file during the instantiation of the loader.
-
 
179
     *
-
 
180
     * @var array<string>
-
 
181
     */
-
 
182
    protected static $composerautoloadfiles = [
-
 
183
        'lib/aws-sdk/src/functions.php',
-
 
184
        'lib/guzzlehttp/guzzle/src/functions_include.php',
126
        'JmesPath' => 'lib/jmespath/src',
185
        'lib/jmespath/src/JmesPath.php',
127
        'Laravel\\SerializableClosure' => 'lib/laravel/serializable-closure/src',
186
        'lib/nikic/fast-route/src/functions.php',
128
        'DI' => 'lib/php-di/php-di/src',
187
        'lib/php-di/php-di/src/functions.php',
-
 
188
        'lib/ralouphie/getallheaders/src/getallheaders.php',
129
        'Invoker' => 'lib/php-di/invoker/src',
189
        'lib/symfony/deprecation-contracts/function.php',
130
    ];
190
    ];
Línea 131... Línea 191...
131
 
191
 
-
 
192
    /**
-
 
193
     * Register the Moodle class autoloader.
-
 
194
     */
-
 
195
    public static function register_autoloader(): void {
-
 
196
        if (defined('COMPONENT_CLASSLOADER')) {
-
 
197
            spl_autoload_register(COMPONENT_CLASSLOADER);
-
 
198
        } else {
-
 
199
            spl_autoload_register([self::class, 'classloader']);
-
 
200
        }
-
 
201
 
-
 
202
        // Load any composer-driven autoload files.
-
 
203
        // This is intended to mimic the behaviour of the standard Composer Autoloader.
-
 
204
        foreach (static::$composerautoloadfiles as $file) {
-
 
205
            $path = dirname(__DIR__, 2) . '/' . $file;
-
 
206
            if (file_exists($path)) {
-
 
207
                require_once($path);
-
 
208
            }
-
 
209
        }
-
 
210
    }
-
 
211
 
132
    /**
212
    /**
133
     * Class loader for Frankenstyle named classes in standard locations.
213
     * Class loader for Frankenstyle named classes in standard locations.
134
     * Frankenstyle namespaces are supported.
214
     * Frankenstyle namespaces are supported.
135
     *
215
     *
136
     * The expected location for core classes is:
216
     * The expected location for core classes is:
Línea 157... Línea 237...
157
        }
237
        }
158
        if (isset(self::$classmaprenames[$classname]) && isset(self::$classmap[self::$classmaprenames[$classname]])) {
238
        if (isset(self::$classmaprenames[$classname]) && isset(self::$classmap[self::$classmaprenames[$classname]])) {
159
            $newclassname = self::$classmaprenames[$classname];
239
            $newclassname = self::$classmaprenames[$classname];
160
            $debugging = "Class '%s' has been renamed for the autoloader and is now deprecated. Please use '%s' instead.";
240
            $debugging = "Class '%s' has been renamed for the autoloader and is now deprecated. Please use '%s' instead.";
161
            debugging(sprintf($debugging, $classname, $newclassname), DEBUG_DEVELOPER);
241
            debugging(sprintf($debugging, $classname, $newclassname), DEBUG_DEVELOPER);
162
            if (PHP_VERSION_ID >= 70000 && preg_match('#\\\null(\\\|$)#', $classname)) {
242
            if (preg_match('#\\\null(\\\|$)#', $classname)) {
163
                throw new \coding_exception("Cannot alias $classname to $newclassname");
243
                throw new coding_exception("Cannot alias $classname to $newclassname");
164
            }
244
            }
165
            class_alias($newclassname, $classname);
245
            class_alias($newclassname, $classname);
166
            return;
246
            return;
167
        }
247
        }
Línea 303... Línea 383...
303
                    }
383
                    }
304
                    return;
384
                    return;
305
                }
385
                }
306
                $cache = [];
386
                $cache = [];
307
                include($cachefile);
387
                include($cachefile);
308
                self::$plugintypes      = $cache['plugintypes'];
388
                self::$plugintypes              = $cache['plugintypes'];
-
 
389
                self::$deprecatedplugintypes    = $cache['deprecatedplugintypes'];
-
 
390
                self::$deletedplugintypes       = $cache['deletedplugintypes'];
309
                self::$plugins          = $cache['plugins'];
391
                self::$plugins                  = $cache['plugins'];
-
 
392
                self::$deprecatedplugins        = $cache['deprecatedplugins'];
-
 
393
                self::$deletedplugins           = $cache['deletedplugins'];
310
                self::$subsystems       = $cache['subsystems'];
394
                self::$subsystems               = $cache['subsystems'];
311
                self::$parents          = $cache['parents'];
395
                self::$parents                  = $cache['parents'];
312
                self::$subplugins       = $cache['subplugins'];
396
                self::$subplugins               = $cache['subplugins'];
-
 
397
                self::$deprecatedsubplugins     = $cache['deprecatedsubplugins'];
-
 
398
                self::$deletedsubplugins        = $cache['deletedsubplugins'];
313
                self::$apis             = $cache['apis'];
399
                self::$apis                     = $cache['apis'];
314
                self::$classmap         = $cache['classmap'];
400
                self::$classmap                 = $cache['classmap'];
315
                self::$classmaprenames  = $cache['classmaprenames'];
401
                self::$classmaprenames          = $cache['classmaprenames'];
316
                self::$filemap          = $cache['filemap'];
402
                self::$filemap                  = $cache['filemap'];
317
                return;
403
                return;
318
            }
404
            }
Línea 319... Línea 405...
319
 
405
 
320
            if (!is_writable(dirname($cachefile))) {
406
            if (!is_writable(dirname($cachefile))) {
Línea 335... Línea 421...
335
            // 1/ Use the cache only outside of install and upgrade.
421
            // 1/ Use the cache only outside of install and upgrade.
336
            // 2/ Let developers add/remove classes in developer mode.
422
            // 2/ Let developers add/remove classes in developer mode.
337
            if (is_readable($cachefile)) {
423
            if (is_readable($cachefile)) {
338
                $cache = false;
424
                $cache = false;
339
                include($cachefile);
425
                include($cachefile);
340
                if (!is_array($cache)) {
426
                if (is_array($cache) && self::is_cache_valid($cache)) {
341
                    // Something is very wrong.
-
 
342
                } else if (!isset($cache['version'])) {
-
 
343
                    // Something is very wrong.
-
 
344
                } else if ((float) $cache['version'] !== (float) self::fetch_core_version()) {
-
 
345
                    // Outdated cache. We trigger an error log to track an eventual repetitive failure of float comparison.
-
 
346
                    error_log('Resetting core_component cache after core upgrade to version ' . self::fetch_core_version());
-
 
347
                } else if ($cache['plugintypes']['mod'] !== "$CFG->dirroot/mod") {
-
 
348
                    // phpcs:ignore moodle.Commenting.InlineComment.NotCapital
-
 
349
                    // $CFG->dirroot was changed.
-
 
350
                } else {
-
 
351
                    // The cache looks ok, let's use it.
427
                    // The cache looks ok, let's use it.
352
                    self::$plugintypes      = $cache['plugintypes'];
428
                    self::$plugintypes              = $cache['plugintypes'];
-
 
429
                    self::$deprecatedplugintypes    = $cache['deprecatedplugintypes'];
-
 
430
                    self::$deletedplugintypes       = $cache['deletedplugintypes'];
353
                    self::$plugins          = $cache['plugins'];
431
                    self::$plugins                  = $cache['plugins'];
-
 
432
                    self::$deprecatedplugins        = $cache['deprecatedplugins'];
-
 
433
                    self::$deletedplugins           = $cache['deletedplugins'];
354
                    self::$subsystems       = $cache['subsystems'];
434
                    self::$subsystems               = $cache['subsystems'];
355
                    self::$parents          = $cache['parents'];
435
                    self::$parents                  = $cache['parents'];
356
                    self::$subplugins       = $cache['subplugins'];
436
                    self::$subplugins               = $cache['subplugins'];
-
 
437
                    self::$deprecatedsubplugins     = $cache['deprecatedsubplugins'];
-
 
438
                    self::$deletedsubplugins        = $cache['deletedsubplugins'];
357
                    self::$apis             = $cache['apis'];
439
                    self::$apis                     = $cache['apis'];
358
                    self::$classmap         = $cache['classmap'];
440
                    self::$classmap                 = $cache['classmap'];
359
                    self::$classmaprenames  = $cache['classmaprenames'];
441
                    self::$classmaprenames          = $cache['classmaprenames'];
360
                    self::$filemap          = $cache['filemap'];
442
                    self::$filemap                  = $cache['filemap'];
361
                    return;
443
                    return;
362
                }
444
                }
363
                // Note: we do not verify $CFG->admin here intentionally,
445
                // Note: we do not verify $CFG->admin here intentionally,
364
                // they must visit admin/index.php after any change.
446
                // they must visit admin/index.php after any change.
365
            }
447
            }
Línea 402... Línea 484...
402
     * Reset the initialisation of the component utility.
484
     * Reset the initialisation of the component utility.
403
     *
485
     *
404
     * Note: It should not be necessary to call this in regular code.
486
     * Note: It should not be necessary to call this in regular code.
405
     * Please only use it where strictly required.
487
     * Please only use it where strictly required.
406
     */
488
     */
407
    public static function reset(): void {
489
    public static function reset(
-
 
490
        bool $fullreset = false,
-
 
491
    ): void {
408
        // The autoloader will re-initialise if plugintypes is null.
492
        // The autoloader will re-initialise if plugintypes is null.
409
        self::$plugintypes = null;
493
        self::$plugintypes = null;
-
 
494
 
-
 
495
        // Reset all caches to ensure they are reloaded.
-
 
496
        self::$plugins = null;
-
 
497
        self::$subsystems = null;
-
 
498
        self::$parents = null;
-
 
499
        self::$subplugins = null;
-
 
500
        self::$deprecatedplugins = null;
-
 
501
        self::$deletedplugins = null;
-
 
502
        self::$deprecatedplugintypes = null;
-
 
503
        self::$deletedplugintypes = null;
-
 
504
        self::$deprecatedsubplugins = null;
-
 
505
        self::$deletedsubplugins = null;
-
 
506
        self::$apis = null;
-
 
507
        self::$classmap = null;
-
 
508
        self::$classmaprenames = null;
-
 
509
        self::$filemap = null;
-
 
510
 
-
 
511
        if ($fullreset) {
-
 
512
            self::$componentsource = null;
-
 
513
            self::$version = null;
-
 
514
            self::$supportsubplugins = ['mod', 'editor', 'tool', 'local'];
-
 
515
        }
-
 
516
    }
-
 
517
 
-
 
518
    /**
-
 
519
     * Check whether the cache content in the supplied cache is valid.
-
 
520
     *
-
 
521
     * @param array $cache The content being loaded
-
 
522
     * @return bool Whether it is valid
-
 
523
     */
-
 
524
    protected static function is_cache_valid(array $cache): bool {
-
 
525
        global $CFG;
-
 
526
 
-
 
527
        if (!isset($cache['version'])) {
-
 
528
            // Something is very wrong.
-
 
529
            return false;
-
 
530
        }
-
 
531
 
-
 
532
        if ((float) $cache['version'] !== (float) self::fetch_core_version()) {
-
 
533
            // Outdated cache. We trigger an error log to track an eventual repetitive failure of float comparison.
-
 
534
            error_log('Resetting core_component cache after core upgrade to version ' . self::fetch_core_version());
-
 
535
            return false;
-
 
536
        }
-
 
537
 
-
 
538
        if ($cache['plugintypes']['mod'] !== "$CFG->dirroot/mod") {
-
 
539
            // phpcs:ignore moodle.Commenting.InlineComment.NotCapital
-
 
540
            // $CFG->dirroot was changed.
-
 
541
            return false;
-
 
542
        }
-
 
543
 
-
 
544
        // Check for key classes which block access to the upgrade in some way.
-
 
545
        // Note: This list should be kept _extremely_ minimal and generally
-
 
546
        // when adding a newly discovered classes older ones should be removed.
-
 
547
        // Always keep moodle_exception in place.
-
 
548
        $keyclasses = [
-
 
549
            \core\exception\moodle_exception::class,
-
 
550
            \core\output\bootstrap_renderer::class,
-
 
551
            \core_cache\cache::class,
-
 
552
        ];
-
 
553
        foreach ($keyclasses as $classname) {
-
 
554
            if (!array_key_exists($classname, $cache['classmap'])) {
-
 
555
                // The cache is missing some key classes. This is likely before the upgrade has run.
-
 
556
                error_log(
-
 
557
                    "The '{$classname}' class was not found in the component class cache. Resetting the classmap.",
-
 
558
                );
-
 
559
                return false;
-
 
560
            }
-
 
561
        }
-
 
562
 
-
 
563
        return true;
410
    }
564
    }
Línea 411... Línea 565...
411
 
565
 
412
    /**
566
    /**
413
     * Are we in developer debug mode?
567
     * Are we in developer debug mode?
414
     *
568
     *
415
     * Note: You need to set "$CFG->debug = (E_ALL | E_STRICT);" in config.php,
569
     * Note: You need to set "$CFG->debug = (E_ALL);" in config.php,
416
     *       the reason is we need to use this before we setup DB connection or caches for CFG.
570
     *       the reason is we need to use this before we setup DB connection or caches for CFG.
417
     *
571
     *
418
     * @return bool
572
     * @return bool
419
     */
573
     */
Línea 425... Línea 579...
425
            $debug = (int)$CFG->config_php_settings['debug'];
579
            $debug = (int)$CFG->config_php_settings['debug'];
426
        } else {
580
        } else {
427
            return false;
581
            return false;
428
        }
582
        }
Línea 429... Línea 583...
429
 
583
 
430
        if ($debug & E_ALL && $debug & E_STRICT) {
584
        if ($debug & E_ALL) {
431
            return true;
585
            return true;
Línea 432... Línea 586...
432
        }
586
        }
433
 
587
 
Línea 445... Línea 599...
445
        if (!isset(self::$plugintypes)) {
599
        if (!isset(self::$plugintypes)) {
446
            self::fill_all_caches();
600
            self::fill_all_caches();
447
        }
601
        }
Línea 448... Línea 602...
448
 
602
 
449
        $cache = [
603
        $cache = [
450
            'subsystems'        => self::$subsystems,
604
            'subsystems'            => self::$subsystems,
-
 
605
            'plugintypes'           => self::$plugintypes,
-
 
606
            'deprecatedplugintypes' => self::$deprecatedplugintypes,
451
            'plugintypes'       => self::$plugintypes,
607
            'deletedplugintypes'    => self::$deletedplugintypes,
-
 
608
            'plugins'               => self::$plugins,
452
            'plugins'           => self::$plugins,
609
            'deprecatedplugins'     => self::$deprecatedplugins,
453
            'parents'           => self::$parents,
610
            'deletedplugins'        => self::$deletedplugins,
-
 
611
            'subplugins'            => self::$subplugins,
-
 
612
            'deprecatedsubplugins'  => self::$deprecatedsubplugins,
-
 
613
            'deletedsubplugins'     => self::$deletedsubplugins,
454
            'subplugins'        => self::$subplugins,
614
            'parents'               => self::$parents,
455
            'apis'              => self::$apis,
615
            'apis'                  => self::$apis,
456
            'classmap'          => self::$classmap,
616
            'classmap'              => self::$classmap,
457
            'classmaprenames'   => self::$classmaprenames,
617
            'classmaprenames'       => self::$classmaprenames,
458
            'filemap'           => self::$filemap,
618
            'filemap'               => self::$filemap,
459
            'version'           => self::$version,
619
            'version'               => self::$version,
Línea 460... Línea 620...
460
        ];
620
        ];
461
 
621
 
462
        return '<?php
622
        return '<?php
Línea 468... Línea 628...
468
     * Fill all caches.
628
     * Fill all caches.
469
     */
629
     */
470
    protected static function fill_all_caches() {
630
    protected static function fill_all_caches() {
471
        self::$subsystems = self::fetch_subsystems();
631
        self::$subsystems = self::fetch_subsystems();
Línea -... Línea 632...
-
 
632
 
-
 
633
        [
-
 
634
            'plugintypes' => self::$plugintypes,
-
 
635
            'parents' => self::$parents,
-
 
636
            'subplugins' => self::$subplugins,
472
 
637
            'deprecatedplugintypes' => self::$deprecatedplugintypes,
-
 
638
            'deletedplugintypes' => self::$deletedplugintypes,
-
 
639
            'deprecatedsubplugins' => self::$deprecatedsubplugins,
-
 
640
            'deletedsubplugin' => self::$deletedsubplugins
Línea 473... Línea 641...
473
        [self::$plugintypes, self::$parents, self::$subplugins] = self::fetch_plugintypes();
641
        ] = self::fetch_plugintypes();
474
 
642
 
475
        self::$plugins = [];
643
        self::$plugins = [];
476
        foreach (self::$plugintypes as $type => $fulldir) {
644
        foreach (self::$plugintypes as $type => $fulldir) {
Línea -... Línea 645...
-
 
645
            self::$plugins[$type] = self::fetch_plugins($type, $fulldir);
-
 
646
        }
-
 
647
 
-
 
648
        self::$deprecatedplugins = [];
-
 
649
        foreach (self::$deprecatedplugintypes as $type => $fulldir) {
-
 
650
            self::$deprecatedplugins[$type] = self::fetch_plugins($type, $fulldir);
-
 
651
        }
-
 
652
 
-
 
653
        self::$deletedplugins = [];
-
 
654
        foreach (self::$deletedplugintypes as $type => $fulldir) {
477
            self::$plugins[$type] = self::fetch_plugins($type, $fulldir);
655
            self::$deletedplugins[$type] = self::fetch_plugins($type, $fulldir);
Línea 478... Línea 656...
478
        }
656
        }
479
 
657
 
480
        self::$apis = self::fetch_apis();
658
        self::$apis = self::fetch_apis();
Línea 541... Línea 719...
541
     * @return array
719
     * @return array
542
     */
720
     */
543
    protected static function fetch_plugintypes() {
721
    protected static function fetch_plugintypes() {
544
        global $CFG;
722
        global $CFG;
Línea -... Línea 723...
-
 
723
 
-
 
724
        // Top level plugin types.
-
 
725
        $plugintypesmap = [
-
 
726
            'plugintypes' => [],
-
 
727
            'deprecatedplugintypes' => [],
-
 
728
            'deletedplugintypes' => [],
-
 
729
        ];
-
 
730
 
-
 
731
        $subplugintypesmap = [
-
 
732
            'plugintypes' => [],
-
 
733
            'deprecatedplugintypes' => [],
-
 
734
            'deletedplugintypes' => [],
-
 
735
        ];
545
 
736
 
-
 
737
        $parents = [];
-
 
738
 
-
 
739
        foreach ($plugintypesmap as $sourcekey => $typesarr) {
546
        $types = [];
740
            /** @var string $plugintype */
547
        foreach (self::fetch_component_source('plugintypes') as $plugintype => $path) {
741
            foreach (self::fetch_component_source($sourcekey) as $plugintype => $path) {
548
            // Replace admin/ with the config setting.
742
                // Replace admin/ with the config setting.
549
            if ($CFG->admin !== 'admin' && strpos($path, 'admin/') === 0) {
743
                if ($CFG->admin !== 'admin' && strpos($path, 'admin/') === 0) {
-
 
744
                    $path = $CFG->admin . substr($path, 5);
-
 
745
                }
550
                $path = $CFG->admin . substr($path, 5);
746
                $plugintypesmap[$sourcekey][$plugintype] = "{$CFG->dirroot}/{$path}";
551
            }
-
 
552
            $types[$plugintype] = "{$CFG->dirroot}/{$path}";
747
            }
Línea -... Línea 748...
-
 
748
        }
-
 
749
 
-
 
750
        // Prevent deprecation of plugin types supporting subplugins (those in self::$supportsubplugins).
-
 
751
        foreach (['deprecatedplugintypes', 'deletedplugintypes'] as $key) {
-
 
752
            $illegaltypes = array_intersect(self::$supportsubplugins, array_keys($plugintypesmap[$key]));
-
 
753
            if (!empty($illegaltypes)) {
-
 
754
                debugging("Deprecation of a plugin type which supports subplugins is not supported. These plugin types will ".
-
 
755
                    "continue to be treated as active.", DEBUG_DEVELOPER);
-
 
756
                foreach ($illegaltypes as $plugintype) {
553
        }
757
                    $plugintypesmap['plugintypes'][$plugintype] = $plugintypesmap[$key][$plugintype];
554
 
758
                    unset($plugintypesmap[$key][$plugintype]);
-
 
759
                }
Línea 555... Línea 760...
555
        $parents = [];
760
            }
556
        $subplugins = [];
761
        }
557
 
762
 
558
        if (!empty($CFG->themedir) && is_dir($CFG->themedir)) {
763
        if (!empty($CFG->themedir) && is_dir($CFG->themedir)) {
559
            $types['theme'] = $CFG->themedir;
764
            $plugintypesmap['plugintypes']['theme'] = $CFG->themedir;
Línea 560... Línea 765...
560
        } else {
765
        } else {
561
            $types['theme'] = $CFG->dirroot . '/theme';
766
            $plugintypesmap['plugintypes']['theme'] = $CFG->dirroot . '/theme';
562
        }
767
        }
563
 
768
 
564
        foreach (self::$supportsubplugins as $type) {
769
        foreach (self::$supportsubplugins as $type) {
-
 
770
            if ($type === 'local') {
565
            if ($type === 'local') {
771
                // Local subplugins must be after local plugins.
566
                // Local subplugins must be after local plugins.
772
                continue;
567
                continue;
773
            }
568
            }
774
 
-
 
775
            $plugins = self::fetch_plugins($type, $plugintypesmap['plugintypes'][$type]);
-
 
776
            foreach ($plugins as $plugin => $fulldir) {
-
 
777
                $allsubtypes = self::fetch_subtypes($fulldir);
-
 
778
                $subplugintypesdata = [
-
 
779
                    'plugintypes' => $allsubtypes['plugintypes'] ?? [],
-
 
780
                    'deprecatedplugintypes' => $allsubtypes['deprecatedplugintypes'] ?? [],
-
 
781
                    'deletedplugintypes' => $allsubtypes['deletedplugintypes'] ?? [],
569
            $plugins = self::fetch_plugins($type, $types[$type]);
782
                ];
570
            foreach ($plugins as $plugin => $fulldir) {
783
 
571
                $subtypes = self::fetch_subtypes($fulldir);
784
                if (!$subplugintypesdata['plugintypes'] && !$subplugintypesdata['deprecatedplugintypes']
-
 
785
                        && !$subplugintypesdata['deletedplugintypes']) {
-
 
786
                    continue;
-
 
787
                }
-
 
788
                $subplugintypesmap['plugintypes'][$type . '_' . $plugin] = [];
572
                if (!$subtypes) {
789
                $subplugintypesmap['deprecatedplugintypes'][$type . '_' . $plugin] = [];
573
                    continue;
790
                $subplugintypesmap['deletedplugintypes'][$type . '_' . $plugin] = [];
-
 
791
 
-
 
792
                foreach ($subplugintypesdata as $key => $subplugintypes) {
574
                }
793
                    foreach ($subplugintypes as $subtype => $subdir) {
575
                $subplugins[$type . '_' . $plugin] = [];
794
                        if (isset($plugintypesmap['plugintypes'][$subtype])
-
 
795
                                || isset($plugintypesmap['deprecatedplugintypes'][$subtype])
-
 
796
                                || isset($plugintypesmap['deletedplugintypes'][$subtype])) {
-
 
797
                            error_log("Invalid subtype '$subtype', duplicate detected.");
-
 
798
                            continue;
-
 
799
                        }
-
 
800
                        $plugintypesmap[$key][$subtype] = $subdir;
576
                foreach ($subtypes as $subtype => $subdir) {
801
                        $parents[$subtype] = $type . '_' . $plugin;
577
                    if (isset($types[$subtype])) {
-
 
578
                        error_log("Invalid subtype '$subtype', duplicate detected.");
-
 
579
                        continue;
-
 
580
                    }
802
                        $subplugintypesmap[$key][$type . '_' . $plugin][$subtype] = array_keys(
581
                    $types[$subtype] = $subdir;
803
                            self::fetch_plugins($subtype, $subdir)
582
                    $parents[$subtype] = $type . '_' . $plugin;
804
                        );
583
                    $subplugins[$type . '_' . $plugin][$subtype] = array_keys(self::fetch_plugins($subtype, $subdir));
805
                    }
584
                }
806
                }
Línea 585... Línea 807...
585
            }
807
            }
586
        }
808
        }
587
        // Local is always last!
809
        // Local is always last!
588
        $types['local'] = $CFG->dirroot . '/local';
810
        $plugintypesmap['plugintypes']['local'] = $CFG->dirroot . '/local';
589
 
811
 
590
        if (in_array('local', self::$supportsubplugins)) {
812
        if (in_array('local', self::$supportsubplugins)) {
-
 
813
            $type = 'local';
-
 
814
            $plugins = self::fetch_plugins($type, $plugintypesmap['plugintypes'][$type]);
-
 
815
            foreach ($plugins as $plugin => $fulldir) {
-
 
816
                $allsubtypes = self::fetch_subtypes($fulldir);
-
 
817
                $subplugintypesdata = [
-
 
818
                    'plugintypes' => $allsubtypes['plugintypes'] ?? [],
591
            $type = 'local';
819
                    'deprecatedplugintypes' => $allsubtypes['deprecatedplugintypes'] ?? [],
592
            $plugins = self::fetch_plugins($type, $types[$type]);
820
                    'deletedplugintypes' => $allsubtypes['deletedplugintypes'] ?? [],
593
            foreach ($plugins as $plugin => $fulldir) {
821
                ];
-
 
822
                if (!$subplugintypesdata['plugintypes'] && !$subplugintypesdata['deprecatedplugintypes']
-
 
823
                        && !$subplugintypesdata['deletedplugintypes']) {
-
 
824
                    continue;
-
 
825
                }
594
                $subtypes = self::fetch_subtypes($fulldir);
826
                $subplugintypesmap['plugintypes'][$type . '_' . $plugin] = [];
595
                if (!$subtypes) {
827
                $subplugintypesmap['deprecatedplugintypes'][$type . '_' . $plugin] = [];
-
 
828
                $subplugintypesmap['deletedplugintypes'][$type . '_' . $plugin] = [];
-
 
829
 
596
                    continue;
830
                foreach ($subplugintypesdata as $key => $subplugintypes) {
597
                }
831
                    foreach ($subplugintypes as $subtype => $subdir) {
-
 
832
                        if (isset($plugintypesmap['plugintypes'][$subtype])
-
 
833
                                || isset($plugintypesmap['deprecatedplugintypes'][$subtype])
-
 
834
                                || isset($plugintypesmap['deletedplugintypes'][$subtype])) {
-
 
835
                            error_log("Invalid subtype '$subtype', duplicate detected.");
-
 
836
                            continue;
-
 
837
                        }
598
                $subplugins[$type . '_' . $plugin] = [];
838
                        $plugintypesmap[$key][$subtype] = $subdir;
599
                foreach ($subtypes as $subtype => $subdir) {
-
 
600
                    if (isset($types[$subtype])) {
-
 
601
                        error_log("Invalid subtype '$subtype', duplicate detected.");
-
 
602
                        continue;
839
                        $parents[$subtype] = $type . '_' . $plugin;
603
                    }
840
                        $subplugintypesmap[$key][$type . '_' . $plugin][$subtype] = array_keys(
604
                    $types[$subtype] = $subdir;
841
                            self::fetch_plugins($subtype, $subdir)
Línea -... Línea 842...
-
 
842
                        );
605
                    $parents[$subtype] = $type . '_' . $plugin;
843
                    }
-
 
844
                }
-
 
845
            }
-
 
846
        }
-
 
847
 
-
 
848
        return [
-
 
849
            'plugintypes' => $plugintypesmap['plugintypes'],
-
 
850
            'parents' => $parents,
606
                    $subplugins[$type . '_' . $plugin][$subtype] = array_keys(self::fetch_plugins($subtype, $subdir));
851
            'subplugins' => $subplugintypesmap['plugintypes'],
Línea 607... Línea 852...
607
                }
852
            'deprecatedplugintypes' => $plugintypesmap['deprecatedplugintypes'],
608
            }
853
            'deletedplugintypes' => $plugintypesmap['deletedplugintypes'],
609
        }
854
            'deprecatedsubplugins' => $subplugintypesmap['deprecatedplugintypes'],
Línea 619... Línea 864...
619
    protected static function fetch_component_source(string $key) {
864
    protected static function fetch_component_source(string $key) {
620
        if (null === self::$componentsource) {
865
        if (null === self::$componentsource) {
621
            self::$componentsource = (array) json_decode(file_get_contents(__DIR__ . '/../components.json'));
866
            self::$componentsource = (array) json_decode(file_get_contents(__DIR__ . '/../components.json'));
622
        }
867
        }
Línea 623... Línea 868...
623
 
868
 
624
        return (array) self::$componentsource[$key];
869
        return !empty(self::$componentsource[$key]) ? (array) self::$componentsource[$key] : [];
Línea 625... Línea 870...
625
    }
870
    }
626
 
871
 
627
    /**
872
    /**
Línea 632... Línea 877...
632
    protected static function fetch_subtypes($ownerdir) {
877
    protected static function fetch_subtypes($ownerdir) {
633
        global $CFG;
878
        global $CFG;
Línea 634... Línea 879...
634
 
879
 
635
        $types = [];
880
        $types = [];
-
 
881
        $subplugins = [];
-
 
882
        if (str_contains($ownerdir, $CFG->dirroot)) {
-
 
883
            $plugindir = substr($ownerdir, strlen($CFG->dirroot) + 1);
-
 
884
        } else {
-
 
885
            $realownerdir = realpath($ownerdir);
-
 
886
            $realroot = realpath(dirname(__DIR__, 2));
-
 
887
            $plugindir = substr($realownerdir, strlen($realroot) + 1);
-
 
888
        }
-
 
889
 
-
 
890
        $subtypesregister = [
-
 
891
            'plugintypes' => [],
-
 
892
            'deprecatedplugintypes' => [],
-
 
893
            'deletedplugintypes' => [],
636
        $subplugins = [];
894
        ];
637
        if (file_exists("$ownerdir/db/subplugins.json")) {
895
        if (file_exists("$ownerdir/db/subplugins.json")) {
638
            $subplugins = [];
896
            $subpluginpathformatter = fn (string $value): string => "{$plugindir}/{$value}";
639
            $subpluginsjson = json_decode(file_get_contents("$ownerdir/db/subplugins.json"));
897
            $subpluginsjson = json_decode(file_get_contents("$ownerdir/db/subplugins.json"));
-
 
898
            if (json_last_error() === JSON_ERROR_NONE) {
640
            if (json_last_error() === JSON_ERROR_NONE) {
899
                $subplugins = [];
-
 
900
                if (!empty($subpluginsjson->subplugintypes)) {
-
 
901
                    // If the newer subplugintypes is defined, use it.
-
 
902
                    // The value here is relative to the plugin's owner directory.
-
 
903
                    $subplugins = array_map($subpluginpathformatter, (array) $subpluginsjson->subplugintypes);
-
 
904
                } else if (!empty($subpluginsjson->plugintypes)) {
-
 
905
                    error_log(
-
 
906
                        "No subplugintypes defined in $ownerdir/db/subplugins.json. " .
-
 
907
                        "Falling back to deprecated plugintypes value. " .
-
 
908
                        "See MDL-83705 for further information.",
641
                if (!empty($subpluginsjson->plugintypes)) {
909
                    );
642
                    $subplugins = (array) $subpluginsjson->plugintypes;
910
                    $subplugins = (array) $subpluginsjson->plugintypes;
643
                } else {
911
                } else if (empty($subpluginjson->deprecatedplugintypes) && empty($subpluginsjson->deletedplugintypes)) {
644
                    error_log("No plugintypes defined in $ownerdir/db/subplugins.json");
912
                    error_log("No plugintypes defined in $ownerdir/db/subplugins.json");
-
 
913
                }
-
 
914
 
-
 
915
                $subtypesregister['plugintypes'] = $subplugins;
-
 
916
 
-
 
917
                // The deprecated and deleted subplugintypes are optional and are always relative to the plugin's root directory.
-
 
918
                $subtypesregister['deprecatedplugintypes'] = array_map(
-
 
919
                    $subpluginpathformatter,
-
 
920
                    (array) ($subpluginsjson->deprecatedsubplugintypes ?? []),
-
 
921
                );
-
 
922
                $subtypesregister['deletedplugintypes'] = array_map(
-
 
923
                    $subpluginpathformatter,
-
 
924
                    (array) ($subpluginsjson->deletedsubplugintypes ?? []),
645
                }
925
                );
646
            } else {
926
            } else {
647
                $jsonerror = json_last_error_msg();
927
                $jsonerror = json_last_error_msg();
648
                error_log("$ownerdir/db/subplugins.json is invalid ($jsonerror)");
928
                error_log("$ownerdir/db/subplugins.json is invalid ($jsonerror)");
-
 
929
            }
-
 
930
 
-
 
931
            if (function_exists('debugging') && debugging()) {
-
 
932
                if (property_exists($subpluginsjson, 'subplugintypes') && property_exists($subpluginsjson, 'plugintypes')) {
-
 
933
                    $subplugintypes = (array) $subpluginsjson->subplugintypes;
-
 
934
                    $plugintypes = (array) $subpluginsjson->plugintypes;
-
 
935
                    if (count($subplugintypes) !== count(($plugintypes))) {
-
 
936
                        error_log("Subplugintypes and plugintypes are not in sync in $ownerdir/db/subplugins.json");
-
 
937
                    }
-
 
938
                    foreach ($subplugintypes as $type => $path) {
-
 
939
                        if (!isset($plugintypes[$type])) {
-
 
940
                            error_log("Subplugintypes and plugintypes are not in sync for '$type' in $ownerdir/db/subplugins.json");
-
 
941
 
-
 
942
                            continue;
-
 
943
                        }
-
 
944
 
-
 
945
                        if ($plugintypes[$type] !== $subplugins[$type]) {
-
 
946
                            error_log("Subplugintypes and plugintypes are not in sync for '$type' in $ownerdir/db/subplugins.json");
-
 
947
                        }
-
 
948
                    }
-
 
949
                }
649
            }
950
            }
-
 
951
        } else if (file_exists("$ownerdir/db/subplugins.php")) {
650
        } else if (file_exists("$ownerdir/db/subplugins.php")) {
952
            throw new coding_exception(
651
            error_log('Use of subplugins.php has been deprecated. ' .
953
                'Use of subplugins.php has been deprecated and is no longer supported. ' .
652
                "Please update your '$ownerdir' plugin to provide a subplugins.json file instead.");
954
                "Please update your '$ownerdir' plugin to provide a subplugins.json file instead.",
653
            include("$ownerdir/db/subplugins.php");
955
            );
Línea -... Línea 956...
-
 
956
        }
654
        }
957
 
655
 
958
        foreach ($subtypesregister as $key => $subtypes) {
656
        foreach ($subplugins as $subtype => $dir) {
959
            foreach ($subtypes as $subtype => $dir) {
657
            if (!preg_match('/^[a-z][a-z0-9]*$/', $subtype)) {
960
                if (!preg_match('/^[a-z][a-z0-9]*$/', $subtype)) {
658
                error_log("Invalid subtype '$subtype'' detected in '$ownerdir', invalid characters present.");
961
                    error_log("Invalid subtype '$subtype'' detected in '$ownerdir', invalid characters present.");
659
                continue;
962
                    continue;
660
            }
963
                }
661
            if (isset(self::$subsystems[$subtype])) {
964
                if (isset(self::$subsystems[$subtype])) {
662
                error_log("Invalid subtype '$subtype'' detected in '$ownerdir', duplicates core subsystem.");
965
                    error_log("Invalid subtype '$subtype'' detected in '$ownerdir', duplicates core subsystem.");
663
                continue;
966
                    continue;
664
            }
967
                }
665
            if ($CFG->admin !== 'admin' && strpos($dir, 'admin/') === 0) {
968
                if ($CFG->admin !== 'admin' && strpos($dir, 'admin/') === 0) {
666
                $dir = preg_replace('|^admin/|', "$CFG->admin/", $dir);
969
                    $dir = preg_replace('|^admin/|', "$CFG->admin/", $dir);
667
            }
970
                }
668
            if (!is_dir("$CFG->dirroot/$dir")) {
971
                if (!is_dir("$CFG->dirroot/$dir")) {
-
 
972
                    error_log("Invalid subtype directory '$dir' detected in '$ownerdir'.");
-
 
973
                    continue;
669
                error_log("Invalid subtype directory '$dir' detected in '$ownerdir'.");
974
                }
670
                continue;
-
 
671
            }
975
                $types[$key][$subtype] = "$CFG->dirroot/$dir";
Línea 672... Línea 976...
672
            $types[$subtype] = "$CFG->dirroot/$dir";
976
            }
673
        }
977
        }
Línea 696... Línea 1000...
696
 
1000
 
697
        foreach ($fulldirs as $fulldir) {
1001
        foreach ($fulldirs as $fulldir) {
698
            if (!is_dir($fulldir)) {
1002
            if (!is_dir($fulldir)) {
699
                continue;
1003
                continue;
700
            }
1004
            }
701
            $items = new \DirectoryIterator($fulldir);
1005
            $items = new DirectoryIterator($fulldir);
702
            foreach ($items as $item) {
1006
            foreach ($items as $item) {
703
                if ($item->isDot() || !$item->isDir()) {
1007
                if ($item->isDot() || !$item->isDir()) {
704
                    continue;
1008
                    continue;
705
                }
1009
                }
Línea 730... Línea 1034...
730
        global $CFG;
1034
        global $CFG;
Línea 731... Línea 1035...
731
 
1035
 
Línea 732... Línea 1036...
732
        self::$classmap = [];
1036
        self::$classmap = [];
-
 
1037
 
Línea 733... Línea 1038...
733
 
1038
        self::load_classes('core', "$CFG->dirroot/lib/classes");
734
        self::load_classes('core', "$CFG->dirroot/lib/classes");
1039
        self::load_legacy_classes($CFG->libdir, true);
735
 
1040
 
736
        foreach (self::$subsystems as $subsystem => $fulldir) {
1041
        foreach (self::$subsystems as $subsystem => $fulldir) {
Línea 741... Línea 1046...
741
        }
1046
        }
Línea 742... Línea 1047...
742
 
1047
 
743
        foreach (self::$plugins as $plugintype => $plugins) {
1048
        foreach (self::$plugins as $plugintype => $plugins) {
744
            foreach ($plugins as $pluginname => $fulldir) {
1049
            foreach ($plugins as $pluginname => $fulldir) {
-
 
1050
                self::load_classes($plugintype . '_' . $pluginname, "$fulldir/classes");
745
                self::load_classes($plugintype . '_' . $pluginname, "$fulldir/classes");
1051
                self::load_legacy_classes($fulldir);
746
            }
1052
            }
-
 
1053
        }
-
 
1054
 
-
 
1055
        // Include deprecated plugins in the classmap, to facilitate migration code which uses existing plugin classes.
-
 
1056
        foreach (self::$deprecatedplugins as $plugintype => $plugins) {
-
 
1057
            foreach ($plugins as $pluginname => $fulldir) {
-
 
1058
                self::load_classes($plugintype . '_' . $pluginname, "$fulldir/classes");
-
 
1059
            }
-
 
1060
        }
747
        }
1061
 
748
        ksort(self::$classmap);
1062
        ksort(self::$classmap);
Línea 749... Línea 1063...
749
    }
1063
    }
750
 
1064
 
Línea 792... Línea 1106...
792
            // because its pretty likely to lead to a missing class error further down the line.
1106
            // because its pretty likely to lead to a missing class error further down the line.
793
            // But our early setup code can't handle errors this early at the moment.
1107
            // But our early setup code can't handle errors this early at the moment.
794
            return;
1108
            return;
795
        }
1109
        }
Línea 796... Línea 1110...
796
 
1110
 
797
        $items = new \DirectoryIterator($fulldir);
1111
        $items = new DirectoryIterator($fulldir);
798
        foreach ($items as $item) {
1112
        foreach ($items as $item) {
799
            if ($item->isDot()) {
1113
            if ($item->isDot()) {
800
                continue;
1114
                continue;
801
            }
1115
            }
Línea 868... Línea 1182...
868
        self::init();
1182
        self::init();
869
        return self::$plugintypes;
1183
        return self::$plugintypes;
870
    }
1184
    }
Línea 871... Línea 1185...
871
 
1185
 
-
 
1186
    /**
-
 
1187
     * Get a list of deprecated plugin types and their locations.
-
 
1188
     *
-
 
1189
     * @return array as (string)plugintype => (string)fulldir
-
 
1190
     */
-
 
1191
    public static function get_deprecated_plugin_types(): array {
-
 
1192
        self::init();
-
 
1193
        return self::$deprecatedplugintypes;
-
 
1194
    }
-
 
1195
 
-
 
1196
    /**
-
 
1197
     * Get a list of all deleted plugin types and their locations.
-
 
1198
     *
-
 
1199
     * @return array as (string)plugintype => (string)fulldir
-
 
1200
     */
-
 
1201
    public static function get_deleted_plugin_types(): array {
-
 
1202
        self::init();
-
 
1203
        return self::$deletedplugintypes;
-
 
1204
    }
-
 
1205
 
-
 
1206
    /**
-
 
1207
     * Gets list of all plugin types, comprising available plugin types as well as any plugin types currently in deprecation.
-
 
1208
     *
-
 
1209
     * @return array as (string)plugintype => (string)fulldir
-
 
1210
     */
-
 
1211
    public static function get_all_plugin_types(): array {
-
 
1212
        self::init();
-
 
1213
        return array_merge(self::$plugintypes, self::$deprecatedplugintypes, self::$deletedplugintypes);
-
 
1214
    }
-
 
1215
 
-
 
1216
    /**
-
 
1217
     * Is the plugintype deprecated.
-
 
1218
     *
-
 
1219
     * @param string $plugintype
-
 
1220
     * @return bool true if deprecated, false otherwise.
-
 
1221
     */
-
 
1222
    public static function is_deprecated_plugin_type(string $plugintype): bool {
-
 
1223
        self::init();
-
 
1224
        return array_key_exists($plugintype, self::$deprecatedplugintypes);
-
 
1225
    }
-
 
1226
 
-
 
1227
    /**
-
 
1228
     * Is the plugintype deleted.
-
 
1229
     *
-
 
1230
     * @param string $plugintype
-
 
1231
     * @return bool true if deleted, false otherwise.
-
 
1232
     */
-
 
1233
    public static function is_deleted_plugin_type(string $plugintype): bool {
-
 
1234
        self::init();
-
 
1235
        return array_key_exists($plugintype, self::$deletedplugintypes);
-
 
1236
    }
-
 
1237
 
-
 
1238
    /**
-
 
1239
     * Is the plugintype in deprecation.
-
 
1240
     *
-
 
1241
     * @param string $plugintype
-
 
1242
     * @return bool true if in either phase 1 (deprecated) or phase 2 (deleted) or deprecation.
-
 
1243
     */
-
 
1244
    public static function is_plugintype_in_deprecation(string $plugintype): bool {
-
 
1245
        self::init();
-
 
1246
        return array_key_exists($plugintype, array_merge(self::$deprecatedplugintypes, self::$deletedplugintypes));
-
 
1247
    }
-
 
1248
 
872
    /**
1249
    /**
873
     * Get list of plugins of given type.
1250
     * Get list of plugins of given type.
874
     *
1251
     *
875
     * @param string $plugintype
1252
     * @param string $plugintype
876
     * @return array as (string)pluginname => (string)fulldir
1253
     * @return array as (string)pluginname => (string)fulldir
Línea 883... Línea 1260...
883
        }
1260
        }
884
        return self::$plugins[$plugintype];
1261
        return self::$plugins[$plugintype];
885
    }
1262
    }
Línea 886... Línea 1263...
886
 
1263
 
-
 
1264
    /**
-
 
1265
     * Get list of deprecated plugins of a given type.
-
 
1266
     *
-
 
1267
     * @param string $plugintype
-
 
1268
     * @return array as (string)pluginname => (string)fulldir
-
 
1269
     */
-
 
1270
    public static function get_deprecated_plugin_list($plugintype): array {
-
 
1271
        self::init();
-
 
1272
        return self::$deprecatedplugins[$plugintype] ?? [];
-
 
1273
    }
-
 
1274
 
-
 
1275
    /**
-
 
1276
     * Get list of deleted plugins of a given type.
-
 
1277
     *
-
 
1278
     * @param string $plugintype
-
 
1279
     * @return array as (string)pluginname => (string)fulldir
-
 
1280
     */
-
 
1281
    public static function get_deleted_plugin_list($plugintype): array {
-
 
1282
        self::init();
-
 
1283
        return self::$deletedplugins[$plugintype] ?? [];
-
 
1284
    }
-
 
1285
 
-
 
1286
    /**
-
 
1287
     * Get list of all plugins of a given type, comprising all available plugins as well as any plugins in deprecation.
-
 
1288
     *
-
 
1289
     * @param string $plugintype
-
 
1290
     * @return array as (string)pluginname => (string)fulldir
-
 
1291
     */
-
 
1292
    public static function get_all_plugins_list(string $plugintype): array {
-
 
1293
        self::init();
-
 
1294
        return array_merge(
-
 
1295
            self::$plugins[$plugintype] ?? [],
-
 
1296
            self::$deprecatedplugins[$plugintype] ?? [],
-
 
1297
            self::$deletedplugins[$plugintype] ?? []
-
 
1298
        );
-
 
1299
    }
-
 
1300
 
887
    /**
1301
    /**
888
     * Get a list of all the plugins of a given type that define a certain class
1302
     * Get a list of all the plugins of a given type that define a certain class
889
     * in a certain file. The plugin component names and class names are returned.
1303
     * in a certain file. The plugin component names and class names are returned.
890
     *
1304
     *
891
     * @param string $plugintype the type of plugin, e.g. 'mod' or 'report'.
1305
     * @param string $plugintype the type of plugin, e.g. 'mod' or 'report'.
Línea 1034... Línea 1448...
1034
            return null;
1448
            return null;
1035
        }
1449
        }
Línea 1036... Línea 1450...
1036
 
1450
 
Línea 1037... Línea 1451...
1037
        self::init();
1451
        self::init();
1038
 
1452
 
1039
        if (!isset(self::$plugins[$plugintype][$pluginname])) {
1453
        if (!isset(self::$plugins[$plugintype][$pluginname]) && !isset(self::$deprecatedplugins[$plugintype][$pluginname])) {
1040
            return null;
1454
            return null;
1041
        }
1455
        }
Línea 1042... Línea 1456...
1042
        return self::$plugins[$plugintype][$pluginname];
1456
        return self::$plugins[$plugintype][$pluginname] ?? self::$deprecatedplugins[$plugintype][$pluginname];
1043
    }
1457
    }
1044
 
1458
 
Línea 1139... Línea 1553...
1139
     *
1553
     *
1140
     * @param string $classname
1554
     * @param string $classname
1141
     * @return null|string The component name, or null if a matching component was not found
1555
     * @return null|string The component name, or null if a matching component was not found
1142
     */
1556
     */
1143
    public static function get_component_from_classname(string $classname): ?string {
1557
    public static function get_component_from_classname(string $classname): ?string {
1144
        $components = static::get_component_names(true);
1558
        $components = static::get_component_names(true, true);
Línea 1145... Línea 1559...
1145
 
1559
 
Línea 1146... Línea 1560...
1146
        $classname = ltrim($classname, '\\');
1560
        $classname = ltrim($classname, '\\');
1147
 
1561
 
Línea 1197... Línea 1611...
1197
    }
1611
    }
Línea 1198... Línea 1612...
1198
 
1612
 
1199
    /**
1613
    /**
1200
     * Returns parent of this subplugin type.
1614
     * Returns parent of this subplugin type.
-
 
1615
     *
-
 
1616
     * No filtering is done on deprecated/deleted subtypes. Calling code should check this if needed.
1201
     *
1617
     *
1202
     * @param string $type
1618
     * @param string $type
1203
     * @return string parent component or null
1619
     * @return string parent component or null
1204
     */
1620
     */
1205
    public static function get_subtype_parent($type) {
1621
    public static function get_subtype_parent($type) {
Línea 1211... Línea 1627...
1211
 
1627
 
1212
        return null;
1628
        return null;
Línea 1213... Línea 1629...
1213
    }
1629
    }
1214
 
1630
 
1215
    /**
1631
    /**
1216
     * Return all subplugins of this component.
1632
     * Return all available subplugins of this component.
1217
     * @param string $component.
1633
     * @param string $component.
1218
     * @return array $subtype=>array($component, ..), null if no subtypes defined
1634
     * @return array $subtype=>array($component, ..), null if no subtypes defined
1219
     */
1635
     */
Línea 1226... Línea 1642...
1226
 
1642
 
1227
        return null;
1643
        return null;
Línea 1228... Línea 1644...
1228
    }
1644
    }
-
 
1645
 
-
 
1646
    /**
-
 
1647
     * Return all subplugins for the component, comprising all available subplugins plus any in deprecation.
-
 
1648
     *
-
 
1649
     * @param string $component
-
 
1650
     * @return array|null $subtype=>array($component, ..), null if no subtypes defined
-
 
1651
     */
-
 
1652
    public static function get_all_subplugins($component): ?array {
-
 
1653
        self::init();
-
 
1654
        $subplugins = array_merge(
-
 
1655
            self::$subplugins[$component] ?? [],
-
 
1656
            self::$deprecatedsubplugins[$component] ?? [],
-
 
1657
            self::$deletedsubplugins[$component] ?? [],
-
 
1658
        );
-
 
1659
        return $subplugins ?: null;
-
 
1660
    }
1229
 
1661
 
1230
    /**
1662
    /**
1231
     * Returns hash of all versions including core and all plugins.
1663
     * Returns hash of all versions including core and all plugins.
1232
     *
1664
     *
1233
     * This is relatively slow and not fully cached, use with care!
1665
     * This is relatively slow and not fully cached, use with care!
Línea 1442... Línea 1874...
1442
            }
1874
            }
1443
        }
1875
        }
1444
    }
1876
    }
Línea 1445... Línea 1877...
1445
 
1877
 
-
 
1878
    /**
-
 
1879
     * Load legacy classes based upon the db/legacyclasses.php file.
-
 
1880
     *
-
 
1881
     * The legacyclasses.php should contain a key => value array ($legacyclasses) where the key is the class name,
-
 
1882
     * and the value is the path to the class file within the relative ../classes/ directory.
-
 
1883
     *
-
 
1884
     * @param string|null $fulldir The directory to the legacy classes.
-
 
1885
     * @param bool $allowsubsystems Whether to allow the specification of alternative subsystems for this path.
-
 
1886
     */
-
 
1887
    protected static function load_legacy_classes(
-
 
1888
        ?string $fulldir,
-
 
1889
        bool $allowsubsystems = false,
-
 
1890
    ): void {
-
 
1891
        if (is_null($fulldir)) {
-
 
1892
            return;
-
 
1893
        }
-
 
1894
 
-
 
1895
        $file = $fulldir . '/db/legacyclasses.php';
-
 
1896
        if (is_readable($file)) {
-
 
1897
            $legacyclasses = null;
-
 
1898
            require($file);
-
 
1899
            if (is_array($legacyclasses)) {
-
 
1900
                foreach ($legacyclasses as $classname => $path) {
-
 
1901
                    if (is_array($path)) {
-
 
1902
                        if (!$allowsubsystems) {
-
 
1903
                            throw new Exception(
-
 
1904
                                "Invalid legacy classes path entry for {$classname}. " .
-
 
1905
                                    "Only files within the component can be specified.",
-
 
1906
                            );
-
 
1907
                        }
-
 
1908
                        if (count($path) !== 2) {
-
 
1909
                            throw new Exception(
-
 
1910
                                "Invalid legacy classes path entry for {$classname}. " .
-
 
1911
                                    "Entries must be in the format [subsystem, path].",
-
 
1912
                            );
-
 
1913
                        }
-
 
1914
                        [$subsystem, $path] = $path;
-
 
1915
                        $subsystem = substr($subsystem, 5);
-
 
1916
                        if (!array_key_exists($subsystem, self::$subsystems)) {
-
 
1917
                            throw new Exception(
-
 
1918
                                "Unknown subsystem '{$subsystem}' for legacy classes entry of '{$classname}'",
-
 
1919
                            );
-
 
1920
                        }
-
 
1921
 
-
 
1922
                        $subsystemfulldir = self::$subsystems[$subsystem];
-
 
1923
                        self::$classmap[$classname] = "{$subsystemfulldir}/classes/{$path}";
-
 
1924
                    } else {
-
 
1925
                        self::$classmap[$classname] = "{$fulldir}/classes/{$path}";
-
 
1926
                    }
-
 
1927
                }
-
 
1928
            }
-
 
1929
        }
-
 
1930
    }
-
 
1931
 
1446
    /**
1932
    /**
1447
     * Returns a list of frankenstyle component names and their paths, for all components (plugins and subsystems).
1933
     * Returns a list of frankenstyle component names and their paths, for all components (plugins and subsystems).
1448
     *
1934
     *
1449
     * E.g.
1935
     * E.g.
1450
     *  [
1936
     *  [
Línea 1481... Línea 1967...
1481
     * Returns a list of frankenstyle component names, including all plugins, subplugins, and subsystems.
1967
     * Returns a list of frankenstyle component names, including all plugins, subplugins, and subsystems.
1482
     *
1968
     *
1483
     * Note: By default the 'core' subsystem is not included.
1969
     * Note: By default the 'core' subsystem is not included.
1484
     *
1970
     *
1485
     * @param bool $includecore Whether to include the 'core' subsystem
1971
     * @param bool $includecore Whether to include the 'core' subsystem
-
 
1972
     * @param bool $includedeprecated Whether to include deprecated components
1486
     * @return string[] the list of frankenstyle component names.
1973
     * @return string[] the list of frankenstyle component names.
1487
     */
1974
     */
1488
    public static function get_component_names(
1975
    public static function get_component_names(
1489
        bool $includecore = false,
1976
        bool $includecore = false,
-
 
1977
        bool $includedeprecated = false
1490
    ): array {
1978
    ): array {
1491
        $componentnames = [];
1979
        $componentnames = [];
1492
        // Get all plugins.
1980
        // Get all plugins.
1493
        foreach (self::get_plugin_types() as $plugintype => $typedir) {
1981
        foreach (self::get_plugin_types() as $plugintype => $typedir) {
1494
            foreach (self::get_plugin_list($plugintype) as $pluginname => $plugindir) {
1982
            foreach (self::get_plugin_list($plugintype) as $pluginname => $plugindir) {
Línea 1502... Línea 1990...
1502
 
1990
 
1503
        if ($includecore) {
1991
        if ($includecore) {
1504
            $componentnames[] = 'core';
1992
            $componentnames[] = 'core';
Línea -... Línea 1993...
-
 
1993
        }
-
 
1994
 
-
 
1995
        if ($includedeprecated) {
-
 
1996
            foreach (self::get_deprecated_plugin_types() as $plugintype => $typedir) {
-
 
1997
                foreach (self::get_deprecated_plugin_list($plugintype) as $pluginname => $plugindir) {
-
 
1998
                    $componentnames[] = $plugintype . '_' . $pluginname;
-
 
1999
                }
-
 
2000
            }
1505
        }
2001
        }
1506
 
2002
 
Línea 1507... Línea 2003...
1507
        return $componentnames;
2003
        return $componentnames;
1508
    }
2004
    }
Línea 1525... Línea 2021...
1525
     * @param string $plugintype The plugin type.
2021
     * @param string $plugintype The plugin type.
1526
     * @param string $pluginname The plugin name.
2022
     * @param string $pluginname The plugin name.
1527
     * @return bool True if the plugin has a monologo icon
2023
     * @return bool True if the plugin has a monologo icon
1528
     */
2024
     */
1529
    public static function has_monologo_icon(string $plugintype, string $pluginname): bool {
2025
    public static function has_monologo_icon(string $plugintype, string $pluginname): bool {
-
 
2026
        global $PAGE;
1530
        $plugindir = self::get_plugin_directory($plugintype, $pluginname);
2027
        $plugindir = self::get_plugin_directory($plugintype, $pluginname);
1531
        if ($plugindir === null) {
2028
        if ($plugindir === null) {
1532
            return false;
2029
            return false;
1533
        }
2030
        }
-
 
2031
        $theme = theme_config::load($PAGE->theme->name);
-
 
2032
        $component = self::normalize_componentname("{$plugintype}_{$pluginname}");
-
 
2033
        $hassvgmonologo = $theme->resolve_image_location('monologo', $component, true) !== null;
-
 
2034
        $haspngmonologo = $theme->resolve_image_location('monologo', $component) !== null;
1534
        return file_exists("$plugindir/pix/monologo.svg") || file_exists("$plugindir/pix/monologo.png");
2035
        return $haspngmonologo || $hassvgmonologo;
1535
    }
2036
    }
1536
}
2037
}
-
 
2038
 
-
 
2039
// Alias this class to the old name.
-
 
2040
// This should be kept here because we use this class in external tooling.
-
 
2041
class_alias(component::class, \core_component::class);