This commit is contained in:
Ilya Tregubov
2024-04-10 14:30:31 +08:00
15 changed files with 707 additions and 40 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -43,8 +43,8 @@ const findMatchingTour = (tourDetails, filters) => {
*/
export const init = async(tourDetails, filters) => {
const requirements = [];
filters.forEach(filter => {
requirements.push(import(`tool_usertours/filter_${filter}`));
filters.forEach((filter) => {
requirements.push(import(filter));
});
const filterPlugins = await Promise.all(requirements);
+48 -16
View File
@@ -16,6 +16,7 @@
namespace tool_usertours;
use coding_exception;
use core\output\inplace_editable;
/**
@@ -534,10 +535,7 @@ class helper {
];
}, $tours);
$filternames = [];
foreach ($filters as $filter) {
$filternames[] = $filter::get_filter_name();
}
$filternames = self::get_clientside_filter_module_names($filters);
$PAGE->requires->js_call_amd('tool_usertours/usertours', 'init', [
$tourdetails,
@@ -546,19 +544,48 @@ class helper {
}
}
/**
* Get the JS module names for the filters.
*
* @param array $filters
* @return array
* @throws coding_exception
*/
public static function get_clientside_filter_module_names(array $filters): array {
$filternames = [];
foreach ($filters as $filter) {
if ($component = \core_component::get_component_from_classname($filter)) {
$filternames[] = sprintf(
"%s/filter_%s",
$component,
$filter::get_filter_name(),
);
} else {
throw new \coding_exception("Could not determine component for filter class {$filter}");
}
}
return $filternames;
}
/**
* Get a list of all possible filters.
*
* @return array
*/
public static function get_all_filters() {
$filters = \core_component::get_component_classes_in_namespace('tool_usertours', 'local\filter');
$filters = array_keys($filters);
$hook = new hook\before_serverside_filter_fetch(array_keys(
\core_component::get_component_classes_in_namespace('tool_usertours', 'local\filter')
));
\core\di::get(\core\hook\manager::class)->dispatch($hook);
$filters = array_filter($filters, function ($filterclass) {
$rc = new \ReflectionClass($filterclass);
return $rc->isInstantiable();
});
$filters = array_filter(
$hook->get_filter_list(),
function ($filterclass) {
$rc = new \ReflectionClass($filterclass);
return $rc->isInstantiable();
}
);
$filters = array_merge($filters, static::get_all_clientside_filters());
@@ -571,13 +598,18 @@ class helper {
* @return array
*/
public static function get_all_clientside_filters() {
$filters = \core_component::get_component_classes_in_namespace('tool_usertours', 'local\clientside_filter');
$filters = array_keys($filters);
$hook = new hook\before_clientside_filter_fetch(array_keys(
\core_component::get_component_classes_in_namespace('tool_usertours', 'local\clientside_filter')
));
\core\di::get(\core\hook\manager::class)->dispatch($hook);
$filters = array_filter($filters, function ($filterclass) {
$rc = new \ReflectionClass($filterclass);
return $rc->isInstantiable();
});
$filters = array_filter(
$hook->get_filter_list(),
function ($filterclass) {
$rc = new \ReflectionClass($filterclass);
return $rc->isInstantiable();
}
);
return $filters;
}
@@ -0,0 +1,74 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace tool_usertours\hook;
/**
* Provides the ability to add and remove custom client-side filters to the user tour filter list.
*
* @package tool_usertours
* @copyright 2024 Andrew Lyons <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
#[\core\attribute\label('Provides the ability to add and remove custom client-side filters to the user tour filter list.')]
#[\core\attribute\tags('tool_usertours')]
class before_clientside_filter_fetch {
/**
* Create a new instance of the hook.
*
* @param array $filters
*/
public function __construct(
/** @var array The list of filters applied */
protected array $filters,
) {
}
/**
* Add a filter classname to the list of filters to be processed.
*
* @param string $classname
* @return self
*/
public function add_filter_by_classname(string $classname): self {
if (!\is_a($classname, \tool_usertours\local\clientside_filter\clientside_filter::class, true)) {
throw new \coding_exception("Invalid clientside filter class {$classname}");
}
$this->filters[] = $classname;
return $this;
}
/**
* Remove a filter classname from the list of filters to be processed.
*
* @param string $classname
* @return self
*/
public function remove_filter_by_classname(string $classname): self {
$this->filters = array_filter($this->filters, fn($filter) => $filter !== $classname);
return $this;
}
/**
* Get the list of filters to be processed.
*
* @return array
*/
public function get_filter_list(): array {
return $this->filters;
}
}
@@ -0,0 +1,78 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace tool_usertours\hook;
/**
* Provides the ability to add and remove custom server-side filters to the user tour filter list.
*
* @package tool_usertours
* @copyright 2024 Andrew Lyons <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
#[\core\attribute\label('Provides the ability to add and remove custom server-side filters to the user tour filter list.')]
#[\core\attribute\tags('tool_usertours')]
class before_serverside_filter_fetch {
/**
* Create a new instance of the hook.
*
* @param array $filters
*/
public function __construct(
/** @var array The list of filters applied */
protected array $filters,
) {
}
/**
* Add a filter classname to the list of filters to be processed.
*
* @param string $classname
* @return self
*/
public function add_filter_by_classname(string $classname): self {
if (!\is_a($classname, \tool_usertours\local\filter\base::class, true)) {
throw new \coding_exception("Invalid filter class {$classname}");
}
if (\is_a($classname, \tool_usertours\local\clientside_filter\clientside_filter::class, true)) {
throw new \coding_exception("Invalid filter class {$classname} (client-side filter for server-side hook)");
}
$this->filters[] = $classname;
return $this;
}
/**
* Remove a filter classname from the list of filters to be processed.
*
* @param string $classname
* @return self
*/
public function remove_filter_by_classname(string $classname): self {
$this->filters = array_filter($this->filters, fn($filter) => $filter !== $classname);
return $this;
}
/**
* Get the list of filters to be processed.
*
* @return array
*/
public function get_filter_list(): array {
return $this->filters;
}
}
@@ -0,0 +1,45 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Hook fixtures for testing of hooks.
*
* @package tool_usertours
* @copyright 2024 Andrew Lyons <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_usertours\test\hook\clientside_filter_for_serverside_hook;
defined('MOODLE_INTERNAL') || die();
final class filter_class extends \tool_usertours\local\clientside_filter\clientside_filter {
}
final class callback {
public static function callme(
\tool_usertours\hook\before_serverside_filter_fetch $hook
): void {
$hook->add_filter_by_classname(filter_class::class);
}
}
$callbacks = [
[
'hook' => \tool_usertours\hook\before_serverside_filter_fetch::class,
'callback' => callback::class . '::callme',
],
];
+61
View File
@@ -0,0 +1,61 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Hook fixtures for testing of hooks.
*
* @package tool_usertours
* @copyright 2024 Andrew Lyons <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_usertours\test\hook;
defined('MOODLE_INTERNAL') || die();
final class serverside_filter_fixture extends \tool_usertours\local\filter\base {
}
final class clientside_filter_fixture extends \tool_usertours\local\clientside_filter\clientside_filter {
}
final class hook_fixtures {
public static function example_serverside_hook(
\tool_usertours\hook\before_serverside_filter_fetch $hook
): void {
// Add a valid serverside and an invalid clientside filter.
$hook->add_filter_by_classname(\tool_usertours\test\hook\serverside_filter_fixture::class);
$hook->remove_filter_by_classname(\tool_usertours\local\filter\accessdate::class);
}
public static function example_clientside_hook(
\tool_usertours\hook\before_clientside_filter_fetch $hook
): void {
$hook->add_filter_by_classname(\tool_usertours\test\hook\clientside_filter_fixture::class);
$hook->remove_filter_by_classname(\tool_usertours\local\clientside_filter\cssselector::class);
}
}
$callbacks = [
[
'hook' => \tool_usertours\hook\before_serverside_filter_fetch::class,
'callback' => \tool_usertours\test\hook\hook_fixtures::class . '::example_serverside_hook',
],
[
'hook' => \tool_usertours\hook\before_clientside_filter_fetch::class,
'callback' => \tool_usertours\test\hook\hook_fixtures::class . '::example_clientside_hook',
],
];
@@ -0,0 +1,43 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Hook fixtures for testing of hooks.
*
* @package tool_usertours
* @copyright 2024 Andrew Lyons <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
final class nocomponent_clientside_filter_fixture extends \tool_usertours\local\clientside_filter\clientside_filter {
}
final class nocomponent_clientside_hook_fixtures {
public static function example_clientside_hook(
\tool_usertours\hook\before_clientside_filter_fetch $hook
): void {
$hook->add_filter_by_classname(\nocomponent_clientside_filter_fixture::class);
}
}
$callbacks = [
[
'hook' => \tool_usertours\hook\before_clientside_filter_fetch::class,
'callback' => \nocomponent_clientside_hook_fixtures::class . '::example_clientside_hook',
],
];
@@ -0,0 +1,43 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Hook fixtures for testing of hooks.
*
* @package tool_usertours
* @copyright 2024 Andrew Lyons <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
final class nocomponent_serverside_filter_fixture {
}
final class nocomponent_serverside_hook_fixtures {
public static function example_serverside_hook(
\tool_usertours\hook\before_serverside_filter_fetch $hook
): void {
$hook->add_filter_by_classname(\nocomponent_serverside_filter_fixture::class);
}
}
$callbacks = [
[
'hook' => \tool_usertours\hook\before_serverside_filter_fetch::class,
'callback' => \nocomponent_serverside_hook_fixtures::class . '::example_serverside_hook',
],
];
@@ -0,0 +1,45 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Hook fixtures for testing of hooks.
*
* @package tool_usertours
* @copyright 2024 Andrew Lyons <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace tool_usertours\test\hook\serverside_filter_for_clientside_hook;
defined('MOODLE_INTERNAL') || die();
final class filter_class extends \tool_usertours\local\filter\base {
}
final class callback {
public static function callme(
\tool_usertours\hook\before_clientside_filter_fetch $hook
): void {
$hook->add_filter_by_classname(filter_class::class);
}
}
$callbacks = [
[
'hook' => \tool_usertours\hook\before_clientside_filter_fetch::class,
'callback' => callback::class . '::callme',
],
];
+118 -4
View File
@@ -16,17 +16,18 @@
namespace tool_usertours;
use advanced_testcase;
/**
* Tests for helper.
*
* @package tool_usertours
* @category test
* @copyright 2022 Huong Nguyen <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \tool_usertours\helper
* @covers \tool_usertours\helper
* @covers \tool_usertours\hook\before_serverside_filter_fetch
* @covers \tool_usertours\hook\before_clientside_filter_fetch
*/
class helper_test extends advanced_testcase {
final class helper_test extends \advanced_testcase {
/**
* Data Provider for get_string_from_input.
*
@@ -71,4 +72,117 @@ class helper_test extends advanced_testcase {
public function test_get_string_from_input($string, $expected): void {
$this->assertEquals($expected, helper::get_string_from_input($string));
}
public function test_get_all_filters(): void {
$filters = helper::get_all_filters();
$this->assertIsArray($filters);
array_map(
function ($filter) {
$this->assertIsString($filter);
$this->assertTrue(class_exists($filter));
$this->assertTrue(is_a($filter, \tool_usertours\local\filter\base::class, true));
$rc = new \ReflectionClass($filter);
$this->assertTrue($rc->isInstantiable());
},
$filters,
);
$this->assertNotContains(\tool_usertours\test\hook\serverside_filter_fixture::class, $filters);
$this->assertNotContains(\tool_usertours\test\hook\clientside_filter_fixture::class, $filters);
$this->assertContains(\tool_usertours\local\filter\accessdate::class, $filters);
$this->assertContains(\tool_usertours\local\clientside_filter\cssselector::class, $filters);
$filters = helper::get_all_clientside_filters();
array_map(
function ($filter) {
$this->assertIsString($filter);
},
$filters,
);
}
public function test_get_invalid_server_filter(): void {
\core\di::set(
\core\hook\manager::class,
\core\hook\manager::phpunit_get_instance([
'test_plugin1' => __DIR__ . '/fixtures/invalid_serverside_hook_fixture.php',
]),
);
$this->expectException(\coding_exception::class);
helper::get_all_filters();
}
public function test_clientside_filter_for_serverside_hook(): void {
\core\di::set(
\core\hook\manager::class,
\core\hook\manager::phpunit_get_instance([
'test_plugin1' => __DIR__ . '/fixtures/clientside_filter_for_serverside_hook.php',
]),
);
$this->expectException(\coding_exception::class);
helper::get_all_filters();
}
public function test_serverside_filter_for_clientside_hook(): void {
\core\di::set(
\core\hook\manager::class,
\core\hook\manager::phpunit_get_instance([
'test_plugin1' => __DIR__ . '/fixtures/serverside_filter_for_clientside_hook.php',
]),
);
$this->expectException(\coding_exception::class);
helper::get_all_clientside_filters();
}
public function test_filter_hooks(): void {
\core\di::set(
\core\hook\manager::class,
\core\hook\manager::phpunit_get_instance([
'test_plugin1' => __DIR__ . '/fixtures/hook_fixtures.php',
]),
);
$filters = helper::get_all_filters();
$this->assertIsArray($filters);
// Check the modifications from the serverside hook.
$this->assertContains(\tool_usertours\test\hook\serverside_filter_fixture::class, $filters);
$this->assertNotContains(\tool_usertours\test\hook\another_clientside_filter_fixture::class, $filters);
$this->assertNotContains(\tool_usertours\local\filter\accessdate::class, $filters);
// Check the modifications from the clientside hook.
$this->assertContains(\tool_usertours\test\hook\clientside_filter_fixture::class, $filters);
$this->assertNotContains(\tool_usertours\test\hook\another_serverside_filter_fixture::class, $filters);
$this->assertNotContains(\tool_usertours\local\clientside_filter\cssselector::class, $filters);
array_map(
function ($filter) {
$this->assertIsString($filter);
$this->assertTrue(class_exists($filter));
$this->assertTrue(is_a($filter, \tool_usertours\local\filter\base::class, true));
$rc = new \ReflectionClass($filter);
$this->assertTrue($rc->isInstantiable());
},
$filters,
);
}
public function test_get_clientside_filter_module_names(): void {
\core\di::set(
\core\hook\manager::class,
\core\hook\manager::phpunit_get_instance([
'test_plugin1' => __DIR__ . '/fixtures/invalid_clientside_hook_fixture.php',
]),
);
$filters = helper::get_all_clientside_filters();
$this->expectException(\coding_exception::class);
$this->expectExceptionMessageMatches('/Could not determine component/');
helper::get_clientside_filter_module_names($filters);
}
}
+7
View File
@@ -1,5 +1,12 @@
This files describes API changes in the tool_usertours code.
=== 4.4 ===
* New hooks have been provided to allow plugins to define their own server-side, and client-side user tour filters.
The new hooks are named:
- \tool_usertours\hook\before_serverside_filter_fetch
- \tool_usertours\hook\before_clientside_filter_fetch
These hooks allow addition, and removal, of filters.
=== 4.0 ===
* The `tourconfig` property returned by the `tool_usertours_fetch_and_start_tour`
external method has also an `endtourlabel` property that contains the label to be used
+42 -10
View File
@@ -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.
*
@@ -1407,18 +1436,16 @@ $cache = ' . var_export($cache, true) . ';
}
/**
* Returns a list of frankenstyle component names.
* Returns a list of frankenstyle component names, including all plugins, subplugins, and subsystems.
*
* E.g.
* [
* 'core_course',
* 'core_message',
* 'mod_assign',
* ...
* ]
* @return array the list of frankenstyle component names.
* Note: By default the 'core' subsystem is not included.
*
* @param bool $includecore Whether to include the 'core' subsystem
* @return string[] the list of frankenstyle component names.
*/
public static function get_component_names(): array {
public static function get_component_names(
bool $includecore = false,
): array {
$componentnames = [];
// Get all plugins.
foreach (self::get_plugin_types() as $plugintype => $typedir) {
@@ -1430,6 +1457,11 @@ $cache = ' . var_export($cache, true) . ';
foreach (self::get_core_subsystems() as $subsystemname => $subsystempath) {
$componentnames[] = 'core_' . $subsystemname;
}
if ($includecore) {
$componentnames[] = 'core';
}
return $componentnames;
}
+99 -6
View File
@@ -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) {
@@ -873,22 +940,31 @@ class component_test extends advanced_testcase {
/**
* Test the get_component_names() method.
*
* @dataProvider get_component_names_provider
* @param bool $includecore Whether to include core in the list.
* @param bool $coreexpected Whether core is expected to be in the list.
*/
public function test_get_component_names(): void {
public function test_get_component_names(
bool $includecore,
bool $coreexpected,
): void {
global $CFG;
$componentnames = \core_component::get_component_names();
$componentnames = \core_component::get_component_names($includecore);
// We should have an entry for each plugin type.
$plugintypes = \core_component::get_plugin_types();
$numplugintypes = 0;
foreach ($plugintypes as $type => $typedir) {
foreach (\core_component::get_plugin_list($type) as $plugin) {
$numplugintypes++;
}
foreach (array_keys($plugintypes) as $type) {
$numplugintypes += count(\core_component::get_plugin_list($type));
}
// And an entry for each core subsystem.
$numcomponents = $numplugintypes + count(\core_component::get_core_subsystems());
if ($coreexpected) {
// Add one for core.
$numcomponents++;
}
$this->assertEquals($numcomponents, count($componentnames));
// Check a few of the known plugin types to confirm their presence at their respective type index.
@@ -896,6 +972,23 @@ class component_test extends advanced_testcase {
$this->assertContains('mod_forum', $componentnames);
$this->assertContains('tool_usertours', $componentnames);
$this->assertContains('core_favourites', $componentnames);
if ($coreexpected) {
$this->assertContains('core', $componentnames);
} else {
$this->assertNotContains('core', $componentnames);
}
}
/**
* Data provider for get_component_names() test.
*
* @return array
*/
public static function get_component_names_provider(): array {
return [
[false, false],
[true, true],
];
}
/**