1
0
mirror of https://github.com/moodle/moodle.git synced 2025-04-24 18:04:43 +02:00

MDL-81063 core: Add helper to get component name from classname

This commit is contained in:
Andrew Nicols 2023-12-19 22:14:09 +08:00
parent 29fc61c2a5
commit dae36f6cfa
No known key found for this signature in database
GPG Key ID: 6D1E3157C8CFBF14
2 changed files with 96 additions and 0 deletions

@ -1090,6 +1090,35 @@ $cache = ' . var_export($cache, true) . ';
return [$type, $plugin];
}
/**
* Fetch the component name from a Moodle PSR-like namespace.
*
* Note: Classnames in the flat underscore_class_name_format are not supported.
*
* @param string $classname
* @return null|string The component name, or null if a matching component was not found
*/
public static function get_component_from_classname(string $classname): ?string {
$components = static::get_component_names(true);
$classname = ltrim($classname, '\\');
// Prefer PSR-4 classnames.
$parts = explode('\\', $classname);
if ($parts) {
$component = array_shift($parts);
if (array_search($component, $components) !== false) {
return $component;
}
}
// Note: Frankenstyle classnames are not supported as they lead to false positives, for example:
// \core_typo\example => \core instead of \core_typo because it does not exist
// Please *do not* add support for Frankenstyle classnames. They will break other things.
return null;
}
/**
* Return exact absolute path to a plugin directory.
*

@ -411,6 +411,73 @@ class component_test extends advanced_testcase {
}
}
/**
* Unit tests for get_component_from_classname.
*
* @dataProvider get_component_from_classname_provider
* @param string $classname The class name to test
* @param string|null $expected The expected component
* @covers \core_component::get_component_from_classname
*/
public function test_get_component_from_classname(
string $classname,
string|null $expected,
): void {
$this->assertEquals(
$expected,
\core_component::get_component_from_classname($classname),
);
}
/**
* Data provider for get_component_from_classname tests.
*
* @return array
*/
public static function get_component_from_classname_provider(): array {
// Start off with testcases which have the leading \.
$testcases = [
// Core.
[\core\example::class, 'core'],
// A core subsystem.
[\core_message\example::class, 'core_message'],
// A fake core subsystem.
[\core_fake\example::class, null],
// A plugin.
[\mod_forum\example::class, 'mod_forum'],
// A plugin in the old style is not supported.
[\mod_forum_example::class, null],
// A fake plugin.
[\mod_fake\example::class, null],
// A subplugin.
[\tiny_link\example::class, 'tiny_link'],
];
// Duplicate the testcases, adding a nested namespace.
$testcases = array_merge(
$testcases,
array_map(
fn ($testcase) => [$testcase[0] . '\\in\\sub\\directory', $testcase[1]],
$testcases,
),
);
// Duplicate the testcases, removing the leading \.
return array_merge(
$testcases,
array_map(
fn ($testcase) => [ltrim($testcase[0], '\\'), $testcase[1]],
$testcases,
),
);
}
public function test_deprecated_get_component_directory(): void {
$plugintypes = core_component::get_plugin_types();
foreach ($plugintypes as $plugintype => $fulldir) {