From 37d2c6adc7e6ebcc2afffcd1904e00eb09b5a7bc Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Tue, 25 Nov 2025 17:55:27 +0000 Subject: [PATCH 01/39] Added method for getting differentiated labels for different delta items. Fixes #341. --- Definition/DeferredGeneratorDefinition.php | 2 +- Definition/MergingGeneratorDefinition.php | 2 +- Generator/BaseGenerator.php | 20 +++++++++++ Generator/DrushCommand.php | 8 +++++ Generator/EntityTypeBase.php | 7 ++++ Generator/Form.php | 7 ++++ Generator/FormElement.php | 8 +++++ Generator/HooksClass.php | 7 ++++ Generator/Library.php | 8 +++++ Generator/PHPUnitTest.php | 12 +++++++ Generator/Permission.php | 8 +++++ Generator/Plugin.php | 18 ++++++++++ Generator/PluginType.php | 7 ++++ Generator/RouterItem.php | 7 ++++ Generator/Service.php | 7 ++++ MutableTypedData/Data/DeltaLabelTrait.php | 35 +++++++++++++++++++ .../MergeableComplexDataWithArrayAccess.php | 2 ++ .../MergeableMutableDataWithArrayAccess.php | 2 ++ 18 files changed, 165 insertions(+), 2 deletions(-) create mode 100644 MutableTypedData/Data/DeltaLabelTrait.php diff --git a/Definition/DeferredGeneratorDefinition.php b/Definition/DeferredGeneratorDefinition.php index ab3b281c..6fdd3fc9 100644 --- a/Definition/DeferredGeneratorDefinition.php +++ b/Definition/DeferredGeneratorDefinition.php @@ -26,7 +26,7 @@ class DeferredGeneratorDefinition extends PropertyDefinition implements Generato public function __construct( string $data_type, protected string $componentType, - protected string $generatorClass, + public readonly string $generatorClass, ) { parent::__construct($data_type); } diff --git a/Definition/MergingGeneratorDefinition.php b/Definition/MergingGeneratorDefinition.php index 09d4c448..d4c71b4d 100644 --- a/Definition/MergingGeneratorDefinition.php +++ b/Definition/MergingGeneratorDefinition.php @@ -37,7 +37,7 @@ class MergingGeneratorDefinition extends PropertyDefinition implements Generator public function __construct( string $data_type, protected string $componentType, - protected string $generatorClass, + public readonly string $generatorClass, ) { parent::__construct($data_type); } diff --git a/Generator/BaseGenerator.php b/Generator/BaseGenerator.php index a8353ea2..c3aed17a 100644 --- a/Generator/BaseGenerator.php +++ b/Generator/BaseGenerator.php @@ -255,6 +255,26 @@ final public static function addBasePropertiesToPropertyDefinition(PropertyListI ]); } + /** + * Gets a diffentiated label suffix for a delta item. + * + * This allows different delta items to differentiate their labels in the UI + * with more than just a delta index. + * + * This may be called for incomplete data items (such as those added into a + * form) and so must account for even required data not being present. + * + * @param \MutableTypedData\Data\DataItem $data + * The data item to get a label suffix for. + * + * @return string|null + * The label suffix, or NULL if useful data is available. It does not need + * any initial space or separator. + */ + public static function getDifferentiatedLabelSuffix(DataItem $data): ?string { + return NULL; + } + public function isRootComponent(): bool { return FALSE; } diff --git a/Generator/DrushCommand.php b/Generator/DrushCommand.php index 6639ee44..c81a4b03 100644 --- a/Generator/DrushCommand.php +++ b/Generator/DrushCommand.php @@ -11,6 +11,7 @@ use DrupalCodeBuilder\Definition\PropertyDefinition; use DrupalCodeBuilder\Generator\Render\DocBlock; use DrupalCodeBuilder\Generator\Render\PhpAttributes; +use MutableTypedData\Data\DataItem; use MutableTypedData\Definition\DefaultDefinition; /** @@ -157,6 +158,13 @@ public static function addToGeneratorDefinition(PropertyListInterface $definitio ->setLiteralDefault(['public']); } + /** + * {@inheritdoc} + */ + public static function getDifferentiatedLabelSuffix(DataItem $data): ?string { + return $data->command_name->value ?: NULL; + } + /** * Return an array of subcomponent types. */ diff --git a/Generator/EntityTypeBase.php b/Generator/EntityTypeBase.php index e3643656..52c0ac3c 100644 --- a/Generator/EntityTypeBase.php +++ b/Generator/EntityTypeBase.php @@ -371,6 +371,13 @@ protected static function getHandlerTypes() { ]; } + /** + * {@inheritdoc} + */ + public static function getDifferentiatedLabelSuffix(DataItem $data): ?string { + return $data->entity_type_id->value ?: NULL; + } + /** * {@inheritdoc} */ diff --git a/Generator/Form.php b/Generator/Form.php index 5e6eeb01..7aa1099d 100644 --- a/Generator/Form.php +++ b/Generator/Form.php @@ -74,6 +74,13 @@ public static function addToGeneratorDefinition(PropertyListInterface $definitio ->setLiteralDefault('\Drupal\Core\Form\FormBase'); } + /** + * {@inheritdoc} + */ + public static function getDifferentiatedLabelSuffix(DataItem $data): ?string { + return $data->plain_class_name->value ?: NULL; + } + /** * {@inheritdoc} */ diff --git a/Generator/FormElement.php b/Generator/FormElement.php index d467f258..d0ff204f 100644 --- a/Generator/FormElement.php +++ b/Generator/FormElement.php @@ -4,6 +4,7 @@ use MutableTypedData\Definition\PropertyListInterface; use DrupalCodeBuilder\Definition\PropertyDefinition; +use MutableTypedData\Data\DataItem; use MutableTypedData\Definition\DefaultDefinition; use MutableTypedData\Definition\OptionsSortOrder; @@ -41,6 +42,13 @@ public static function addToGeneratorDefinition(PropertyListInterface $definitio ]); } + /** + * {@inheritdoc} + */ + public static function getDifferentiatedLabelSuffix(DataItem $data): ?string { + return $data->form_key->value ?: NULL; + } + /** * {@inheritdoc} */ diff --git a/Generator/HooksClass.php b/Generator/HooksClass.php index 30cbfabb..72664206 100644 --- a/Generator/HooksClass.php +++ b/Generator/HooksClass.php @@ -78,6 +78,13 @@ public static function addToGeneratorDefinition(PropertyListInterface $definitio ); } + /** + * {@inheritdoc} + */ + public static function getDifferentiatedLabelSuffix(DataItem $data): ?string { + return $data->plain_class_name->value ?: NULL; + } + /** * {@inheritdoc} */ diff --git a/Generator/Library.php b/Generator/Library.php index 7fdf1ea8..6ee6dbe2 100644 --- a/Generator/Library.php +++ b/Generator/Library.php @@ -6,6 +6,7 @@ use MutableTypedData\Definition\DefaultDefinition; use DrupalCodeBuilder\Definition\MergingGeneratorDefinition; use DrupalCodeBuilder\Definition\PropertyDefinition; +use MutableTypedData\Data\DataItem; /** * Generator for a module library. @@ -55,6 +56,13 @@ public static function addToGeneratorDefinition(PropertyListInterface $definitio ]); } + /** + * {@inheritdoc} + */ + public static function getDifferentiatedLabelSuffix(DataItem $data): ?string { + return $data->library_name->value ?: NULL; + } + /** * {@inheritdoc} */ diff --git a/Generator/PHPUnitTest.php b/Generator/PHPUnitTest.php index 16baf153..67d87b94 100644 --- a/Generator/PHPUnitTest.php +++ b/Generator/PHPUnitTest.php @@ -235,6 +235,18 @@ public static function addToGeneratorDefinition(PropertyListInterface $definitio $definition->getProperty('docblock_first_line')->setLiteralDefault("Test case class TODO."); } + /** + * {@inheritdoc} + */ + public static function getDifferentiatedLabelSuffix(DataItem $data): ?string { + $label = []; + $label[] = $data->test_type->value; + $label[] = $data->plain_class_name->value; + + return implode(' - ', array_filter($label)); + return $data->test_type->value ?: NULL; + } + /** * {@inheritdoc} */ diff --git a/Generator/Permission.php b/Generator/Permission.php index 720d781b..fa22883a 100644 --- a/Generator/Permission.php +++ b/Generator/Permission.php @@ -5,6 +5,7 @@ use MutableTypedData\Definition\PropertyListInterface; use MutableTypedData\Definition\DefaultDefinition; use DrupalCodeBuilder\Definition\PropertyDefinition; +use MutableTypedData\Data\DataItem; /** * Generator for module permissions on Drupal 8 and higher. @@ -46,6 +47,13 @@ public static function addToGeneratorDefinition(PropertyListInterface $definitio ]); } + /** + * {@inheritdoc} + */ + public static function getDifferentiatedLabelSuffix(DataItem $data): ?string { + return $data->permission->value ?: NULL; + } + /** * Return an array of subcomponent types. */ diff --git a/Generator/Plugin.php b/Generator/Plugin.php index e191e9ea..421f63db 100644 --- a/Generator/Plugin.php +++ b/Generator/Plugin.php @@ -5,6 +5,7 @@ use MutableTypedData\Definition\PropertyListInterface; use DrupalCodeBuilder\Definition\PropertyDefinition; use DrupalCodeBuilder\Definition\VariantGeneratorDefinition; +use MutableTypedData\Data\DataItem; use MutableTypedData\Definition\OptionsSortOrder; /** @@ -93,4 +94,21 @@ public static function addToGeneratorDefinition(PropertyListInterface $definitio ]); } + /** + * {@inheritdoc} + */ + public static function getDifferentiatedLabelSuffix(DataItem $data): ?string { + $label = []; + $label[] = $data->plugin_type->value; + + if ($data->hasProperty('plugin_label')) { + $label[] = $data->plugin_label->value; + } + else { + $label[] = $data->plugin_name->value; + } + + return implode(' - ', array_filter($label)); + } + } diff --git a/Generator/PluginType.php b/Generator/PluginType.php index 111d0b63..a414ec79 100644 --- a/Generator/PluginType.php +++ b/Generator/PluginType.php @@ -293,6 +293,13 @@ public static function addToGeneratorDefinition(PropertyListInterface $definitio } } + /** + * {@inheritdoc} + */ + public static function getDifferentiatedLabelSuffix(DataItem $data): ?string { + return $data->plugin_label->value ?: NULL; + } + /** * {@inheritdoc} */ diff --git a/Generator/RouterItem.php b/Generator/RouterItem.php index cc770f0c..c2d2ceee 100644 --- a/Generator/RouterItem.php +++ b/Generator/RouterItem.php @@ -407,6 +407,13 @@ public static function controllerRelativeClassFromRoutePath(string $path) { return $controller_class_name; } + /** + * {@inheritdoc} + */ + public static function getDifferentiatedLabelSuffix(DataItem $data): ?string { + return $data->path->value ?: NULL; + } + /** * {@inheritdoc} */ diff --git a/Generator/Service.php b/Generator/Service.php index 1b257a33..c159c687 100644 --- a/Generator/Service.php +++ b/Generator/Service.php @@ -187,6 +187,13 @@ public static function defaultRelativeNamespace($data_item) { } } + /** + * {@inheritdoc} + */ + public static function getDifferentiatedLabelSuffix(DataItem $data): ?string { + return $data->service_name->value ?: NULL; + } + /** * {@inheritdoc} */ diff --git a/MutableTypedData/Data/DeltaLabelTrait.php b/MutableTypedData/Data/DeltaLabelTrait.php new file mode 100644 index 00000000..584b519d --- /dev/null +++ b/MutableTypedData/Data/DeltaLabelTrait.php @@ -0,0 +1,35 @@ +getLabel(); + + // Just return the label if this isn't a delta, or if there's no associated + // generator. + if (!$this->isDelta() || empty($this->definition->generatorClass)) { + return $label; + } + + if ($qualifying_label = $this->definition->generatorClass::getDifferentiatedLabelSuffix($this)) { + $label .= ' - ' . $qualifying_label; + } + + return $label; + } + +} diff --git a/MutableTypedData/Data/MergeableComplexDataWithArrayAccess.php b/MutableTypedData/Data/MergeableComplexDataWithArrayAccess.php index 5b7f4447..5dc0fea5 100644 --- a/MutableTypedData/Data/MergeableComplexDataWithArrayAccess.php +++ b/MutableTypedData/Data/MergeableComplexDataWithArrayAccess.php @@ -8,6 +8,8 @@ class MergeableComplexDataWithArrayAccess extends ComplexData implements \ArrayA use DataItemArrayAccessTrait; + use DeltaLabelTrait; + use MergeableComplexDataTrait; } diff --git a/MutableTypedData/Data/MergeableMutableDataWithArrayAccess.php b/MutableTypedData/Data/MergeableMutableDataWithArrayAccess.php index f8e12de6..a3a01dc8 100644 --- a/MutableTypedData/Data/MergeableMutableDataWithArrayAccess.php +++ b/MutableTypedData/Data/MergeableMutableDataWithArrayAccess.php @@ -9,6 +9,8 @@ class MergeableMutableDataWithArrayAccess extends MutableData implements \ArrayA use DataItemArrayAccessTrait; + use DeltaLabelTrait; + use MergeableComplexDataTrait; /** From c639d2f669af92758f03e58305dee8f1c0bdd863 Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Tue, 25 Nov 2025 18:07:53 +0000 Subject: [PATCH 02/39] Changed CodeFileInterface to inherit from Stringable. Fixes #345. --- File/CodeFile.php | 2 +- File/CodeFileInterface.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/File/CodeFile.php b/File/CodeFile.php index 78bea945..f56edc8a 100644 --- a/File/CodeFile.php +++ b/File/CodeFile.php @@ -13,7 +13,7 @@ * This goes through a refinement process, with some properties being set later * and some which hold earlier versions of data being unset. */ -class CodeFile implements \Stringable, CodeFileInterface { +class CodeFile implements CodeFileInterface { /** * The array of body pieces. diff --git a/File/CodeFileInterface.php b/File/CodeFileInterface.php index c2aa2f69..e022ea75 100644 --- a/File/CodeFileInterface.php +++ b/File/CodeFileInterface.php @@ -8,7 +8,7 @@ * This may include the code of file on disk if this exists and the file is of * a type that we are able to merge. */ -interface CodeFileInterface { +interface CodeFileInterface extends \Stringable { /** * Gets the code for the file. From 98a840e2f6150ed38e273f78e3dcf13a0d01690a Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Tue, 25 Nov 2025 18:14:45 +0000 Subject: [PATCH 03/39] Changed CodeFile::getFilePath() to be public API. Fixes #344. --- File/CodeFile.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/File/CodeFile.php b/File/CodeFile.php index f56edc8a..8d7e581d 100644 --- a/File/CodeFile.php +++ b/File/CodeFile.php @@ -165,10 +165,6 @@ public function fileIsMerged(): bool { /** * Gets the relative filepath. * - * @internal - * - * @todo Make this part of the API in 4.3.0. - * * @return string * The filepath. */ From 26fc1b25138caabfdc5661e002d15ae675df06c1 Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Fri, 21 Nov 2025 14:34:24 +0000 Subject: [PATCH 04/39] Added utility class for changing order of items in an array. --- Utility/ArrayOrder.php | 103 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 Utility/ArrayOrder.php diff --git a/Utility/ArrayOrder.php b/Utility/ArrayOrder.php new file mode 100644 index 00000000..05faa5ac --- /dev/null +++ b/Utility/ArrayOrder.php @@ -0,0 +1,103 @@ + $value]); + } + + + /** + * Moves an item to the end of an array, specifying by value. + * + * @param array &$array + * The array to change. + * @param mixed $value + * The value to move. + * + * @throws \InvalidArgumentException + * Throws an exception if the value is not in the array. + */ + public static function moveValueToEnd(array &$array, mixed $value): void { + $key = array_find($array, $value); + + if ($key === FALSE) { + throw new \InvalidArgumentException('Value not found in array.'); + } + + unset($array[$key]); + + $array[$key] = $value; + } + + /** + * Moves an item to the end of an array, specifying by key. + * + * @param array &$array + * The array to change. + * @param mixed $key + * The key to move. + * + * @throws \InvalidArgumentException + * Throws an exception if the key is not in the array. + */ + public static function moveKeyToEnd(array &$array, mixed $key): void { + if (!isset($array[$key])) { + throw new \InvalidArgumentException('Key not found in array.'); + } + + $value = $array[$key]; + + unset($array[$key]); + + $array[$key] = $value; + } + +} From a16b02f5d3cf92d95582e935ab3d95b0710677f9 Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Sat, 24 Jan 2026 09:18:44 +0000 Subject: [PATCH 05/39] Added collect task for the analysis timestamp. Fixes #118. --- .../DrupalCodeBuilderCompiledContainer.php | 892 +++++++++--------- Task/Collect.php | 15 +- Task/Collect/MetadataCollector.php | 45 + 3 files changed, 526 insertions(+), 426 deletions(-) create mode 100644 Task/Collect/MetadataCollector.php diff --git a/DependencyInjection/cache/DrupalCodeBuilderCompiledContainer.php b/DependencyInjection/cache/DrupalCodeBuilderCompiledContainer.php index b7740d0c..f4e38b35 100644 --- a/DependencyInjection/cache/DrupalCodeBuilderCompiledContainer.php +++ b/DependencyInjection/cache/DrupalCodeBuilderCompiledContainer.php @@ -45,170 +45,176 @@ class DrupalCodeBuilderCompiledContainer extends DI\CompiledContainer{ 'subEntry17' => 'get39', 'Collect\\HooksCollector9' => 'get40', 'subEntry18' => 'get41', - 'Collect\\MethodCollector' => 'get42', - 'Collect\\PluginTypesCollector' => 'get43', - 'subEntry19' => 'get44', - 'subEntry20' => 'get45', - 'subEntry21' => 'get46', - 'subEntry22' => 'get47', - 'Collect\\ServiceTagTypesCollector' => 'get48', - 'subEntry23' => 'get49', - 'subEntry24' => 'get50', - 'subEntry25' => 'get51', - 'Collect\\ServicesCollector' => 'get52', - 'subEntry26' => 'get53', - 'subEntry27' => 'get54', - 'subEntry28' => 'get55', - 'Collect5' => 'get56', - 'subEntry29' => 'get57', - 'subEntry30' => 'get58', - 'Collect6' => 'get59', - 'subEntry31' => 'get60', - 'subEntry32' => 'get61', - 'Collect7' => 'get62', - 'subEntry33' => 'get63', - 'subEntry34' => 'get64', - 'Configuration' => 'get65', - 'subEntry35' => 'get66', - 'subEntry36' => 'get67', - 'Generate\\ComponentClassHandler' => 'get68', - 'subEntry37' => 'get69', - 'subEntry38' => 'get70', - 'Generate\\ComponentCollector' => 'get71', - 'subEntry39' => 'get72', - 'subEntry40' => 'get73', - 'Generate\\FileAssembler' => 'get74', - 'ReportAdminRoutes' => 'get75', - 'subEntry41' => 'get76', - 'ReportDataTypes' => 'get77', - 'subEntry42' => 'get78', - 'ReportElementTypes' => 'get79', - 'subEntry43' => 'get80', - 'ReportEntityTypes' => 'get81', - 'subEntry44' => 'get82', - 'ReportEventNames' => 'get83', - 'subEntry45' => 'get84', - 'ReportFieldTypes' => 'get85', - 'subEntry46' => 'get86', - 'ReportHookClassMethodData' => 'get87', - 'subEntry47' => 'get88', - 'ReportHookData' => 'get89', - 'subEntry48' => 'get90', - 'ReportHookDataFolder' => 'get91', - 'subEntry49' => 'get92', - 'ReportHookGroups' => 'get93', - 'subEntry50' => 'get94', - 'ReportHookPresets' => 'get95', - 'subEntry51' => 'get96', - 'ReportPluginData' => 'get97', - 'subEntry52' => 'get98', - 'ReportServiceData' => 'get99', - 'subEntry53' => 'get100', - 'ReportServiceTags' => 'get101', - 'subEntry54' => 'get102', - 'ReportSummary' => 'get103', - 'subEntry55' => 'get104', - 'subEntry56' => 'get105', - 'subEntry57' => 'get106', - 'subEntry58' => 'get107', - 'subEntry59' => 'get108', - 'subEntry60' => 'get109', - 'subEntry61' => 'get110', - 'subEntry62' => 'get111', - 'subEntry63' => 'get112', - 'subEntry64' => 'get113', - 'subEntry65' => 'get114', - 'subEntry66' => 'get115', - 'subEntry67' => 'get116', - 'subEntry68' => 'get117', - 'Testing\\CollectTesting10' => 'get118', - 'subEntry69' => 'get119', - 'subEntry70' => 'get120', - 'subEntry71' => 'get121', - 'subEntry72' => 'get122', - 'subEntry73' => 'get123', - 'subEntry74' => 'get124', - 'subEntry75' => 'get125', - 'subEntry76' => 'get126', - 'subEntry77' => 'get127', - 'subEntry78' => 'get128', - 'subEntry79' => 'get129', - 'subEntry80' => 'get130', - 'subEntry81' => 'get131', - 'Testing\\CollectTesting11' => 'get132', + 'Collect\\MetadataCollector' => 'get42', + 'Collect\\MethodCollector' => 'get43', + 'Collect\\PluginTypesCollector' => 'get44', + 'subEntry19' => 'get45', + 'subEntry20' => 'get46', + 'subEntry21' => 'get47', + 'subEntry22' => 'get48', + 'Collect\\ServiceTagTypesCollector' => 'get49', + 'subEntry23' => 'get50', + 'subEntry24' => 'get51', + 'subEntry25' => 'get52', + 'Collect\\ServicesCollector' => 'get53', + 'subEntry26' => 'get54', + 'subEntry27' => 'get55', + 'subEntry28' => 'get56', + 'Collect5' => 'get57', + 'subEntry29' => 'get58', + 'subEntry30' => 'get59', + 'Collect6' => 'get60', + 'subEntry31' => 'get61', + 'subEntry32' => 'get62', + 'Collect7' => 'get63', + 'subEntry33' => 'get64', + 'subEntry34' => 'get65', + 'Configuration' => 'get66', + 'subEntry35' => 'get67', + 'subEntry36' => 'get68', + 'Generate\\ComponentClassHandler' => 'get69', + 'subEntry37' => 'get70', + 'subEntry38' => 'get71', + 'Generate\\ComponentCollector' => 'get72', + 'subEntry39' => 'get73', + 'subEntry40' => 'get74', + 'Generate\\FileAssembler' => 'get75', + 'ReportAdminRoutes' => 'get76', + 'subEntry41' => 'get77', + 'ReportDataTypes' => 'get78', + 'subEntry42' => 'get79', + 'ReportElementTypes' => 'get80', + 'subEntry43' => 'get81', + 'ReportEntityTypes' => 'get82', + 'subEntry44' => 'get83', + 'ReportEventNames' => 'get84', + 'subEntry45' => 'get85', + 'ReportFieldTypes' => 'get86', + 'subEntry46' => 'get87', + 'ReportHookClassMethodData' => 'get88', + 'subEntry47' => 'get89', + 'ReportHookData' => 'get90', + 'subEntry48' => 'get91', + 'ReportHookDataFolder' => 'get92', + 'subEntry49' => 'get93', + 'ReportHookGroups' => 'get94', + 'subEntry50' => 'get95', + 'ReportHookPresets' => 'get96', + 'subEntry51' => 'get97', + 'ReportPluginData' => 'get98', + 'subEntry52' => 'get99', + 'ReportServiceData' => 'get100', + 'subEntry53' => 'get101', + 'ReportServiceTags' => 'get102', + 'subEntry54' => 'get103', + 'ReportSummary' => 'get104', + 'subEntry55' => 'get105', + 'subEntry56' => 'get106', + 'subEntry57' => 'get107', + 'subEntry58' => 'get108', + 'subEntry59' => 'get109', + 'subEntry60' => 'get110', + 'subEntry61' => 'get111', + 'subEntry62' => 'get112', + 'subEntry63' => 'get113', + 'subEntry64' => 'get114', + 'subEntry65' => 'get115', + 'subEntry66' => 'get116', + 'subEntry67' => 'get117', + 'subEntry68' => 'get118', + 'Testing\\CollectTesting10' => 'get119', + 'subEntry69' => 'get120', + 'subEntry70' => 'get121', + 'subEntry71' => 'get122', + 'subEntry72' => 'get123', + 'subEntry73' => 'get124', + 'subEntry74' => 'get125', + 'subEntry75' => 'get126', + 'subEntry76' => 'get127', + 'subEntry77' => 'get128', + 'subEntry78' => 'get129', + 'subEntry79' => 'get130', + 'subEntry80' => 'get131', + 'subEntry81' => 'get132', 'subEntry82' => 'get133', - 'subEntry83' => 'get134', - 'subEntry84' => 'get135', - 'subEntry85' => 'get136', - 'subEntry86' => 'get137', - 'subEntry87' => 'get138', - 'subEntry88' => 'get139', - 'subEntry89' => 'get140', - 'subEntry90' => 'get141', - 'subEntry91' => 'get142', - 'subEntry92' => 'get143', - 'subEntry93' => 'get144', - 'subEntry94' => 'get145', - 'Testing\\CollectTesting7' => 'get146', + 'Testing\\CollectTesting11' => 'get134', + 'subEntry83' => 'get135', + 'subEntry84' => 'get136', + 'subEntry85' => 'get137', + 'subEntry86' => 'get138', + 'subEntry87' => 'get139', + 'subEntry88' => 'get140', + 'subEntry89' => 'get141', + 'subEntry90' => 'get142', + 'subEntry91' => 'get143', + 'subEntry92' => 'get144', + 'subEntry93' => 'get145', + 'subEntry94' => 'get146', 'subEntry95' => 'get147', 'subEntry96' => 'get148', - 'Testing\\CollectTesting8' => 'get149', + 'Testing\\CollectTesting7' => 'get149', 'subEntry97' => 'get150', 'subEntry98' => 'get151', - 'subEntry99' => 'get152', - 'subEntry100' => 'get153', - 'subEntry101' => 'get154', - 'subEntry102' => 'get155', - 'subEntry103' => 'get156', - 'subEntry104' => 'get157', - 'subEntry105' => 'get158', - 'subEntry106' => 'get159', - 'subEntry107' => 'get160', - 'subEntry108' => 'get161', - 'subEntry109' => 'get162', - 'Testing\\CollectTesting9' => 'get163', + 'Testing\\CollectTesting8' => 'get152', + 'subEntry99' => 'get153', + 'subEntry100' => 'get154', + 'subEntry101' => 'get155', + 'subEntry102' => 'get156', + 'subEntry103' => 'get157', + 'subEntry104' => 'get158', + 'subEntry105' => 'get159', + 'subEntry106' => 'get160', + 'subEntry107' => 'get161', + 'subEntry108' => 'get162', + 'subEntry109' => 'get163', 'subEntry110' => 'get164', 'subEntry111' => 'get165', 'subEntry112' => 'get166', - 'subEntry113' => 'get167', - 'subEntry114' => 'get168', - 'subEntry115' => 'get169', - 'subEntry116' => 'get170', - 'subEntry117' => 'get171', - 'subEntry118' => 'get172', - 'subEntry119' => 'get173', - 'subEntry120' => 'get174', - 'subEntry121' => 'get175', - 'subEntry122' => 'get176', - 'Generate|module' => 'get177', - 'Generate|profile' => 'get178', - 'Collect\\HooksCollector' => 'get179', - 'Collect' => 'get180', - 'Collect.unversioned' => 'get181', - 'subEntry123' => 'get182', - 'subEntry124' => 'get183', - 'subEntry125' => 'get184', - 'subEntry126' => 'get185', - 'subEntry127' => 'get186', - 'subEntry128' => 'get187', - 'subEntry129' => 'get188', - 'subEntry130' => 'get189', - 'subEntry131' => 'get190', - 'subEntry132' => 'get191', - 'subEntry133' => 'get192', - 'subEntry134' => 'get193', - 'subEntry135' => 'get194', - 'Testing\\CollectTesting' => 'get195', - 'DrupalCodeBuilder\\Task\\Collect\\HooksCollector' => 'get196', - 'DrupalCodeBuilder\\Task\\Generate\\ComponentClassHandler' => 'get197', - 'subEntry136' => 'get198', - 'subEntry137' => 'get199', - 'DrupalCodeBuilder\\Task\\Collect\\ContainerBuilderGetter' => 'get200', - 'DrupalCodeBuilder\\Task\\Collect\\MethodCollector' => 'get201', - 'DrupalCodeBuilder\\Task\\Collect\\CodeAnalyser' => 'get202', - 'subEntry138' => 'get203', - 'DrupalCodeBuilder\\Task\\ReportHookData' => 'get204', - 'subEntry139' => 'get205', + 'Testing\\CollectTesting9' => 'get167', + 'subEntry113' => 'get168', + 'subEntry114' => 'get169', + 'subEntry115' => 'get170', + 'subEntry116' => 'get171', + 'subEntry117' => 'get172', + 'subEntry118' => 'get173', + 'subEntry119' => 'get174', + 'subEntry120' => 'get175', + 'subEntry121' => 'get176', + 'subEntry122' => 'get177', + 'subEntry123' => 'get178', + 'subEntry124' => 'get179', + 'subEntry125' => 'get180', + 'subEntry126' => 'get181', + 'Generate|module' => 'get182', + 'Generate|profile' => 'get183', + 'Collect\\HooksCollector' => 'get184', + 'Collect' => 'get185', + 'Collect.unversioned' => 'get186', + 'subEntry127' => 'get187', + 'subEntry128' => 'get188', + 'subEntry129' => 'get189', + 'subEntry130' => 'get190', + 'subEntry131' => 'get191', + 'subEntry132' => 'get192', + 'subEntry133' => 'get193', + 'subEntry134' => 'get194', + 'subEntry135' => 'get195', + 'subEntry136' => 'get196', + 'subEntry137' => 'get197', + 'subEntry138' => 'get198', + 'subEntry139' => 'get199', + 'subEntry140' => 'get200', + 'Testing\\CollectTesting' => 'get201', + 'DrupalCodeBuilder\\Task\\Collect\\HooksCollector' => 'get202', + 'DrupalCodeBuilder\\Task\\Generate\\ComponentClassHandler' => 'get203', + 'subEntry141' => 'get204', + 'subEntry142' => 'get205', + 'DrupalCodeBuilder\\Task\\Collect\\ContainerBuilderGetter' => 'get206', + 'DrupalCodeBuilder\\Task\\Collect\\MethodCollector' => 'get207', + 'DrupalCodeBuilder\\Task\\Collect\\CodeAnalyser' => 'get208', + 'subEntry143' => 'get209', + 'DrupalCodeBuilder\\Task\\ReportHookData' => 'get210', + 'subEntry144' => 'get211', ); protected function get1() @@ -482,778 +488,808 @@ protected function get40() } protected function get42() + { + $object = new \DrupalCodeBuilder\Task\Collect\MetadataCollector(); + return $object; + } + + protected function get43() { $object = new \DrupalCodeBuilder\Task\Collect\MethodCollector(); return $object; } - protected function get44() + protected function get45() { return $this->delegateContainer->get('DrupalCodeBuilder\\Environment\\EnvironmentInterface'); } - protected function get45() + protected function get46() { return $this->delegateContainer->get('DrupalCodeBuilder\\Task\\Collect\\ContainerBuilderGetter'); } - protected function get46() + protected function get47() { return $this->delegateContainer->get('DrupalCodeBuilder\\Task\\Collect\\MethodCollector'); } - protected function get47() + protected function get48() { return $this->delegateContainer->get('DrupalCodeBuilder\\Task\\Collect\\CodeAnalyser'); } - protected function get43() + protected function get44() { - $object = new \DrupalCodeBuilder\Task\Collect\PluginTypesCollector($this->get44(), $this->get45(), $this->get46(), $this->get47()); + $object = new \DrupalCodeBuilder\Task\Collect\PluginTypesCollector($this->get45(), $this->get46(), $this->get47(), $this->get48()); return $object; } - protected function get49() + protected function get50() { return $this->delegateContainer->get('DrupalCodeBuilder\\Environment\\EnvironmentInterface'); } - protected function get50() + protected function get51() { return $this->delegateContainer->get('DrupalCodeBuilder\\Task\\Collect\\ContainerBuilderGetter'); } - protected function get51() + protected function get52() { return $this->delegateContainer->get('DrupalCodeBuilder\\Task\\Collect\\MethodCollector'); } - protected function get48() + protected function get49() { - $object = new \DrupalCodeBuilder\Task\Collect\ServiceTagTypesCollector($this->get49(), $this->get50(), $this->get51()); + $object = new \DrupalCodeBuilder\Task\Collect\ServiceTagTypesCollector($this->get50(), $this->get51(), $this->get52()); return $object; } - protected function get53() + protected function get54() { return $this->delegateContainer->get('DrupalCodeBuilder\\Environment\\EnvironmentInterface'); } - protected function get54() + protected function get55() { return $this->delegateContainer->get('DrupalCodeBuilder\\Task\\Collect\\ContainerBuilderGetter'); } - protected function get55() + protected function get56() { return $this->delegateContainer->get('DrupalCodeBuilder\\Task\\Collect\\CodeAnalyser'); } - protected function get52() + protected function get53() { - $object = new \DrupalCodeBuilder\Task\Collect\ServicesCollector($this->get53(), $this->get54(), $this->get55()); + $object = new \DrupalCodeBuilder\Task\Collect\ServicesCollector($this->get54(), $this->get55(), $this->get56()); return $object; } - protected function get57() + protected function get58() { return $this->delegateContainer->get('DrupalCodeBuilder\\Environment\\EnvironmentInterface'); } - protected function get58() + protected function get59() { return $this->delegateContainer->get('DrupalCodeBuilder\\Task\\Collect\\HooksCollector'); } - protected function get56() + protected function get57() { - $object = new \DrupalCodeBuilder\Task\Collect5($this->get57(), $this->get58()); + $object = new \DrupalCodeBuilder\Task\Collect5($this->get58(), $this->get59()); return $object; } - protected function get60() + protected function get61() { return $this->delegateContainer->get('DrupalCodeBuilder\\Environment\\EnvironmentInterface'); } - protected function get61() + protected function get62() { return $this->delegateContainer->get('DrupalCodeBuilder\\Task\\Collect\\HooksCollector'); } - protected function get59() + protected function get60() { - $object = new \DrupalCodeBuilder\Task\Collect6($this->get60(), $this->get61()); + $object = new \DrupalCodeBuilder\Task\Collect6($this->get61(), $this->get62()); return $object; } - protected function get63() + protected function get64() { return $this->delegateContainer->get('DrupalCodeBuilder\\Environment\\EnvironmentInterface'); } - protected function get64() + protected function get65() { return $this->delegateContainer->get('DrupalCodeBuilder\\Task\\Collect\\HooksCollector'); } - protected function get62() + protected function get63() { - $object = new \DrupalCodeBuilder\Task\Collect7($this->get63(), $this->get64()); + $object = new \DrupalCodeBuilder\Task\Collect7($this->get64(), $this->get65()); return $object; } - protected function get66() + protected function get67() { return $this->delegateContainer->get('DrupalCodeBuilder\\Environment\\EnvironmentInterface'); } - protected function get67() + protected function get68() { return $this->delegateContainer->get('DrupalCodeBuilder\\Task\\Generate\\ComponentClassHandler'); } - protected function get65() + protected function get66() { - $object = new \DrupalCodeBuilder\Task\Configuration($this->get66(), $this->get67()); + $object = new \DrupalCodeBuilder\Task\Configuration($this->get67(), $this->get68()); return $object; } - protected function get69() + protected function get70() { return $this->delegateContainer->get('DrupalCodeBuilder\\Environment\\EnvironmentInterface'); } - protected function get70() + protected function get71() { return $this->delegateContainer->get('generator_classmap'); } - protected function get68() + protected function get69() { - $object = new \DrupalCodeBuilder\Task\Generate\ComponentClassHandler($this->get69(), $this->get70()); + $object = new \DrupalCodeBuilder\Task\Generate\ComponentClassHandler($this->get70(), $this->get71()); return $object; } - protected function get72() + protected function get73() { return $this->delegateContainer->get('DrupalCodeBuilder\\Environment\\EnvironmentInterface'); } - protected function get73() + protected function get74() { return $this->delegateContainer->get('DrupalCodeBuilder\\Task\\Generate\\ComponentClassHandler'); } - protected function get71() + protected function get72() { - $object = new \DrupalCodeBuilder\Task\Generate\ComponentCollector($this->get72(), $this->get73()); + $object = new \DrupalCodeBuilder\Task\Generate\ComponentCollector($this->get73(), $this->get74()); return $object; } - protected function get74() + protected function get75() { $object = new \DrupalCodeBuilder\Task\Generate\FileAssembler(); return $object; } - protected function get76() + protected function get77() { return $this->delegateContainer->get('DrupalCodeBuilder\\Environment\\EnvironmentInterface'); } - protected function get75() + protected function get76() { - $object = new \DrupalCodeBuilder\Task\ReportAdminRoutes($this->get76()); + $object = new \DrupalCodeBuilder\Task\ReportAdminRoutes($this->get77()); return $object; } - protected function get78() + protected function get79() { return $this->delegateContainer->get('DrupalCodeBuilder\\Environment\\EnvironmentInterface'); } - protected function get77() + protected function get78() { - $object = new \DrupalCodeBuilder\Task\ReportDataTypes($this->get78()); + $object = new \DrupalCodeBuilder\Task\ReportDataTypes($this->get79()); return $object; } - protected function get80() + protected function get81() { return $this->delegateContainer->get('DrupalCodeBuilder\\Environment\\EnvironmentInterface'); } - protected function get79() + protected function get80() { - $object = new \DrupalCodeBuilder\Task\ReportElementTypes($this->get80()); + $object = new \DrupalCodeBuilder\Task\ReportElementTypes($this->get81()); return $object; } - protected function get82() + protected function get83() { return $this->delegateContainer->get('DrupalCodeBuilder\\Environment\\EnvironmentInterface'); } - protected function get81() + protected function get82() { - $object = new \DrupalCodeBuilder\Task\ReportEntityTypes($this->get82()); + $object = new \DrupalCodeBuilder\Task\ReportEntityTypes($this->get83()); return $object; } - protected function get84() + protected function get85() { return $this->delegateContainer->get('DrupalCodeBuilder\\Environment\\EnvironmentInterface'); } - protected function get83() + protected function get84() { - $object = new \DrupalCodeBuilder\Task\ReportEventNames($this->get84()); + $object = new \DrupalCodeBuilder\Task\ReportEventNames($this->get85()); return $object; } - protected function get86() + protected function get87() { return $this->delegateContainer->get('DrupalCodeBuilder\\Environment\\EnvironmentInterface'); } - protected function get85() + protected function get86() { - $object = new \DrupalCodeBuilder\Task\ReportFieldTypes($this->get86()); + $object = new \DrupalCodeBuilder\Task\ReportFieldTypes($this->get87()); return $object; } - protected function get88() + protected function get89() { return $this->delegateContainer->get('DrupalCodeBuilder\\Environment\\EnvironmentInterface'); } - protected function get87() + protected function get88() { - $object = new \DrupalCodeBuilder\Task\ReportHookClassMethodData($this->get88()); + $object = new \DrupalCodeBuilder\Task\ReportHookClassMethodData($this->get89()); return $object; } - protected function get90() + protected function get91() { return $this->delegateContainer->get('DrupalCodeBuilder\\Environment\\EnvironmentInterface'); } - protected function get89() + protected function get90() { - $object = new \DrupalCodeBuilder\Task\ReportHookData($this->get90()); + $object = new \DrupalCodeBuilder\Task\ReportHookData($this->get91()); return $object; } - protected function get92() + protected function get93() { return $this->delegateContainer->get('DrupalCodeBuilder\\Environment\\EnvironmentInterface'); } - protected function get91() + protected function get92() { - $object = new \DrupalCodeBuilder\Task\ReportHookDataFolder($this->get92()); + $object = new \DrupalCodeBuilder\Task\ReportHookDataFolder($this->get93()); return $object; } - protected function get94() + protected function get95() { return $this->delegateContainer->get('DrupalCodeBuilder\\Task\\ReportHookData'); } - protected function get93() + protected function get94() { - $object = new \DrupalCodeBuilder\Task\ReportHookGroups($this->get94()); + $object = new \DrupalCodeBuilder\Task\ReportHookGroups($this->get95()); return $object; } - protected function get96() + protected function get97() { return $this->delegateContainer->get('DrupalCodeBuilder\\Environment\\EnvironmentInterface'); } - protected function get95() + protected function get96() { - $object = new \DrupalCodeBuilder\Task\ReportHookPresets($this->get96()); + $object = new \DrupalCodeBuilder\Task\ReportHookPresets($this->get97()); return $object; } - protected function get98() + protected function get99() { return $this->delegateContainer->get('DrupalCodeBuilder\\Environment\\EnvironmentInterface'); } - protected function get97() + protected function get98() { - $object = new \DrupalCodeBuilder\Task\ReportPluginData($this->get98()); + $object = new \DrupalCodeBuilder\Task\ReportPluginData($this->get99()); return $object; } - protected function get100() + protected function get101() { return $this->delegateContainer->get('DrupalCodeBuilder\\Environment\\EnvironmentInterface'); } - protected function get99() + protected function get100() { - $object = new \DrupalCodeBuilder\Task\ReportServiceData($this->get100()); + $object = new \DrupalCodeBuilder\Task\ReportServiceData($this->get101()); return $object; } - protected function get102() + protected function get103() { return $this->delegateContainer->get('DrupalCodeBuilder\\Environment\\EnvironmentInterface'); } - protected function get101() + protected function get102() { - $object = new \DrupalCodeBuilder\Task\ReportServiceTags($this->get102()); + $object = new \DrupalCodeBuilder\Task\ReportServiceTags($this->get103()); return $object; } - protected function get104() + protected function get105() { return $this->delegateContainer->get('DrupalCodeBuilder\\Environment\\EnvironmentInterface'); } - protected function get106() + protected function get107() { return $this->delegateContainer->get('Analyse\\TestTraits'); } - protected function get107() + protected function get108() { return $this->delegateContainer->get('ReportAdminRoutes'); } - protected function get108() + protected function get109() { return $this->delegateContainer->get('ReportDataTypes'); } - protected function get109() + protected function get110() { return $this->delegateContainer->get('ReportElementTypes'); } - protected function get110() + protected function get111() { return $this->delegateContainer->get('ReportEntityTypes'); } - protected function get111() + protected function get112() { return $this->delegateContainer->get('ReportEventNames'); } - protected function get112() + protected function get113() { return $this->delegateContainer->get('ReportFieldTypes'); } - protected function get113() + protected function get114() { return $this->delegateContainer->get('ReportHookClassMethodData'); } - protected function get114() + protected function get115() { return $this->delegateContainer->get('ReportHookData'); } - protected function get115() + protected function get116() { return $this->delegateContainer->get('ReportPluginData'); } - protected function get116() + protected function get117() { return $this->delegateContainer->get('ReportServiceData'); } - protected function get117() + protected function get118() { return $this->delegateContainer->get('ReportServiceTags'); } - protected function get105() + protected function get106() { return [ - 'Analyse\\TestTraits' => $this->get106(), - 'ReportAdminRoutes' => $this->get107(), - 'ReportDataTypes' => $this->get108(), - 'ReportElementTypes' => $this->get109(), - 'ReportEntityTypes' => $this->get110(), - 'ReportEventNames' => $this->get111(), - 'ReportFieldTypes' => $this->get112(), - 'ReportHookClassMethodData' => $this->get113(), - 'ReportHookData' => $this->get114(), - 'ReportPluginData' => $this->get115(), - 'ReportServiceData' => $this->get116(), - 'ReportServiceTags' => $this->get117(), + 'Analyse\\TestTraits' => $this->get107(), + 'ReportAdminRoutes' => $this->get108(), + 'ReportDataTypes' => $this->get109(), + 'ReportElementTypes' => $this->get110(), + 'ReportEntityTypes' => $this->get111(), + 'ReportEventNames' => $this->get112(), + 'ReportFieldTypes' => $this->get113(), + 'ReportHookClassMethodData' => $this->get114(), + 'ReportHookData' => $this->get115(), + 'ReportPluginData' => $this->get116(), + 'ReportServiceData' => $this->get117(), + 'ReportServiceTags' => $this->get118(), ]; } - protected function get103() + protected function get104() { - $object = new \DrupalCodeBuilder\Task\ReportSummary($this->get104()); - $object->setReportHelpers($this->get105()); + $object = new \DrupalCodeBuilder\Task\ReportSummary($this->get105()); + $object->setReportHelpers($this->get106()); return $object; } - protected function get119() + protected function get120() { return $this->delegateContainer->get('DrupalCodeBuilder\\Environment\\EnvironmentInterface'); } - protected function get121() + protected function get122() { return $this->delegateContainer->get('Analyse\\TestTraits'); } - protected function get122() + protected function get123() { return $this->delegateContainer->get('Collect\\AdminRoutesCollector'); } - protected function get123() + protected function get124() { return $this->delegateContainer->get('Collect\\DataTypesCollector'); } - protected function get124() + protected function get125() { return $this->delegateContainer->get('Collect\\ElementTypesCollector'); } - protected function get125() + protected function get126() { return $this->delegateContainer->get('Collect\\EntityTypesCollector'); } - protected function get126() + protected function get127() { return $this->delegateContainer->get('Collect\\EventNamesCollector'); } - protected function get127() + protected function get128() { return $this->delegateContainer->get('Collect\\FieldTypesCollector'); } - protected function get128() + protected function get129() + { + return $this->delegateContainer->get('Collect\\MetadataCollector'); + } + + protected function get130() { return $this->delegateContainer->get('Collect\\PluginTypesCollector'); } - protected function get129() + protected function get131() { return $this->delegateContainer->get('Collect\\ServiceTagTypesCollector'); } - protected function get130() + protected function get132() { return $this->delegateContainer->get('Collect\\ServicesCollector'); } - protected function get131() + protected function get133() { return $this->delegateContainer->get('Collect\\HooksCollector'); } - protected function get120() + protected function get121() { return [ - 'Analyse\\TestTraits' => $this->get121(), - 'Collect\\AdminRoutesCollector' => $this->get122(), - 'Collect\\DataTypesCollector' => $this->get123(), - 'Collect\\ElementTypesCollector' => $this->get124(), - 'Collect\\EntityTypesCollector' => $this->get125(), - 'Collect\\EventNamesCollector' => $this->get126(), - 'Collect\\FieldTypesCollector' => $this->get127(), - 'Collect\\PluginTypesCollector' => $this->get128(), - 'Collect\\ServiceTagTypesCollector' => $this->get129(), - 'Collect\\ServicesCollector' => $this->get130(), - 'Collect\\HooksCollector' => $this->get131(), + 'Analyse\\TestTraits' => $this->get122(), + 'Collect\\AdminRoutesCollector' => $this->get123(), + 'Collect\\DataTypesCollector' => $this->get124(), + 'Collect\\ElementTypesCollector' => $this->get125(), + 'Collect\\EntityTypesCollector' => $this->get126(), + 'Collect\\EventNamesCollector' => $this->get127(), + 'Collect\\FieldTypesCollector' => $this->get128(), + 'Collect\\MetadataCollector' => $this->get129(), + 'Collect\\PluginTypesCollector' => $this->get130(), + 'Collect\\ServiceTagTypesCollector' => $this->get131(), + 'Collect\\ServicesCollector' => $this->get132(), + 'Collect\\HooksCollector' => $this->get133(), ]; } - protected function get118() + protected function get119() { - $object = new \DrupalCodeBuilder\Task\Testing\CollectTesting10($this->get119()); - $object->setCollectors($this->get120()); + $object = new \DrupalCodeBuilder\Task\Testing\CollectTesting10($this->get120()); + $object->setCollectors($this->get121()); return $object; } - protected function get133() + protected function get135() { return $this->delegateContainer->get('DrupalCodeBuilder\\Environment\\EnvironmentInterface'); } - protected function get135() + protected function get137() { return $this->delegateContainer->get('Analyse\\TestTraits'); } - protected function get136() + protected function get138() { return $this->delegateContainer->get('Collect\\AdminRoutesCollector'); } - protected function get137() + protected function get139() { return $this->delegateContainer->get('Collect\\DataTypesCollector'); } - protected function get138() + protected function get140() { return $this->delegateContainer->get('Collect\\ElementTypesCollector'); } - protected function get139() + protected function get141() { return $this->delegateContainer->get('Collect\\EntityTypesCollector'); } - protected function get140() + protected function get142() { return $this->delegateContainer->get('Collect\\EventNamesCollector'); } - protected function get141() + protected function get143() { return $this->delegateContainer->get('Collect\\FieldTypesCollector'); } - protected function get142() + protected function get144() + { + return $this->delegateContainer->get('Collect\\MetadataCollector'); + } + + protected function get145() { return $this->delegateContainer->get('Collect\\PluginTypesCollector'); } - protected function get143() + protected function get146() { return $this->delegateContainer->get('Collect\\ServiceTagTypesCollector'); } - protected function get144() + protected function get147() { return $this->delegateContainer->get('Collect\\ServicesCollector'); } - protected function get145() + protected function get148() { return $this->delegateContainer->get('Collect\\HooksCollector'); } - protected function get134() + protected function get136() { return [ - 'Analyse\\TestTraits' => $this->get135(), - 'Collect\\AdminRoutesCollector' => $this->get136(), - 'Collect\\DataTypesCollector' => $this->get137(), - 'Collect\\ElementTypesCollector' => $this->get138(), - 'Collect\\EntityTypesCollector' => $this->get139(), - 'Collect\\EventNamesCollector' => $this->get140(), - 'Collect\\FieldTypesCollector' => $this->get141(), - 'Collect\\PluginTypesCollector' => $this->get142(), - 'Collect\\ServiceTagTypesCollector' => $this->get143(), - 'Collect\\ServicesCollector' => $this->get144(), - 'Collect\\HooksCollector' => $this->get145(), + 'Analyse\\TestTraits' => $this->get137(), + 'Collect\\AdminRoutesCollector' => $this->get138(), + 'Collect\\DataTypesCollector' => $this->get139(), + 'Collect\\ElementTypesCollector' => $this->get140(), + 'Collect\\EntityTypesCollector' => $this->get141(), + 'Collect\\EventNamesCollector' => $this->get142(), + 'Collect\\FieldTypesCollector' => $this->get143(), + 'Collect\\MetadataCollector' => $this->get144(), + 'Collect\\PluginTypesCollector' => $this->get145(), + 'Collect\\ServiceTagTypesCollector' => $this->get146(), + 'Collect\\ServicesCollector' => $this->get147(), + 'Collect\\HooksCollector' => $this->get148(), ]; } - protected function get132() + protected function get134() { - $object = new \DrupalCodeBuilder\Task\Testing\CollectTesting11($this->get133()); - $object->setCollectors($this->get134()); + $object = new \DrupalCodeBuilder\Task\Testing\CollectTesting11($this->get135()); + $object->setCollectors($this->get136()); return $object; } - protected function get147() + protected function get150() { return $this->delegateContainer->get('DrupalCodeBuilder\\Environment\\EnvironmentInterface'); } - protected function get148() + protected function get151() { return $this->delegateContainer->get('DrupalCodeBuilder\\Task\\Collect\\HooksCollector'); } - protected function get146() + protected function get149() { - $object = new \DrupalCodeBuilder\Task\Testing\CollectTesting7($this->get147(), $this->get148()); + $object = new \DrupalCodeBuilder\Task\Testing\CollectTesting7($this->get150(), $this->get151()); return $object; } - protected function get150() + protected function get153() { return $this->delegateContainer->get('DrupalCodeBuilder\\Environment\\EnvironmentInterface'); } - protected function get152() + protected function get155() { return $this->delegateContainer->get('Analyse\\TestTraits'); } - protected function get153() + protected function get156() { return $this->delegateContainer->get('Collect\\AdminRoutesCollector'); } - protected function get154() + protected function get157() { return $this->delegateContainer->get('Collect\\DataTypesCollector'); } - protected function get155() + protected function get158() { return $this->delegateContainer->get('Collect\\ElementTypesCollector'); } - protected function get156() + protected function get159() { return $this->delegateContainer->get('Collect\\EntityTypesCollector'); } - protected function get157() + protected function get160() { return $this->delegateContainer->get('Collect\\EventNamesCollector'); } - protected function get158() + protected function get161() { return $this->delegateContainer->get('Collect\\FieldTypesCollector'); } - protected function get159() + protected function get162() + { + return $this->delegateContainer->get('Collect\\MetadataCollector'); + } + + protected function get163() { return $this->delegateContainer->get('Collect\\PluginTypesCollector'); } - protected function get160() + protected function get164() { return $this->delegateContainer->get('Collect\\ServiceTagTypesCollector'); } - protected function get161() + protected function get165() { return $this->delegateContainer->get('Collect\\ServicesCollector'); } - protected function get162() + protected function get166() { return $this->delegateContainer->get('Collect\\HooksCollector'); } - protected function get151() + protected function get154() { return [ - 'Analyse\\TestTraits' => $this->get152(), - 'Collect\\AdminRoutesCollector' => $this->get153(), - 'Collect\\DataTypesCollector' => $this->get154(), - 'Collect\\ElementTypesCollector' => $this->get155(), - 'Collect\\EntityTypesCollector' => $this->get156(), - 'Collect\\EventNamesCollector' => $this->get157(), - 'Collect\\FieldTypesCollector' => $this->get158(), - 'Collect\\PluginTypesCollector' => $this->get159(), - 'Collect\\ServiceTagTypesCollector' => $this->get160(), - 'Collect\\ServicesCollector' => $this->get161(), - 'Collect\\HooksCollector' => $this->get162(), + 'Analyse\\TestTraits' => $this->get155(), + 'Collect\\AdminRoutesCollector' => $this->get156(), + 'Collect\\DataTypesCollector' => $this->get157(), + 'Collect\\ElementTypesCollector' => $this->get158(), + 'Collect\\EntityTypesCollector' => $this->get159(), + 'Collect\\EventNamesCollector' => $this->get160(), + 'Collect\\FieldTypesCollector' => $this->get161(), + 'Collect\\MetadataCollector' => $this->get162(), + 'Collect\\PluginTypesCollector' => $this->get163(), + 'Collect\\ServiceTagTypesCollector' => $this->get164(), + 'Collect\\ServicesCollector' => $this->get165(), + 'Collect\\HooksCollector' => $this->get166(), ]; } - protected function get149() + protected function get152() { - $object = new \DrupalCodeBuilder\Task\Testing\CollectTesting8($this->get150()); - $object->setCollectors($this->get151()); + $object = new \DrupalCodeBuilder\Task\Testing\CollectTesting8($this->get153()); + $object->setCollectors($this->get154()); return $object; } - protected function get164() + protected function get168() { return $this->delegateContainer->get('DrupalCodeBuilder\\Environment\\EnvironmentInterface'); } - protected function get166() + protected function get170() { return $this->delegateContainer->get('Analyse\\TestTraits'); } - protected function get167() + protected function get171() { return $this->delegateContainer->get('Collect\\AdminRoutesCollector'); } - protected function get168() + protected function get172() { return $this->delegateContainer->get('Collect\\DataTypesCollector'); } - protected function get169() + protected function get173() { return $this->delegateContainer->get('Collect\\ElementTypesCollector'); } - protected function get170() + protected function get174() { return $this->delegateContainer->get('Collect\\EntityTypesCollector'); } - protected function get171() + protected function get175() { return $this->delegateContainer->get('Collect\\EventNamesCollector'); } - protected function get172() + protected function get176() { return $this->delegateContainer->get('Collect\\FieldTypesCollector'); } - protected function get173() + protected function get177() + { + return $this->delegateContainer->get('Collect\\MetadataCollector'); + } + + protected function get178() { return $this->delegateContainer->get('Collect\\PluginTypesCollector'); } - protected function get174() + protected function get179() { return $this->delegateContainer->get('Collect\\ServiceTagTypesCollector'); } - protected function get175() + protected function get180() { return $this->delegateContainer->get('Collect\\ServicesCollector'); } - protected function get176() + protected function get181() { return $this->delegateContainer->get('Collect\\HooksCollector'); } - protected function get165() + protected function get169() { return [ - 'Analyse\\TestTraits' => $this->get166(), - 'Collect\\AdminRoutesCollector' => $this->get167(), - 'Collect\\DataTypesCollector' => $this->get168(), - 'Collect\\ElementTypesCollector' => $this->get169(), - 'Collect\\EntityTypesCollector' => $this->get170(), - 'Collect\\EventNamesCollector' => $this->get171(), - 'Collect\\FieldTypesCollector' => $this->get172(), - 'Collect\\PluginTypesCollector' => $this->get173(), - 'Collect\\ServiceTagTypesCollector' => $this->get174(), - 'Collect\\ServicesCollector' => $this->get175(), - 'Collect\\HooksCollector' => $this->get176(), + 'Analyse\\TestTraits' => $this->get170(), + 'Collect\\AdminRoutesCollector' => $this->get171(), + 'Collect\\DataTypesCollector' => $this->get172(), + 'Collect\\ElementTypesCollector' => $this->get173(), + 'Collect\\EntityTypesCollector' => $this->get174(), + 'Collect\\EventNamesCollector' => $this->get175(), + 'Collect\\FieldTypesCollector' => $this->get176(), + 'Collect\\MetadataCollector' => $this->get177(), + 'Collect\\PluginTypesCollector' => $this->get178(), + 'Collect\\ServiceTagTypesCollector' => $this->get179(), + 'Collect\\ServicesCollector' => $this->get180(), + 'Collect\\HooksCollector' => $this->get181(), ]; } - protected function get163() + protected function get167() { - $object = new \DrupalCodeBuilder\Task\Testing\CollectTesting9($this->get164()); - $object->setCollectors($this->get165()); + $object = new \DrupalCodeBuilder\Task\Testing\CollectTesting9($this->get168()); + $object->setCollectors($this->get169()); return $object; } - protected function get177() + protected function get182() { return $this->resolveFactory([ 0 => 'DrupalCodeBuilder\\DependencyInjection\\ServiceFactories', @@ -1263,7 +1299,7 @@ protected function get177() ]); } - protected function get178() + protected function get183() { return $this->resolveFactory([ 0 => 'DrupalCodeBuilder\\DependencyInjection\\ServiceFactories', @@ -1273,7 +1309,7 @@ protected function get178() ]); } - protected function get179() + protected function get184() { return $this->resolveFactory([ 0 => 'DrupalCodeBuilder\\DependencyInjection\\ServiceFactories', @@ -1281,7 +1317,7 @@ protected function get179() ], 'Collect\\HooksCollector'); } - protected function get180() + protected function get185() { return $this->resolveFactory([ 0 => 'DrupalCodeBuilder\\DependencyInjection\\ServiceFactories', @@ -1289,91 +1325,97 @@ protected function get180() ], 'Collect'); } - protected function get182() + protected function get187() { return $this->delegateContainer->get('DrupalCodeBuilder\\Environment\\EnvironmentInterface'); } - protected function get184() + protected function get189() { return $this->delegateContainer->get('Analyse\\TestTraits'); } - protected function get185() + protected function get190() { return $this->delegateContainer->get('Collect\\AdminRoutesCollector'); } - protected function get186() + protected function get191() { return $this->delegateContainer->get('Collect\\DataTypesCollector'); } - protected function get187() + protected function get192() { return $this->delegateContainer->get('Collect\\ElementTypesCollector'); } - protected function get188() + protected function get193() { return $this->delegateContainer->get('Collect\\EntityTypesCollector'); } - protected function get189() + protected function get194() { return $this->delegateContainer->get('Collect\\EventNamesCollector'); } - protected function get190() + protected function get195() { return $this->delegateContainer->get('Collect\\FieldTypesCollector'); } - protected function get191() + protected function get196() + { + return $this->delegateContainer->get('Collect\\MetadataCollector'); + } + + protected function get197() { return $this->delegateContainer->get('Collect\\PluginTypesCollector'); } - protected function get192() + protected function get198() { return $this->delegateContainer->get('Collect\\ServiceTagTypesCollector'); } - protected function get193() + protected function get199() { return $this->delegateContainer->get('Collect\\ServicesCollector'); } - protected function get194() + protected function get200() { return $this->delegateContainer->get('Collect\\HooksCollector'); } - protected function get183() + protected function get188() { return [ - 'Analyse\\TestTraits' => $this->get184(), - 'Collect\\AdminRoutesCollector' => $this->get185(), - 'Collect\\DataTypesCollector' => $this->get186(), - 'Collect\\ElementTypesCollector' => $this->get187(), - 'Collect\\EntityTypesCollector' => $this->get188(), - 'Collect\\EventNamesCollector' => $this->get189(), - 'Collect\\FieldTypesCollector' => $this->get190(), - 'Collect\\PluginTypesCollector' => $this->get191(), - 'Collect\\ServiceTagTypesCollector' => $this->get192(), - 'Collect\\ServicesCollector' => $this->get193(), - 'Collect\\HooksCollector' => $this->get194(), + 'Analyse\\TestTraits' => $this->get189(), + 'Collect\\AdminRoutesCollector' => $this->get190(), + 'Collect\\DataTypesCollector' => $this->get191(), + 'Collect\\ElementTypesCollector' => $this->get192(), + 'Collect\\EntityTypesCollector' => $this->get193(), + 'Collect\\EventNamesCollector' => $this->get194(), + 'Collect\\FieldTypesCollector' => $this->get195(), + 'Collect\\MetadataCollector' => $this->get196(), + 'Collect\\PluginTypesCollector' => $this->get197(), + 'Collect\\ServiceTagTypesCollector' => $this->get198(), + 'Collect\\ServicesCollector' => $this->get199(), + 'Collect\\HooksCollector' => $this->get200(), ]; } - protected function get181() + protected function get186() { - $object = new \DrupalCodeBuilder\Task\Collect($this->get182()); - $object->setCollectors($this->get183()); + $object = new \DrupalCodeBuilder\Task\Collect($this->get187()); + $object->setCollectors($this->get188()); return $object; } - protected function get195() + protected function get201() { return $this->resolveFactory([ 0 => 'DrupalCodeBuilder\\DependencyInjection\\ServiceFactories', @@ -1381,58 +1423,58 @@ protected function get195() ], 'Testing\\CollectTesting'); } - protected function get196() + protected function get202() { return $this->delegateContainer->get('Collect\\HooksCollector'); } - protected function get198() + protected function get204() { return $this->delegateContainer->get('DrupalCodeBuilder\\Environment\\EnvironmentInterface'); } - protected function get199() + protected function get205() { return $this->delegateContainer->get('generator_classmap'); } - protected function get197() + protected function get203() { - $object = new DrupalCodeBuilder\Task\Generate\ComponentClassHandler($this->get198(), $this->get199()); + $object = new DrupalCodeBuilder\Task\Generate\ComponentClassHandler($this->get204(), $this->get205()); return $object; } - protected function get200() + protected function get206() { $object = new DrupalCodeBuilder\Task\Collect\ContainerBuilderGetter(); return $object; } - protected function get201() + protected function get207() { $object = new DrupalCodeBuilder\Task\Collect\MethodCollector(); return $object; } - protected function get203() + protected function get209() { return $this->delegateContainer->get('DrupalCodeBuilder\\Environment\\EnvironmentInterface'); } - protected function get202() + protected function get208() { - $object = new DrupalCodeBuilder\Task\Collect\CodeAnalyser($this->get203()); + $object = new DrupalCodeBuilder\Task\Collect\CodeAnalyser($this->get209()); return $object; } - protected function get205() + protected function get211() { return $this->delegateContainer->get('DrupalCodeBuilder\\Environment\\EnvironmentInterface'); } - protected function get204() + protected function get210() { - $object = new DrupalCodeBuilder\Task\ReportHookData($this->get205()); + $object = new DrupalCodeBuilder\Task\ReportHookData($this->get211()); return $object; } diff --git a/Task/Collect.php b/Task/Collect.php index 4dcdcb07..4bb34804 100644 --- a/Task/Collect.php +++ b/Task/Collect.php @@ -8,8 +8,10 @@ namespace DrupalCodeBuilder\Task; use DrupalCodeBuilder\Attribute\InjectImplementations; +use DrupalCodeBuilder\Environment\EnvironmentInterface; use DrupalCodeBuilder\Task\Collect\CollectorInterface; - +use DrupalCodeBuilder\Task\Collect\MetadataCollector; +use DrupalCodeBuilder\Utility\ArrayOrder; /** * Task handler for collecting and processing definitions for Drupal components. * @@ -51,6 +53,17 @@ class Collect extends Base { */ #[InjectImplementations(CollectorInterface::class)] public function setCollectors(array $collectors) { + // Append the metadata controller so it runs last. + // This is faffy, but the faff is small and contained. The alternatives + // would be: a weight system for interface-based injection + // (over-engineered), or injecting this collector separately (but then it + // can't implement the interface or use the base class, which requires more + // code). + // WARNING: We rely on the array of collectors being keyed by the service + // name, which is only the case because of a bug in PHP-DI which doesn't + // allow us to use the splat operator for the collectors parameter! + ArrayOrder::moveKeyToEnd($collectors, 'Collect\\MetadataCollector'); + $this->collectors = $collectors; } diff --git a/Task/Collect/MetadataCollector.php b/Task/Collect/MetadataCollector.php new file mode 100644 index 00000000..825fa9b1 --- /dev/null +++ b/Task/Collect/MetadataCollector.php @@ -0,0 +1,45 @@ + time(), + ]; + } + +} From cddbc9134243aa4cd101edf1b0b07cde1d0b2a6a Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Fri, 21 Nov 2025 19:42:36 +0000 Subject: [PATCH 06/39] Added lastUpdatedDate() to ReportSummary using metadata, overriding method in parent class. --- Task/ReportSummary.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Task/ReportSummary.php b/Task/ReportSummary.php index 28a8cd80..1a8df762 100644 --- a/Task/ReportSummary.php +++ b/Task/ReportSummary.php @@ -45,6 +45,18 @@ public function setReportHelpers(array $helper_services) { $this->helperServices = $helper_services; } + /** + * Gets the timestamp of the last data analysis. + * + * @return + * A unix timestamp, or NULL if the data analysis has never been done. + */ + public function lastUpdatedDate(): ?int { + $metadata = $this->environment->getStorage()->retrieve('metadata'); + + return $metadata['timestamp'] ?? NULL; + } + /** * Returns a listing of all stored data, with counts. * From f2ee79c037c2164966955900743270609178f3e0 Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Fri, 21 Nov 2025 20:09:12 +0000 Subject: [PATCH 07/39] Deprecated ReportHookDataFolder::lastUpdatedDate(). Fixes #418. --- Task/ReportHookDataFolder.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Task/ReportHookDataFolder.php b/Task/ReportHookDataFolder.php index d6e2bd2b..37d62db2 100644 --- a/Task/ReportHookDataFolder.php +++ b/Task/ReportHookDataFolder.php @@ -27,6 +27,9 @@ class ReportHookDataFolder extends Base { * * @return * A unix timestamp, or NULL if the hooks have never been collected. + * + * @deprecated Use \DrupalCodeBuilder\Task\ReportSummary::lastUpdatedDate() + * instead. */ public function lastUpdatedDate() { $directory = $this->environment->getDataDirectory(); From 4ebde3b2cbe127ad02e27630be20dbef4d18ed62 Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Sat, 24 Jan 2026 17:52:12 +0000 Subject: [PATCH 08/39] Fixed services whose name is a class-like producing broken variable and property names. Fixes #415. --- Task/Collect/ServicesCollector.php | 3 ++- ...e10Test.php => ComponentService11Test.php} | 24 +++++++++++++++++-- .../11/services_processed.php | 10 ++++++++ 3 files changed, 34 insertions(+), 3 deletions(-) rename Test/Unit/{ComponentService10Test.php => ComponentService11Test.php} (98%) diff --git a/Task/Collect/ServicesCollector.php b/Task/Collect/ServicesCollector.php index ae9cc9ba..5cce5e56 100644 --- a/Task/Collect/ServicesCollector.php +++ b/Task/Collect/ServicesCollector.php @@ -31,6 +31,7 @@ class ServicesCollector extends CollectorBase { 'module_handler' => TRUE, 'cache.discovery' => TRUE, 'storage:node' => TRUE, + 'Drupal\Core\DefaultContent\Importer' => TRUE, ]; /** @@ -251,7 +252,7 @@ protected function getAllServices(): array { $service_class = '\\' . $service_class; } - if (substr_count($service_id, '.') == 0) { + if (!str_contains($service_id, '.') && !str_contains($service_id, '\\')) { // If the service name does not contain any dots, in particular, // 'current_user', then use that, as it's usually clearer than the // class name. diff --git a/Test/Unit/ComponentService10Test.php b/Test/Unit/ComponentService11Test.php similarity index 98% rename from Test/Unit/ComponentService10Test.php rename to Test/Unit/ComponentService11Test.php index 603c9add..87a34133 100644 --- a/Test/Unit/ComponentService10Test.php +++ b/Test/Unit/ComponentService11Test.php @@ -11,14 +11,14 @@ * * @group yaml */ -class ComponentService10Test extends TestBase { +class ComponentService11Test extends TestBase { /** * The Drupal core major version to set up for this test. * * @var int */ - protected $drupalMajorVersion = 10; + protected $drupalMajorVersion = 11; /** * Test generating a module with a service. @@ -366,6 +366,26 @@ public static function providerServiceGenerationWithServices() { ], ], ], + // Class name service. + 'class-named' => [ + 'injected_services' => [ + 'Drupal\Core\DefaultContent\Importer', + ], + 'property_promotion' => FALSE, + 'yaml_arguments' => [ + '@Drupal\Core\DefaultContent\Importer', + ], + 'assert_injected_services' => [ + [ + // Eh this typehint is a whole other problem with this particular + // service. + 'typehint' => 'Psr\Log\LoggerAwareInterface', + 'service_name' => 'importer', + 'property_name' => 'importer', + 'parameter_name' => 'importer', + ], + ], + ], // Pseudoservice with the real service also present as a parameter. 'pseudo-with-real' => [ 'injected_services' => [ diff --git a/Test/sample_hook_definitions/11/services_processed.php b/Test/sample_hook_definitions/11/services_processed.php index d6ac5137..7b1496a1 100644 --- a/Test/sample_hook_definitions/11/services_processed.php +++ b/Test/sample_hook_definitions/11/services_processed.php @@ -32,6 +32,16 @@ ), 'all' => array ( + 'Drupal\\Core\\DefaultContent\\Importer' => + array ( + 'id' => 'Drupal\\Core\\DefaultContent\\Importer', + 'label' => 'Importer', + 'static_method' => '', + 'class' => '\\Drupal\\Core\\DefaultContent\\Importer', + 'interface' => '\\Psr\\Log\\LoggerAwareInterface', + 'description' => 'The importer service', + 'variable_name' => 'importer', + ), 'cache.discovery' => array ( 'id' => 'cache.discovery', From 87c234de13614ccd4573873de5ecffbd8af5279e Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Sun, 25 Jan 2026 13:14:48 +0000 Subject: [PATCH 09/39] Added DI to plugin deriver classes. Fixes #410. --- Generator/PluginClassDiscovery.php | 11 ++- Generator/PluginDeriver.php | 77 +++++++++++++++++++ Generator/PluginYamlDiscovery.php | 11 ++- Test/Unit/ComponentPluginsAnnotated9Test.php | 2 +- Test/Unit/ComponentPluginsAttribute11Test.php | 34 +++++++- Test/Unit/ComponentPluginsYAML10Test.php | 2 +- 6 files changed, 126 insertions(+), 11 deletions(-) create mode 100644 Generator/PluginDeriver.php diff --git a/Generator/PluginClassDiscovery.php b/Generator/PluginClassDiscovery.php index c2a5bcb7..e8bb3f01 100644 --- a/Generator/PluginClassDiscovery.php +++ b/Generator/PluginClassDiscovery.php @@ -91,6 +91,11 @@ public static function addToGeneratorDefinition(PropertyListInterface $definitio 'deriver' => PropertyDefinition::create('boolean') ->setLabel('Use deriver') ->setDescription("Adds a deriver class to dynamically derive plugins from a template."), + 'deriver_injected_services' => PropertyDefinition::create('string') + ->setLabel('Deriver injected services') + ->setDescription("Services to inject into the deriver class.") + ->setMultiple(TRUE) + ->setOptionSetDefinition(\DrupalCodeBuilder\Factory::getTask('ReportServiceData')), 'deriver_plain_class_name' => PropertyDefinition::create('string') ->setInternal(TRUE) ->setDefault(DefaultDefinition::create() @@ -236,16 +241,14 @@ public function requiredComponents(): array { if (!empty($this->component_data->deriver->value)) { $components['deriver'] = [ - 'component_type' => 'PHPClassFile', + 'component_type' => 'PluginDeriver', 'class_docblock_lines' => [ 'Plugin deriver for ' . $this->component_data->plugin_name->value . '.', ], 'plain_class_name' => $this->component_data->deriver_plain_class_name->value, 'relative_namespace' => 'Plugin\Derivative', 'parent_class_name' => '\Drupal\Component\Plugin\Derivative\DeriverBase', - 'interfaces' => [ - '\Drupal\Core\Plugin\Discovery\ContainerDeriverInterface', - ], + 'injected_services' => $this->component_data->deriver_injected_services->values(), ]; $components['getDerivativeDefinitions'] = [ diff --git a/Generator/PluginDeriver.php b/Generator/PluginDeriver.php new file mode 100644 index 00000000..1d38bc8d --- /dev/null +++ b/Generator/PluginDeriver.php @@ -0,0 +1,77 @@ + 'base_plugin_id', + 'description' => 'The base plugin ID.', + 'typehint' => 'string', + ], + ]; + + /** + * {@inheritdoc} + */ + public static function addToGeneratorDefinition(PropertyListInterface $definition) { + parent::addToGeneratorDefinition($definition); + + $definition->getProperty('use_static_factory_method') + ->setLiteralDefault(TRUE); + } + + /** + * Produces the class declaration. + */ + function classDeclaration() { + if (!$this->needsDiInterface()) { + // Numeric key will clobber, so make something up! + // TODO: fix! + $this->component_data->interfaces->add(['CLASS_NO_DI_INTERFACE' => static::CLASS_NO_DI_INTERFACE]); + } + + return parent::classDeclaration(); + } + + /** + * {@inheritdoc} + */ + protected function getConstructBaseParameters() { + // Deriver classes do not pass on the $base_plugin_id create() parameter to + // the constructor. + return []; + } + + /** + * {@inheritdoc} + */ + protected function getCreateParameters() { + return static::STANDARD_FIXED_PARAMS; + } + +} diff --git a/Generator/PluginYamlDiscovery.php b/Generator/PluginYamlDiscovery.php index 1bc3d92c..35351351 100644 --- a/Generator/PluginYamlDiscovery.php +++ b/Generator/PluginYamlDiscovery.php @@ -33,6 +33,11 @@ public static function addToGeneratorDefinition(PropertyListInterface $definitio 'deriver' => PropertyDefinition::create('boolean') ->setLabel('Use deriver') ->setDescription("Adds a deriver class to dynamically derive plugins from a template."), + 'deriver_injected_services' => PropertyDefinition::create('string') + ->setLabel('Deriver injected services') + ->setDescription("Services to inject into the deriver class.") + ->setMultiple(TRUE) + ->setOptionSetDefinition(\DrupalCodeBuilder\Factory::getTask('ReportServiceData')), 'deriver_plain_class_name' => PropertyDefinition::create('string') ->setInternal(TRUE) ->setDefault(DefaultDefinition::create() @@ -190,16 +195,14 @@ public function requiredComponents(): array { if (!empty($this->component_data->deriver->value)) { $components['deriver'] = [ - 'component_type' => 'PHPClassFile', + 'component_type' => 'PluginDeriver', 'class_docblock_lines' => [ 'Plugin deriver for ' . $this->component_data->plugin_name->value . '.', ], 'plain_class_name' => $this->component_data->deriver_plain_class_name->value, 'relative_namespace' => 'Plugin\Derivative', 'parent_class_name' => '\Drupal\Component\Plugin\Derivative\DeriverBase', - 'interfaces' => [ - '\Drupal\Core\Plugin\Discovery\ContainerDeriverInterface', - ], + 'injected_services' => $this->component_data->deriver_injected_services->values(), ]; $components['getDerivativeDefinitions'] = [ diff --git a/Test/Unit/ComponentPluginsAnnotated9Test.php b/Test/Unit/ComponentPluginsAnnotated9Test.php index c8f4d5a0..75019945 100644 --- a/Test/Unit/ComponentPluginsAnnotated9Test.php +++ b/Test/Unit/ComponentPluginsAnnotated9Test.php @@ -213,7 +213,7 @@ function testPluginsGenerationDeriver() { $deriver = $files['src/Plugin/Derivative/AlphaBlockDeriver.php']; $php_tester = PHPTester::fromCodeFile($this->drupalMajorVersion, $deriver); $php_tester->assertClassHasParent('Drupal\Component\Plugin\Derivative\DeriverBase'); - $php_tester->assertClassHasInterfaces(['Drupal\Core\Plugin\Discovery\ContainerDeriverInterface']); + $php_tester->assertClassHasInterfaces(['Drupal\Component\Plugin\Derivative\DeriverInterface']); $php_tester->assertHasMethod('getDerivativeDefinitions'); // Check the plugin file declares the deriver. diff --git a/Test/Unit/ComponentPluginsAttribute11Test.php b/Test/Unit/ComponentPluginsAttribute11Test.php index a6bb4691..0077276d 100644 --- a/Test/Unit/ComponentPluginsAttribute11Test.php +++ b/Test/Unit/ComponentPluginsAttribute11Test.php @@ -264,6 +264,8 @@ public static function providerPluginsGenerationNamePrefixing() { /** * Tests plugin derivers. + * + * @group di */ function testPluginsGenerationDeriver() { // Create a module. @@ -293,7 +295,7 @@ function testPluginsGenerationDeriver() { $deriver = $files['src/Plugin/Derivative/AlphaFieldFormatterDeriver.php']; $php_tester = PHPTester::fromCodeFile($this->drupalMajorVersion, $deriver); $php_tester->assertClassHasParent('Drupal\Component\Plugin\Derivative\DeriverBase'); - $php_tester->assertClassHasInterfaces(['Drupal\Core\Plugin\Discovery\ContainerDeriverInterface']); + $php_tester->assertClassHasInterfaces(['Drupal\Component\Plugin\Derivative\DeriverInterface']); $php_tester->assertHasMethod('getDerivativeDefinitions'); // Check the plugin file declares the deriver. @@ -301,6 +303,36 @@ function testPluginsGenerationDeriver() { $php_tester = PHPTester::fromCodeFile($this->drupalMajorVersion, $plugin_file); $php_tester->assertImportsClassLike(['Drupal\test_module\Plugin\Derivative\AlphaFieldFormatterDeriver']); $php_tester->assertClassAttributeHasNamedParameterValue('deriver', 'AlphaFieldFormatterDeriver::class', 'FieldFormatter'); + + // Add DI to the deriver class. + $module_data['plugins'][0]['deriver_injected_services'] = [ + 'current_user', + 'entity_type.manager', + ]; + + $files = $this->generateModuleFiles($module_data); + + $this->assertArrayHasKey('src/Plugin/Derivative/AlphaFieldFormatterDeriver.php', $files); + $deriver = $files['src/Plugin/Derivative/AlphaFieldFormatterDeriver.php']; + + $php_tester = PHPTester::fromCodeFile($this->drupalMajorVersion, $deriver); + $php_tester->assertClassHasParent('Drupal\Component\Plugin\Derivative\DeriverBase'); + $php_tester->assertClassHasInterfaces(['Drupal\Core\Plugin\Discovery\ContainerDeriverInterface']); + // Check service injection. + $php_tester->assertInjectedServicesWithFactory([ + [ + 'typehint' => 'Drupal\Core\Session\AccountProxyInterface', + 'service_name' => 'current_user', + 'property_name' => 'currentUser', + 'parameter_name' => 'current_user', + ], + [ + 'typehint' => 'Drupal\Core\Entity\EntityTypeManagerInterface', + 'service_name' => 'entity_type.manager', + 'property_name' => 'entityTypeManager', + 'parameter_name' => 'entity_type_manager', + ], + ]); } /** diff --git a/Test/Unit/ComponentPluginsYAML10Test.php b/Test/Unit/ComponentPluginsYAML10Test.php index 1eca1f6c..71d661be 100644 --- a/Test/Unit/ComponentPluginsYAML10Test.php +++ b/Test/Unit/ComponentPluginsYAML10Test.php @@ -91,7 +91,7 @@ function testYamlPluginsGenerationDeriver() { $deriver = $files['src/Plugin/Derivative/AlphaMenuLinkDeriver.php']; $php_tester = PHPTester::fromCodeFile($this->drupalMajorVersion, $deriver); $php_tester->assertClassHasParent('Drupal\Component\Plugin\Derivative\DeriverBase'); - $php_tester->assertClassHasInterfaces(['Drupal\Core\Plugin\Discovery\ContainerDeriverInterface']); + $php_tester->assertClassHasInterfaces(['Drupal\Component\Plugin\Derivative\DeriverInterface']); $php_tester->assertHasMethod('getDerivativeDefinitions'); // Check the plugin YAML file declares the deriver. From 89f6f45f1d661cae0d7b6ad6b4a198bf4bd66840 Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Sun, 25 Jan 2026 15:55:59 +0000 Subject: [PATCH 10/39] Added dependent values system to data properties. --- Definition/PropertyDefinition.php | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/Definition/PropertyDefinition.php b/Definition/PropertyDefinition.php index 1bf4f97d..3635fc01 100644 --- a/Definition/PropertyDefinition.php +++ b/Definition/PropertyDefinition.php @@ -18,6 +18,7 @@ * - Presets * - Processing * - Auto-acquisition + * - Dependency values */ class PropertyDefinition extends BasePropertyDefinition implements PropertyListInterface, \ArrayAccess { @@ -36,6 +37,8 @@ class PropertyDefinition extends BasePropertyDefinition implements PropertyListI protected $autoAcquired = FALSE; + protected ?array $dependentValue = NULL; + /** * {@inheritdoc} */ @@ -322,6 +325,27 @@ public function loadLazyProperties() { } } + /** + * Sets dependent values. + * + * UIs can use these to determine whether to show a property. + * + * @param array $dependent_value + * An array of dependencies which this property may require to be shown. + * Keys are relative addresses. Values are either the target value, or for + * string data, TRUE to represent that the target property must be filled. + * + * @return self + */ + public function setDependencyValue(array $dependent_value): self { + $this->dependentValue = $dependent_value; + return $this; + } + + public function getDependencyValue(): ?array { + return $this->dependentValue; + } + public function offsetExists(mixed $offset): bool { dump($this); throw new \Exception("Accessing definition $this->name as array with offsetExists $offset."); From e62e33bf7b3ea45ee7062bf7c95f105ec962e579 Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Sun, 25 Jan 2026 15:56:27 +0000 Subject: [PATCH 11/39] Added dependencies on plugin deriver injected services, and parent plugin replacement. --- Generator/PluginClassDiscovery.php | 10 ++++++++-- Generator/PluginYamlDiscovery.php | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Generator/PluginClassDiscovery.php b/Generator/PluginClassDiscovery.php index e8bb3f01..be663289 100644 --- a/Generator/PluginClassDiscovery.php +++ b/Generator/PluginClassDiscovery.php @@ -95,7 +95,10 @@ public static function addToGeneratorDefinition(PropertyListInterface $definitio ->setLabel('Deriver injected services') ->setDescription("Services to inject into the deriver class.") ->setMultiple(TRUE) - ->setOptionSetDefinition(\DrupalCodeBuilder\Factory::getTask('ReportServiceData')), + ->setOptionSetDefinition(\DrupalCodeBuilder\Factory::getTask('ReportServiceData')) + ->setDependencyValue([ + '..:deriver' => TRUE, + ]), 'deriver_plain_class_name' => PropertyDefinition::create('string') ->setInternal(TRUE) ->setDefault(DefaultDefinition::create() @@ -126,7 +129,10 @@ public static function addToGeneratorDefinition(PropertyListInterface $definitio ), 'replace_parent_plugin' => PropertyDefinition::create('boolean') ->setLabel('Replace parent plugin') - ->setDescription("Replace the parent plugin's class with the generated class, rather than define a new plugin."), + ->setDescription("Replace the parent plugin's class with the generated class, rather than define a new plugin.") + ->setDependencyValue([ + '..:parent_plugin_id' => TRUE, + ]), 'class_docblock_lines' => PropertyDefinition::create('mapping') ->setInternal(TRUE) ->setDefault( diff --git a/Generator/PluginYamlDiscovery.php b/Generator/PluginYamlDiscovery.php index 35351351..ea152412 100644 --- a/Generator/PluginYamlDiscovery.php +++ b/Generator/PluginYamlDiscovery.php @@ -37,7 +37,10 @@ public static function addToGeneratorDefinition(PropertyListInterface $definitio ->setLabel('Deriver injected services') ->setDescription("Services to inject into the deriver class.") ->setMultiple(TRUE) - ->setOptionSetDefinition(\DrupalCodeBuilder\Factory::getTask('ReportServiceData')), + ->setOptionSetDefinition(\DrupalCodeBuilder\Factory::getTask('ReportServiceData')) + ->setDependencyValue([ + '..:deriver' => TRUE, + ]), 'deriver_plain_class_name' => PropertyDefinition::create('string') ->setInternal(TRUE) ->setDefault(DefaultDefinition::create() @@ -96,7 +99,10 @@ public static function addToGeneratorDefinition(PropertyListInterface $definitio ->setLabel('Injected services for custom class') ->setDescription("Services to inject if using a custom plugin class.") ->setMultiple(TRUE) - ->setOptionSetDefinition(\DrupalCodeBuilder\Factory::getTask('ReportServiceData')), + ->setOptionSetDefinition(\DrupalCodeBuilder\Factory::getTask('ReportServiceData')) + ->setDependencyValue([ + '..:plugin_custom_class' => TRUE, + ]), 'prefix_name' => PropertyDefinition::create('boolean') ->setInternal(TRUE) ->setLiteralDefault(TRUE), From 6121ffe5a26dd543a71043145edbc4d5f9e0808f Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Sun, 25 Jan 2026 15:56:43 +0000 Subject: [PATCH 12/39] Added detail to label. --- Generator/RouterItem.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Generator/RouterItem.php b/Generator/RouterItem.php index c2d2ceee..08913b27 100644 --- a/Generator/RouterItem.php +++ b/Generator/RouterItem.php @@ -56,7 +56,7 @@ public static function addToGeneratorDefinition(PropertyListInterface $definitio ->setLabel('The title for the menu tab') ->setLiteralDefault('My Page'), 'base_route' => PropertyDefinition::create('string') - ->setLabel('Route that this tab shows on') + ->setLabel('Base route that this tab shows on') ]), // TODO: remove this if possible? Probably need to allow PHPClassFile From 37b6b450945cc5078ab662e09eb63e417c1a32f3 Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Sun, 25 Jan 2026 16:07:50 +0000 Subject: [PATCH 13/39] Changed preprocess_ hooks to be available for OO. Fixes #417. --- Task/Collect/HooksCollector.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Task/Collect/HooksCollector.php b/Task/Collect/HooksCollector.php index 14ebecce..d1c99244 100644 --- a/Task/Collect/HooksCollector.php +++ b/Task/Collect/HooksCollector.php @@ -279,7 +279,7 @@ protected function processHookData($hook_file_data) { $procedural = ( in_array($short_name, $obligate_procedural_hooks) || - preg_match('/^(post_update_|preprocess_|process_|update_\d+$)/', $short_name) + preg_match('/^(post_update_|process_|update_\d+$)/', $short_name) ); // Because we're working through the raw data array, we keep the incoming From 3555886337c2bd5abd924faae74a714dbc00a403 Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Mon, 26 Jan 2026 09:43:56 +0000 Subject: [PATCH 14/39] Updated tests for new class name match sniff. --- Test/Unit/Parsing/PHPTester.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Test/Unit/Parsing/PHPTester.php b/Test/Unit/Parsing/PHPTester.php index ea4b5818..e5916d43 100644 --- a/Test/Unit/Parsing/PHPTester.php +++ b/Test/Unit/Parsing/PHPTester.php @@ -126,8 +126,9 @@ public function assertDrupalCodingStandards(array $excluded_sniffs = []) { $excluded_sniffs[] = 'SlevomatCodingStandard.Commenting.ForbiddenComments'; if (empty($this->phpCodeFilePath)) { - // Exclude this sniff if we don't have access to the file name. + // Exclude the class names sniff if we don't have access to the file name. $excluded_sniffs[] = 'Squiz.Classes.ClassFileName.NoMatch'; + $excluded_sniffs[] = 'Drupal.Classes.ClassFileName.NoMatch'; } if ($this->drupalMajorVersion <= 7) { @@ -137,6 +138,7 @@ public function assertDrupalCodingStandards(array $excluded_sniffs = []) { // Drupal 7 typically has classes in .inc files, which do not match the // class name. $excluded_sniffs[] = 'Squiz.Classes.ClassFileName.NoMatch'; + $excluded_sniffs[] = 'Drupal.Classes.ClassFileName.NoMatch'; } $constraint = new CodeAdheresToCodingStandards($this->drupalMajorVersion, $excluded_sniffs, $this->phpCodeFilePath); From 7c5d2942f0463990075346e196cfa0105cf3fda7 Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Wed, 28 Jan 2026 17:36:21 +0000 Subject: [PATCH 15/39] Fixed implicit nullable param deprecation. --- Definition/OptionDefinition.php | 2 +- Definition/PresetDefinition.php | 2 +- Generator/DrushCommand.php | 2 +- Generator/PHPFunction.php | 2 +- Task/Generate.php | 2 +- Task/Generate/ComponentClassHandler.php | 2 +- Task/Generate/ComponentCollector.php | 2 +- Task/Generate/FileAssembler.php | 4 ++-- .../modules/test_analyze_9/src/Plugin/Action/Alpha.php | 2 +- Test/Unit/Parsing/FormBuilderTester.php | 2 +- Test/Unit/Parsing/PHPTester.php | 2 +- Test/Unit/TestBase.php | 4 ++-- Utility/NestedArray.php | 2 +- 13 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Definition/OptionDefinition.php b/Definition/OptionDefinition.php index b01ce8e4..c6c45f74 100644 --- a/Definition/OptionDefinition.php +++ b/Definition/OptionDefinition.php @@ -37,7 +37,7 @@ public function __construct( * * @return static */ - public static function create($value, string $label, string $description = NULL, int $weight = 0, ?string $api_url = NULL): self { + public static function create($value, string $label, ?string $description = NULL, int $weight = 0, ?string $api_url = NULL): self { return new static($value, $label, $description, $weight, $api_url); } diff --git a/Definition/PresetDefinition.php b/Definition/PresetDefinition.php index c2a0e211..e93eb58e 100644 --- a/Definition/PresetDefinition.php +++ b/Definition/PresetDefinition.php @@ -57,7 +57,7 @@ public function __construct($value, $label, $description = NULL) { * * @return static */ - public static function create($value, string $label, string $description = NULL): self { + public static function create($value, string $label, ?string $description = NULL): self { return new static($value, $label, $description); } diff --git a/Generator/DrushCommand.php b/Generator/DrushCommand.php index c81a4b03..c15a0a75 100644 --- a/Generator/DrushCommand.php +++ b/Generator/DrushCommand.php @@ -309,7 +309,7 @@ protected function getFunctionAttributes(): array { /** * {@inheritdoc} */ - protected function buildMethodDeclaration($name, $parameters = [], $options = [], string $return_type = NULL): array { + protected function buildMethodDeclaration($name, $parameters = [], $options = [], ?string $return_type = NULL): array { $parameters = []; // Add command parameters. diff --git a/Generator/PHPFunction.php b/Generator/PHPFunction.php index a335d78a..f6cfb071 100644 --- a/Generator/PHPFunction.php +++ b/Generator/PHPFunction.php @@ -406,7 +406,7 @@ protected function getFunctionAttributes(): array { * @return array * An array of code lines. */ - protected function buildMethodDeclaration($name, $parameters = [], $options = [], string $return_type = NULL): array { + protected function buildMethodDeclaration($name, $parameters = [], $options = [], ?string $return_type = NULL): array { $options += [ 'prefixes' => [], 'break_declaration' => FALSE, diff --git a/Task/Generate.php b/Task/Generate.php index 5330815f..d33d4161 100644 --- a/Task/Generate.php +++ b/Task/Generate.php @@ -111,7 +111,7 @@ public function getRootComponentData($component_type = 'module') { * @throws \DrupalCodeBuilder\Exception\InvalidInputException * Throws an exception if the given data is invalid. */ - public function generateComponent(DataItem $component_data, $existing_module_files = [], DataItem $configuration = NULL, DrupalExtension $existing_extension = NULL) { + public function generateComponent(DataItem $component_data, $existing_module_files = [], ?DataItem $configuration = NULL, ?DrupalExtension $existing_extension = NULL) { // Validate to ensure defaults are filled in. $component_data->validate(); diff --git a/Task/Generate/ComponentClassHandler.php b/Task/Generate/ComponentClassHandler.php index b616d2a5..1e909dbe 100644 --- a/Task/Generate/ComponentClassHandler.php +++ b/Task/Generate/ComponentClassHandler.php @@ -54,7 +54,7 @@ public function __construct( * @throws \InvalidArgumentException * Throws an exception if there is no class found for the component type. */ - public function getStandaloneComponentPropertyDefinition(string $component_type, string $machine_name = NULL): PropertyDefinition { + public function getStandaloneComponentPropertyDefinition(string $component_type, ?string $machine_name = NULL): PropertyDefinition { $definition = MergingGeneratorDefinition::createFromGeneratorType($component_type); if (!$definition->getName()) { diff --git a/Task/Generate/ComponentCollector.php b/Task/Generate/ComponentCollector.php index 3b89546a..cbf5f68f 100644 --- a/Task/Generate/ComponentCollector.php +++ b/Task/Generate/ComponentCollector.php @@ -174,7 +174,7 @@ public function __construct( * @return \DrupalCodeBuilder\Generator\Collection\ComponentCollection * The collection of components. */ - public function assembleComponentList(DataItem $component_data, DrupalExtension $extension = NULL): ComponentCollection { + public function assembleComponentList(DataItem $component_data, ?DrupalExtension $extension = NULL): ComponentCollection { // Reset all class properties. We don't normally run this twice, but // probably needed for tests. $this->requested_data_record = []; diff --git a/Task/Generate/FileAssembler.php b/Task/Generate/FileAssembler.php index f232274d..c2cb4b1d 100644 --- a/Task/Generate/FileAssembler.php +++ b/Task/Generate/FileAssembler.php @@ -23,7 +23,7 @@ class FileAssembler { * are filepaths relative to the module folder (eg, 'foo.module', * 'tests/module.test'). */ - public function generateFiles($component_data, ComponentCollection $component_collection, DrupalExtension $existing_extension = NULL) { + public function generateFiles($component_data, ComponentCollection $component_collection, ?DrupalExtension $existing_extension = NULL) { $component_list = $component_collection->getComponents(); // Let each file component in the tree gather data from its own children. @@ -73,7 +73,7 @@ protected function collectFileContents(ComponentCollection $component_collection * are filepaths relative to the module folder (eg, 'foo.module', * 'tests/module.test'). */ - protected function collectFiles(ComponentCollection $component_collection, DrupalExtension $existing_extension = NULL): array { + protected function collectFiles(ComponentCollection $component_collection, ?DrupalExtension $existing_extension = NULL): array { $code_files = []; // Components which provide a file should have registered themselves as diff --git a/Test/Fixtures/modules/test_analyze_9/src/Plugin/Action/Alpha.php b/Test/Fixtures/modules/test_analyze_9/src/Plugin/Action/Alpha.php index 42573a50..5e441986 100644 --- a/Test/Fixtures/modules/test_analyze_9/src/Plugin/Action/Alpha.php +++ b/Test/Fixtures/modules/test_analyze_9/src/Plugin/Action/Alpha.php @@ -76,7 +76,7 @@ public function executeMultiple(array $objects) { /** * {@inheritdoc} */ - public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) { + public function access($object, ?AccountInterface $account = NULL, $return_as_object = FALSE) { // Checks object access. } diff --git a/Test/Unit/Parsing/FormBuilderTester.php b/Test/Unit/Parsing/FormBuilderTester.php index 973f409f..d0b483f5 100644 --- a/Test/Unit/Parsing/FormBuilderTester.php +++ b/Test/Unit/Parsing/FormBuilderTester.php @@ -272,7 +272,7 @@ public function assertElementIsRequired($element_name, $message = NULL) { * @param string $message * (optional) The assertion message. */ - public function assertElementHasAttribute(string $attribute_name, string $element_name, string $message = NULL) { + public function assertElementHasAttribute(string $attribute_name, string $element_name, ?string $message = NULL) { $message = $message ?? "The form's '{$element_name}' element has the attribute '{$attribute_name}'."; $this->assertHasElementName($element_name); diff --git a/Test/Unit/Parsing/PHPTester.php b/Test/Unit/Parsing/PHPTester.php index e5916d43..4c38e9a6 100644 --- a/Test/Unit/Parsing/PHPTester.php +++ b/Test/Unit/Parsing/PHPTester.php @@ -776,7 +776,7 @@ public function assertNotClassHasInterfaces($not_expected_interface_names) { * @param string $message * (optional) The assertion message. */ - public function assertClassHasConstant(string $name, string $message = NULL) { + public function assertClassHasConstant(string $name, ?string $message = NULL) { $message ??= "The class has the constant '$name'."; Assert::assertArrayHasKey($name, $this->parser_nodes['constants'], $message); diff --git a/Test/Unit/TestBase.php b/Test/Unit/TestBase.php index 6d6f77d7..41573c0c 100644 --- a/Test/Unit/TestBase.php +++ b/Test/Unit/TestBase.php @@ -121,7 +121,7 @@ protected function getMockedExtension(string $type, array $files = []) { * @param * An array of files. */ - protected function generateComponentFilesFromData(DataItem $component_data, DrupalExtension $extension = NULL) { + protected function generateComponentFilesFromData(DataItem $component_data, ?DrupalExtension $extension = NULL) { $violations = $component_data->validate(); if ($violations) { @@ -146,7 +146,7 @@ protected function generateComponentFilesFromData(DataItem $component_data, Drup * @param * An array of files. */ - protected function generateModuleFiles(array $module_data, DrupalExtension $extension = NULL) { + protected function generateModuleFiles(array $module_data, ?DrupalExtension $extension = NULL) { $component_data = $this->getRootComponentBlankData('module'); $component_data->set($module_data); diff --git a/Utility/NestedArray.php b/Utility/NestedArray.php index 0dddc84f..f008a3bc 100644 --- a/Utility/NestedArray.php +++ b/Utility/NestedArray.php @@ -361,7 +361,7 @@ public static function mergeDeepArray(array $arrays, $preserve_integer_keys = FA * @return array * The filtered array. */ - public static function filter(array $array, callable $callable = NULL) { + public static function filter(array $array, ?callable $callable = NULL) { $array = is_callable($callable) ? array_filter($array, $callable) : array_filter($array); foreach ($array as &$element) { if (is_array($element)) { From 7ec94fa47cb704aa9ce5c2efff275bf672e5ba4e Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Sat, 7 Feb 2026 17:41:33 +0000 Subject: [PATCH 16/39] Added content entity properties for revisions UI. Fixes #402. --- .../DrupalCodeBuilderCompiledContainer.php | 4 ++ Generator/ContentEntityType.php | 45 ++++++++++++--- Generator/ContentEntityType9AndLower.php | 24 ++++++++ .../Unit/ComponentContentEntityType10Test.php | 41 +++++++++++++ Test/Unit/ComponentContentEntityType9Test.php | 57 +++++++++++++++++++ 5 files changed, 162 insertions(+), 9 deletions(-) create mode 100644 Generator/ContentEntityType9AndLower.php create mode 100644 Test/Unit/ComponentContentEntityType9Test.php diff --git a/DependencyInjection/cache/DrupalCodeBuilderCompiledContainer.php b/DependencyInjection/cache/DrupalCodeBuilderCompiledContainer.php index f4e38b35..8063a636 100644 --- a/DependencyInjection/cache/DrupalCodeBuilderCompiledContainer.php +++ b/DependencyInjection/cache/DrupalCodeBuilderCompiledContainer.php @@ -233,6 +233,10 @@ protected function get3() return [ 'AdminSettingsForm' => [ 7 => 'AdminSettingsForm7', + ], + 'ContentEntityType' => [ + 9 => 'ContentEntityType9AndLower', + 8 => 'ContentEntityType9AndLower', ], 'DrushCommand' => [ 11 => 'DrushCommand', diff --git a/Generator/ContentEntityType.php b/Generator/ContentEntityType.php index 488aa02a..82dac940 100644 --- a/Generator/ContentEntityType.php +++ b/Generator/ContentEntityType.php @@ -560,13 +560,18 @@ public function requiredComponents(): array { protected function getAnnotationData() { $annotation_data = parent::getAnnotationData(); + $revisionable = in_array('revisionable', $this->component_data['functionality']); + $translatable = in_array('translatable', $this->component_data['functionality']); + $ui = !empty($this->component_data['entity_ui']); + // Add further annotation properties. // Use the entity type ID as the base table. $annotation_data['base_table'] = $this->component_data['entity_type_id']; - if (!empty($this->component_data['entity_ui'])) { + if ($ui) { $annotation_data['links'] = []; $entity_path_component = $this->component_data['entity_type_id']; + $entity_path_placeholder = "{{$entity_path_component}}"; // The structure of the add UI depends on whether there is a bundle // entity. @@ -584,12 +589,10 @@ protected function getAnnotationData() { $annotation_data['links']["add-form"] = "/$entity_path_component/add"; } - $annotation_data['links']["canonical"] = "/$entity_path_component/{{$entity_path_component}}"; + $annotation_data['links']["canonical"] = "/$entity_path_component/$entity_path_placeholder"; $annotation_data['links']["collection"] = "/admin/content/$entity_path_component"; - $annotation_data['links']["delete-form"] = "/$entity_path_component/{{$entity_path_component}}/delete"; - $annotation_data['links']["edit-form"] = "/$entity_path_component/{{$entity_path_component}}/edit"; - // TODO: revision link template. - // $annotation_data['links']["revision"] = "/$entity_path_component/{}/revisions/{media_revision}/view"; + $annotation_data['links']["delete-form"] = "/$entity_path_component/$entity_path_placeholder/delete"; + $annotation_data['links']["edit-form"] = "/$entity_path_component/$entity_path_placeholder/edit"; } if (!$this->component_data->bundle_entity->isEmpty()) { @@ -597,9 +600,6 @@ protected function getAnnotationData() { $annotation_data['bundle_label'] = ClassAnnotation::Translation($this->component_data['bundle_label']); } - $revisionable = in_array('revisionable', $this->component_data['functionality']); - $translatable = in_array('translatable', $this->component_data['functionality']); - if ($this->component_data->field_ui_base_route->value) { $annotation_data['field_ui_base_route'] = $this->component_data->field_ui_base_route->value; } @@ -617,7 +617,34 @@ protected function getAnnotationData() { $annotation_data['revision_data_table'] = "{$annotation_data['base_table']}_field_revision"; } + if ($ui && $revisionable) { + $this->addRevisionUiAnnotationData($annotation_data); + } + return $annotation_data; } + /** + * Adds annotation data for revisions UI. + * + * @param array &$annotation_data + * The annotation data. + */ + protected function addRevisionUiAnnotationData(&$annotation_data) { + $entity_path_component = $this->component_data->entity_type_id->value; + $entity_path_placeholder = "{{$entity_path_component}}"; + $entity_revision_path_placeholder = "{{$entity_path_component}_revision}"; + + $annotation_data['handlers']['route_provider']['revision'] = 'Drupal\Core\Entity\Routing\RevisionHtmlRouteProvider'; + + $annotation_data['handlers']['form']['revision-delete'] = 'Drupal\Core\Entity\Form\RevisionDeleteForm'; + $annotation_data['handlers']['form']['revision-revert'] = 'Drupal\Core\Entity\Form\RevisionRevertForm'; + + $annotation_data['links']['version-history'] = "/$entity_path_component/$entity_path_placeholder/revisions"; + $annotation_data['links']['revision'] = "/$entity_path_component/$entity_path_placeholder/revisions/$entity_revision_path_placeholder/view"; + $annotation_data['links']['revision-delete-form'] = "/$entity_path_component/$entity_path_placeholder/revisions/$entity_revision_path_placeholder/view"; + $annotation_data['links']['revision-revert-form'] = "/$entity_path_component/$entity_path_placeholder/revisions/$entity_revision_path_placeholder/revert"; + $annotation_data['links']['version-history'] = "/$entity_path_component/$entity_path_placeholder/revisions"; + } + } diff --git a/Generator/ContentEntityType9AndLower.php b/Generator/ContentEntityType9AndLower.php new file mode 100644 index 00000000..12a57446 --- /dev/null +++ b/Generator/ContentEntityType9AndLower.php @@ -0,0 +1,24 @@ +assertHasLine('$form_state->setRedirectUrl($this->entity->toUrl(\'canonical\'));'); } + /** + * Tests creating a content entity with a revision UI. + * + * @group entity_ui + * @group form + */ + public function testContentEntityTypeWithRevisionEntityUI() { + $module_name = 'test_module'; + $module_data = [ + 'base' => 'module', + 'root_name' => $module_name, + 'readable_name' => 'Test module', + 'content_entity_types' => [ + 0 => [ + 'entity_type_id' => 'kitty_cat', + 'functionality' => [ + 'revisionable', + ], + 'entity_ui' => 'admin', + ], + ], + 'readme' => FALSE, + ]; + + $files = $this->generateModuleFiles($module_data); + + $entity_class_file = $files['src/Entity/KittyCat.php']; + $php_tester = PHPTester::fromCodeFile($this->drupalMajorVersion, $entity_class_file); + $annotation_tester = $php_tester->getAnnotationTesterForClass(); + + $annotation_tester->assertPropertyHasValue(['handlers', 'route_provider', 'revision'], 'Drupal\Core\Entity\Routing\RevisionHtmlRouteProvider'); + + $annotation_tester->assertPropertyHasValue(['handlers', 'form', 'revision-delete'], 'Drupal\Core\Entity\Form\RevisionDeleteForm'); + $annotation_tester->assertPropertyHasValue(['handlers', 'form', 'revision-revert'], 'Drupal\Core\Entity\Form\RevisionRevertForm'); + + $annotation_tester->assertPropertyHasValue(['links', 'revision'], '/kitty_cat/{kitty_cat}/revisions/{kitty_cat_revision}/view'); + $annotation_tester->assertPropertyHasValue(['links', 'revision-delete-form'], '/kitty_cat/{kitty_cat}/revisions/{kitty_cat_revision}/view'); + $annotation_tester->assertPropertyHasValue(['links', 'revision-revert-form'], '/kitty_cat/{kitty_cat}/revisions/{kitty_cat_revision}/revert'); + $annotation_tester->assertPropertyHasValue(['links', 'version-history'], '/kitty_cat/{kitty_cat}/revisions'); + } + /** * Tests creating a content entity with a bundle entity UI. * diff --git a/Test/Unit/ComponentContentEntityType9Test.php b/Test/Unit/ComponentContentEntityType9Test.php new file mode 100644 index 00000000..b9017571 --- /dev/null +++ b/Test/Unit/ComponentContentEntityType9Test.php @@ -0,0 +1,57 @@ + 'module', + 'root_name' => $module_name, + 'readable_name' => 'Test module', + 'content_entity_types' => [ + 0 => [ + 'entity_type_id' => 'kitty_cat', + 'functionality' => [ + 'revisionable', + ], + 'entity_ui' => 'admin', + ], + ], + 'readme' => FALSE, + ]; + + $files = $this->generateModuleFiles($module_data); + + $entity_class_file = $files['src/Entity/KittyCat.php']; + $php_tester = PHPTester::fromCodeFile($this->drupalMajorVersion, $entity_class_file); + $annotation_tester = $php_tester->getAnnotationTesterForClass(); + + $annotation_tester->assertNotHasProperty(['handlers', 'route_provider', 'revision']); + } + +} From 52d036d7e3930892bcfb2075b91d094c6f52cda5 Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Sat, 7 Feb 2026 17:41:55 +0000 Subject: [PATCH 17/39] Fixed missing revision metadata keys on content entities using revisions. --- Generator/ContentEntityType.php | 7 +++++++ Test/Unit/ComponentContentEntityType10Test.php | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/Generator/ContentEntityType.php b/Generator/ContentEntityType.php index 82dac940..00aa42cf 100644 --- a/Generator/ContentEntityType.php +++ b/Generator/ContentEntityType.php @@ -41,6 +41,7 @@ class ContentEntityType extends EntityTypeBase { 'handlers', 'admin_permission', 'entity_keys', + 'revision_metadata_keys', 'bundle_entity_type', 'field_ui_base_route', 'links', @@ -606,6 +607,12 @@ protected function getAnnotationData() { if ($revisionable) { $annotation_data['revision_table'] = "{$annotation_data['base_table']}_revision"; + + $annotation_data['revision_metadata_keys'] = [ + 'revision_user' => 'revision_uid', + 'revision_created' => 'revision_timestamp', + 'revision_log_message' => 'revision_log' + ]; } if ($translatable) { diff --git a/Test/Unit/ComponentContentEntityType10Test.php b/Test/Unit/ComponentContentEntityType10Test.php index 6c6cfb44..5f2b6ea5 100644 --- a/Test/Unit/ComponentContentEntityType10Test.php +++ b/Test/Unit/ComponentContentEntityType10Test.php @@ -594,6 +594,7 @@ public function testEntityTypeWithRevisions() { 'handlers', 'admin_permission', 'entity_keys', + 'revision_metadata_keys', 'field_ui_base_route', ]); $annotation_tester->assertPropertyHasValue('base_table', 'kitty_cat'); @@ -606,6 +607,10 @@ public function testEntityTypeWithRevisions() { ], 'entity_keys'); $annotation_tester->assertPropertyHasValue(['entity_keys', 'id'], 'kitty_cat_id'); $annotation_tester->assertPropertyHasValue(['entity_keys', 'revision'], 'revision_id'); + + $annotation_tester->assertPropertyHasValue(['revision_metadata_keys', 'revision_user'], 'revision_uid'); + $annotation_tester->assertPropertyHasValue(['revision_metadata_keys', 'revision_created'], 'revision_timestamp'); + $annotation_tester->assertPropertyHasValue(['revision_metadata_keys', 'revision_log_message'], 'revision_log'); } /** From 0bc257f1330bbbb48f02e8bef419280ba58fcf44 Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Sun, 8 Feb 2026 10:25:16 +0000 Subject: [PATCH 18/39] Added default container injection interface to base DI class. --- Generator/Controller.php | 5 ----- Generator/DrushCommandsClass.php | 5 +++++ Generator/DynamicRouteProvider.php | 5 ----- Generator/Form.php | 5 ----- Generator/PHPClassFileWithInjection.php | 2 +- Generator/Service.php | 5 +++++ 6 files changed, 11 insertions(+), 16 deletions(-) diff --git a/Generator/Controller.php b/Generator/Controller.php index ffb886ad..835219e3 100644 --- a/Generator/Controller.php +++ b/Generator/Controller.php @@ -9,11 +9,6 @@ */ class Controller extends PHPClassFileWithInjection { - /** - * {@inheritdoc} - */ - protected const CLASS_DI_INTERFACE = '\Drupal\Core\DependencyInjection\ContainerInjectionInterface'; - /** * {@inheritdoc} */ diff --git a/Generator/DrushCommandsClass.php b/Generator/DrushCommandsClass.php index 233bec4b..87e7e769 100644 --- a/Generator/DrushCommandsClass.php +++ b/Generator/DrushCommandsClass.php @@ -9,6 +9,11 @@ */ class DrushCommandsClass extends PHPClassFileWithInjection { + /** + * {@inheritdoc} + */ + protected const CLASS_DI_INTERFACE = NULL; + /** * {@inheritdoc} */ diff --git a/Generator/DynamicRouteProvider.php b/Generator/DynamicRouteProvider.php index c17248b8..d4d46d15 100644 --- a/Generator/DynamicRouteProvider.php +++ b/Generator/DynamicRouteProvider.php @@ -12,11 +12,6 @@ */ class DynamicRouteProvider extends PHPClassFileWithInjection { - /** - * {@inheritdoc} - */ - protected const CLASS_DI_INTERFACE = '\Drupal\Core\DependencyInjection\ContainerInjectionInterface'; - /** * {@inheritdoc} */ diff --git a/Generator/Form.php b/Generator/Form.php index 7aa1099d..c18c933b 100644 --- a/Generator/Form.php +++ b/Generator/Form.php @@ -19,11 +19,6 @@ */ class Form extends PHPClassFileWithInjection implements AdoptableInterface { - /** - * {@inheritdoc} - */ - protected const CLASS_DI_INTERFACE = '\Drupal\Core\DependencyInjection\ContainerInjectionInterface'; - /** * {@inheritdoc} */ diff --git a/Generator/PHPClassFileWithInjection.php b/Generator/PHPClassFileWithInjection.php index 25936d60..6ca53ed1 100644 --- a/Generator/PHPClassFileWithInjection.php +++ b/Generator/PHPClassFileWithInjection.php @@ -18,7 +18,7 @@ class PHPClassFileWithInjection extends PHPClassFile { * * @var string|null */ - protected const CLASS_DI_INTERFACE = NULL; + protected const CLASS_DI_INTERFACE = '\Drupal\Core\DependencyInjection\ContainerInjectionInterface'; /** * The interface to use for the static create() method's container parameter. diff --git a/Generator/Service.php b/Generator/Service.php index c159c687..7c5b704e 100644 --- a/Generator/Service.php +++ b/Generator/Service.php @@ -16,6 +16,11 @@ */ class Service extends PHPClassFileWithInjection implements AdoptableInterface { + /** + * {@inheritdoc} + */ + protected const CLASS_DI_INTERFACE = NULL; + use NameFormattingTrait; /** From e2a4902f6c5eff88dbc9625636702ecf31e5eb8a Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Sun, 8 Feb 2026 11:59:56 +0000 Subject: [PATCH 19/39] Fixed DI code on constraint plugin going in the plugin rather than the validator class. Fixes #381. --- Generator/PluginValidationConstraint.php | 12 ++++++++++-- Test/Unit/ComponentPluginsAttribute11Test.php | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/Generator/PluginValidationConstraint.php b/Generator/PluginValidationConstraint.php index 768e0b75..99c7d824 100644 --- a/Generator/PluginValidationConstraint.php +++ b/Generator/PluginValidationConstraint.php @@ -17,11 +17,13 @@ class PluginValidationConstraint extends PluginClassDiscoveryHybrid { * Return an array of subcomponent types. */ public function requiredComponents(): array { - $components = parent::requiredComponents(); + $components = []; $components['validator'] = [ - 'component_type' => 'PHPClassFile', + 'component_type' => 'PHPClassFileWithInjection', 'plain_class_name' => $this->component_data['plain_class_name'] . 'Validator', + 'injected_services' => $this->component_data->injected_services->values(), + 'use_static_factory_method' => TRUE, 'relative_namespace' => $this->component_data['relative_namespace'], 'parent_class_name' => '\Symfony\Component\Validator\ConstraintValidator', 'docblock_first_line' => "Validates the {$this->component_data['plain_class_name']} constraint.", @@ -30,6 +32,12 @@ public function requiredComponents(): array { // See https://github.com/drupal-code-builder/drupal-code-builder/issues/134 ]; + // Zap the injected services set here, as we don't want the plugin class to + // have any DI. + $this->component_data->injected_services = []; + + $components += parent::requiredComponents(); + $components['validator_validate'] = [ 'component_type' => 'PHPFunction', 'function_name' => 'validate', diff --git a/Test/Unit/ComponentPluginsAttribute11Test.php b/Test/Unit/ComponentPluginsAttribute11Test.php index 0077276d..09bbbe32 100644 --- a/Test/Unit/ComponentPluginsAttribute11Test.php +++ b/Test/Unit/ComponentPluginsAttribute11Test.php @@ -598,6 +598,8 @@ function testPluginsGenerationWithOtherSchema() { /** * Test the validation constraint plugin variant. + * + * @group di */ public function testPluginValidationConstraint(): void { // Create a module. @@ -611,6 +613,9 @@ public function testPluginValidationConstraint(): void { 0 => [ 'plugin_type' => 'validation.constraint', 'plugin_name' => 'alpha', + 'injected_services' => [ + 'entity_type.manager', + ], ], ], 'readme' => FALSE, @@ -639,6 +644,20 @@ public function testPluginValidationConstraint(): void { $php_tester->assertHasClass('Drupal\test_module\Plugin\Validation\Constraint\AlphaValidator'); $php_tester->assertClassHasParent('Symfony\Component\Validator\ConstraintValidator'); $php_tester->assertHasMethod('validate'); + + // Check service injection. + $php_tester->assertClassHasInterfaces([ + 'Drupal\Core\DependencyInjection\ContainerInjectionInterface', + ]); + $php_tester->assertInjectedServicesWithFactory([ + [ + 'typehint' => 'Drupal\Core\Entity\EntityTypeManagerInterface', + 'service_name' => 'entity_type.manager', + 'property_name' => 'entityTypeManager', + 'parameter_name' => 'entity_type_manager', + ], + ]); + } } From e4ce6a5e3a821c3721fa3c34d679b1179b7c3974 Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Mon, 9 Feb 2026 13:50:07 +0000 Subject: [PATCH 20/39] Fixed (temporarily!) crash caused by analysis of BlockContentCreationTrait. --- Task/Analyse/TestTraits.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Task/Analyse/TestTraits.php b/Task/Analyse/TestTraits.php index 4d67c093..9448767f 100644 --- a/Task/Analyse/TestTraits.php +++ b/Task/Analyse/TestTraits.php @@ -120,6 +120,12 @@ public function collect($job_list) { $short_trait_name = $file->getFilenameWithoutExtension(); + // Temporary workaround. + // See https://github.com/drupal-code-builder/drupal-code-builder/issues/420. + if ($short_trait_name == 'BlockContentCreationTrait') { + continue; + } + // Files in test folders aren't in the regular Composer autoloader, so // include the file so we can use reflection on the class. include_once($relative_pathname); From 28a9c0e7429135152e7d03891e55e772596afa97 Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Mon, 9 Feb 2026 13:54:35 +0000 Subject: [PATCH 21/39] Fixed NULL offset. --- Task/ReportPluginData.php | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/Task/ReportPluginData.php b/Task/ReportPluginData.php index d7b711e3..da305b85 100644 --- a/Task/ReportPluginData.php +++ b/Task/ReportPluginData.php @@ -74,17 +74,21 @@ public function getVariantMapping(): array { * The processed plugin data. * * @see \DrupalCodeBuilder\Task\Collect::gatherPluginTypeInfo() + * + * @todo Split this method into two. */ function listPluginData($discovery_type = NULL) { - // We may come here several times, so cache this. - // TODO: look into finer-grained caching higher up. - if (isset($this->cache[$discovery_type])) { - return $this->cache[$discovery_type]; + if ($discovery_type) { + // We may come here several times, so cache a filtered result. + // TODO: look into finer-grained caching higher up. + if (isset($this->cache[$discovery_type])) { + return $this->cache[$discovery_type]; + } } $plugin_data = $this->environment->getStorage()->retrieve('plugins'); - // Filter the plugins by the discovery type. + // Filter the plugins if there's a requested discovery type. if ($discovery_type) { $plugin_data = array_filter($plugin_data, function($item) use ($discovery_type) { $discovery_pieces = explode('\\', $item['discovery']); @@ -92,9 +96,9 @@ function listPluginData($discovery_type = NULL) { return ($discovery_short_name == $discovery_type); }); - } - $this->cache[$discovery_type] = $plugin_data; + $this->cache[$discovery_type] = $plugin_data; + } return $plugin_data; } From b95830b765db0e12a38846ea9e77761a7b6f84bb Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Mon, 9 Feb 2026 13:55:12 +0000 Subject: [PATCH 22/39] Fixed generator type for generator classes with version attributes. Fixes #384. --- Generator/BaseGenerator.php | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Generator/BaseGenerator.php b/Generator/BaseGenerator.php index c3aed17a..51b67d01 100644 --- a/Generator/BaseGenerator.php +++ b/Generator/BaseGenerator.php @@ -2,6 +2,7 @@ namespace DrupalCodeBuilder\Generator; +use DrupalCodeBuilder\Attribute\RelatedBaseClass; use MutableTypedData\Definition\PropertyListInterface; use DrupalCodeBuilder\Generator\Collection\ComponentCollection; use DrupalCodeBuilder\Definition\PropertyDefinition; @@ -194,9 +195,16 @@ function __construct(DataItem $component_data) { // Set the type. This is the short class name without the numeric version // suffix. $class = get_class($this); - $class_pieces = explode('\\', $class); - $short_class = array_pop($class_pieces); - $this->type = preg_replace('@\d+$@', '', $short_class); + + $reflector = new \ReflectionClass($class); + if ($base_class_attributes = $reflector->getAttributes(RelatedBaseClass::class)) { + $this->type = $base_class_attributes[0]->newInstance()->base_class; + } + else { + $class_pieces = explode('\\', $class); + $short_class = array_pop($class_pieces); + $this->type = preg_replace('@\d+$@', '', $short_class); + } } /** From 1f5be93d8b98378ca21e177a8066e471ba1db9a7 Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Mon, 23 Feb 2026 15:20:32 +0000 Subject: [PATCH 23/39] Fixed naive loading of test trait files not working for trait inheritance and non-installed modules. Fixes #420. --- Task/Analyse/TestTraits.php | 44 +++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/Task/Analyse/TestTraits.php b/Task/Analyse/TestTraits.php index 9448767f..0af1fa3a 100644 --- a/Task/Analyse/TestTraits.php +++ b/Task/Analyse/TestTraits.php @@ -2,12 +2,14 @@ namespace DrupalCodeBuilder\Task\Analyse; -use MutableTypedData\Definition\OptionSetDefininitionInterface; +use Composer\Autoload\ClassLoader; use DrupalCodeBuilder\Environment\EnvironmentInterface; use DrupalCodeBuilder\Task\Collect\CollectorBase; use DrupalCodeBuilder\Task\Report\SectionReportInterface; use DrupalCodeBuilder\Task\SectionReportSimpleCountTrait; use DrupalCodeBuilder\Definition\OptionDefinition; +use Drupal\Core\Extension\ExtensionDiscovery; +use MutableTypedData\Definition\OptionSetDefininitionInterface; /** * Task helper for analysing and reporting on traits intended for use in tests. @@ -74,6 +76,36 @@ public function getJobList() { * {@inheritdoc} */ public function collect($job_list) { + // Set up an autoloader, as test code is not included in Composer's project + // autoloader. Traits may extend other traits, so we can't just include + // files naively. + $loader = new ClassLoader(); + + $drupal_test_dir = $this->environment->getRoot() . '/core/tests'; + + $loader->add('Drupal\\BuildTests', $drupal_test_dir); + $loader->add('Drupal\\Tests', $drupal_test_dir); + $loader->add('Drupal\\TestSite', $drupal_test_dir); + $loader->add('Drupal\\KernelTests', $drupal_test_dir); + $loader->add('Drupal\\FunctionalTests', $drupal_test_dir); + $loader->add('Drupal\\FunctionalJavascriptTests', $drupal_test_dir); + $loader->add('Drupal\\TestTools', $drupal_test_dir); + + $root = $this->environment->getRoot() . '/'; + + // We need to include all discovered modules, not just enabled ones, as our + // Finder looks at all code, and installed modules may have traits which + // inherit from non-installed modules. + // Safe to use this as ExtensionDiscovery was introduced in 8.0.0. + $discovery = new ExtensionDiscovery($root); + $discovery->setProfileDirectories([]); + $discovered_modules = $discovery->scan('module'); + foreach ($discovered_modules as $module_name => $module_extension) { + $loader->addPsr4('Drupal\\Tests\\' . $module_name . '\\', $root . $module_extension->getPath() . '/tests/src'); + } + + $loader->register(); + $finder = new \Symfony\Component\Finder\Finder(); $finder ->in($this->environment->getRoot()) @@ -120,16 +152,6 @@ public function collect($job_list) { $short_trait_name = $file->getFilenameWithoutExtension(); - // Temporary workaround. - // See https://github.com/drupal-code-builder/drupal-code-builder/issues/420. - if ($short_trait_name == 'BlockContentCreationTrait') { - continue; - } - - // Files in test folders aren't in the regular Composer autoloader, so - // include the file so we can use reflection on the class. - include_once($relative_pathname); - $class_reflection = new \ReflectionClass($classname); $docblock = $class_reflection->getDocComment(); From 855e80f8a8c89fa5fa52e2106241fd8f6982269b Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Mon, 23 Feb 2026 15:33:20 +0000 Subject: [PATCH 24/39] Updated for deprecated setAccessible(). --- Task/Collect/ContainerBuilderGetter.php | 4 +- Task/Collect/PluginTypesCollector.php | 43 +++++++++++++++---- .../CollectPluginInfoDummyModulesTest.php | 5 ++- .../Collection/CollectPluginInfoTest.php | 5 ++- .../Installation/InstallationTestBase.php | 5 ++- Test/Unit/ComponentPHPFile10Test.php | 5 ++- Test/Unit/ContainerCollectionTest.php | 5 ++- Test/Unit/ContainerTest.php | 20 +++++++-- 8 files changed, 73 insertions(+), 19 deletions(-) diff --git a/Task/Collect/ContainerBuilderGetter.php b/Task/Collect/ContainerBuilderGetter.php index d4c5e5ed..17f552a8 100644 --- a/Task/Collect/ContainerBuilderGetter.php +++ b/Task/Collect/ContainerBuilderGetter.php @@ -27,7 +27,9 @@ public function getContainerBuilder() { $kernel_R = new \ReflectionClass($kernel); $compileContainer_R = $kernel_R->getMethod('compileContainer'); - $compileContainer_R->setAccessible(TRUE); + if (version_compare(PHP_VERSION, '8.1.0', '<')) { + $compileContainer_R->setAccessible(TRUE); + } $this->containerBuilder = $compileContainer_R->invoke($kernel); } diff --git a/Task/Collect/PluginTypesCollector.php b/Task/Collect/PluginTypesCollector.php index 53997371..3ef1c592 100644 --- a/Task/Collect/PluginTypesCollector.php +++ b/Task/Collect/PluginTypesCollector.php @@ -366,7 +366,9 @@ protected function addPluginTypeServiceData(&$data) { // Determine the alter hook name. if ($service_reflection->hasProperty('alterHook')) { $property_alter_hook = $service_reflection->getProperty('alterHook'); - $property_alter_hook->setAccessible(TRUE); + if (version_compare(PHP_VERSION, '8.1.0', '<')) { + $property_alter_hook->setAccessible(TRUE); + } $alter_hook_name = $property_alter_hook->getValue($service); if (!empty($alter_hook_name)) { $data['alter_hook_name'] = $alter_hook_name . '_alter'; @@ -376,7 +378,9 @@ protected function addPluginTypeServiceData(&$data) { // Determine the plugin discovery type. // Get the discovery object from the plugin manager. $method_getDiscovery = $service_reflection->getMethod('getDiscovery'); - $method_getDiscovery->setAccessible(TRUE); + if (version_compare(PHP_VERSION, '8.1.0', '<')) { + $method_getDiscovery->setAccessible(TRUE); + } $discovery = $method_getDiscovery->invoke($service); $reflection_discovery = new \ReflectionClass($discovery); @@ -396,7 +400,10 @@ protected function addPluginTypeServiceData(&$data) { break; } - $property_decorated->setAccessible(TRUE); + if (version_compare(PHP_VERSION, '8.1.0', '<')) { + $property_decorated->setAccessible(TRUE); + } + $decorated_discovery = $property_decorated->getValue($discovery); // We don't go in to a decorated class that's not in a Plugin component. @@ -525,7 +532,10 @@ protected function addPluginTypeServiceDataAttribute(&$data, $service, $discover } $property = $reflection->getProperty($property_name); - $property->setAccessible(TRUE); + if (version_compare(PHP_VERSION, '8.1.0', '<')) { + $property->setAccessible(TRUE); + } + $data[$data_key] = $property->getValue($service) ?? ''; } @@ -570,7 +580,10 @@ protected function addPluginTypeServiceDataAnnotated(&$data, $service, $discover } $property = $reflection->getProperty($property_name); - $property->setAccessible(TRUE); + if (version_compare(PHP_VERSION, '8.1.0', '<')) { + $property->setAccessible(TRUE); + } + $data[$data_key] = $property->getValue($service) ?? ''; } @@ -595,7 +608,10 @@ protected function addPluginTypeServiceDataAnnotated(&$data, $service, $discover protected function addPluginTypeServiceDataYaml(&$data, $service, $discovery) { $service_reflection = new \ReflectionClass($service); $property = $service_reflection->getProperty('defaults'); - $property->setAccessible(TRUE); + if (version_compare(PHP_VERSION, '8.1.0', '<')) { + $property->setAccessible(TRUE); + } + $defaults = $property->getValue($service); // YAML plugins don't specify their ID; it's generated automatically. @@ -608,12 +624,18 @@ protected function addPluginTypeServiceDataYaml(&$data, $service, $discovery) { // when recursively getting the decorated discovery. $discovery_reflection = new \ReflectionClass($discovery); $property = $discovery_reflection->getProperty('discovery'); - $property->setAccessible(TRUE); + if (version_compare(PHP_VERSION, '8.1.0', '<')) { + $property->setAccessible(TRUE); + } + $wrapped_discovery = $property->getValue($discovery); $wrapped_discovery_reflection = new \ReflectionClass($wrapped_discovery); $property = $wrapped_discovery_reflection->getProperty('name'); - $property->setAccessible(TRUE); + if (version_compare(PHP_VERSION, '8.1.0', '<')) { + $property->setAccessible(TRUE); + } + $name = $property->getValue($wrapped_discovery); $data['yaml_file_suffix'] = $name; @@ -1492,7 +1514,10 @@ protected function addPluginModuleData(&$plugin_type_data) { // Unfortunately, there's no accessor for this, so some reflection hackery // is required until https://www.drupal.org/node/2907862 is fixed. $reflection = new \ReflectionProperty(\Drupal\plugin\PluginType\PluginType::class, 'pluginManagerServiceId'); - $reflection->setAccessible(TRUE); + if (version_compare(PHP_VERSION, '8.1.0', '<')) { + $reflection->setAccessible(TRUE); + } + foreach ($plugin_types as $plugin_type) { // Get the service ID from the reflection, and then our ID. diff --git a/Test/Integration/Collection/CollectPluginInfoDummyModulesTest.php b/Test/Integration/Collection/CollectPluginInfoDummyModulesTest.php index 3d89e430..3bb61a4d 100644 --- a/Test/Integration/Collection/CollectPluginInfoDummyModulesTest.php +++ b/Test/Integration/Collection/CollectPluginInfoDummyModulesTest.php @@ -35,7 +35,10 @@ protected function setUp(): void { // of plugin manager service IDs. $class = new \ReflectionObject($this->pluginTypesCollector); $this->gatherPluginTypeInfoMethod = $class->getMethod('gatherPluginTypeInfo'); - $this->gatherPluginTypeInfoMethod->setAccessible(TRUE); + if (version_compare(PHP_VERSION, '8.1.0', '<')) { + $this->gatherPluginTypeInfoMethod->setAccessible(TRUE); + } + } protected function getPluginTypeInfoFromCollector($job) { diff --git a/Test/Integration/Collection/CollectPluginInfoTest.php b/Test/Integration/Collection/CollectPluginInfoTest.php index aada724a..c98ca755 100644 --- a/Test/Integration/Collection/CollectPluginInfoTest.php +++ b/Test/Integration/Collection/CollectPluginInfoTest.php @@ -31,7 +31,10 @@ protected function setUp(): void { // of plugin manager service IDs. $class = new \ReflectionObject($this->pluginTypesCollector); $this->gatherPluginTypeInfoMethod = $class->getMethod('gatherPluginTypeInfo'); - $this->gatherPluginTypeInfoMethod->setAccessible(TRUE); + if (version_compare(PHP_VERSION, '8.1.0', '<')) { + $this->gatherPluginTypeInfoMethod->setAccessible(TRUE); + } + } /** diff --git a/Test/Integration/Installation/InstallationTestBase.php b/Test/Integration/Installation/InstallationTestBase.php index e9d16a78..3e9d05cb 100644 --- a/Test/Integration/Installation/InstallationTestBase.php +++ b/Test/Integration/Installation/InstallationTestBase.php @@ -153,7 +153,10 @@ protected function installModule(string $module_name) { // ExtensionDiscovery keeps a cache of found files in a static property that // can only be cleared by hacking it with reflection. $reflection_property = new \ReflectionProperty(\Drupal\Core\Extension\ExtensionDiscovery::class, 'files'); - $reflection_property->setAccessible(TRUE); + if (version_compare(PHP_VERSION, '8.1.0', '<')) { + $reflection_property->setAccessible(TRUE); + } + $reflection_property->setValue(NULL, []); $result = $this->container->get('module_installer')->install([$module_name]); diff --git a/Test/Unit/ComponentPHPFile10Test.php b/Test/Unit/ComponentPHPFile10Test.php index 1667450a..677d0755 100644 --- a/Test/Unit/ComponentPHPFile10Test.php +++ b/Test/Unit/ComponentPHPFile10Test.php @@ -67,7 +67,10 @@ public static function setUpMockedComponent() { public function testQualifiedClassNameExtraction($code, $expected_changed_code, $expected_qualified_class_names) { // Make the protected method we're testing callable. $method = new \ReflectionMethod(PHPFile::class, 'extractFullyQualifiedClasses'); - $method->setAccessible(TRUE); + if (version_compare(PHP_VERSION, '8.1.0', '<')) { + $method->setAccessible(TRUE); + } + // Pass a component data item to PHPFile. Prophecy won't work as // PHPFile::extractFullyQualifiedClasses() accesses a property, so we create diff --git a/Test/Unit/ContainerCollectionTest.php b/Test/Unit/ContainerCollectionTest.php index 5ae4f418..62025d6a 100644 --- a/Test/Unit/ContainerCollectionTest.php +++ b/Test/Unit/ContainerCollectionTest.php @@ -18,7 +18,10 @@ class ContainerCollectionTest extends TestBase { public function testCollectorServices() { $collect = \DrupalCodeBuilder\Factory::getTask('Collect'); $reflection = new \ReflectionProperty($collect, 'collectors'); - $reflection->setAccessible(TRUE); + if (version_compare(PHP_VERSION, '8.1.0', '<')) { + $reflection->setAccessible(TRUE); + } + $collectors = $reflection->getValue($collect); $collector_classes = []; diff --git a/Test/Unit/ContainerTest.php b/Test/Unit/ContainerTest.php index be10e555..524059fd 100644 --- a/Test/Unit/ContainerTest.php +++ b/Test/Unit/ContainerTest.php @@ -34,7 +34,10 @@ public function testContainer7() { $collect_task = $container->get('Collect'); $collect_reflection = new \ReflectionObject($collect_task); $p = $collect_reflection->getProperty('collectors'); - $p->setAccessible(TRUE); + if (version_compare(PHP_VERSION, '8.1.0', '<')) { + $p->setAccessible(TRUE); + } + $collectors = $p->getValue($collect_task); $this->assertCount(1, $collectors); $this->assertArrayHasKey('Collect\HooksCollector', $p->getValue($collect_task)); @@ -61,7 +64,10 @@ public function testContainer8() { $collect_task = $container->get('Collect'); $collect_reflection = new \ReflectionObject($collect_task); $p = $collect_reflection->getProperty('collectors'); - $p->setAccessible(TRUE); + if (version_compare(PHP_VERSION, '8.1.0', '<')) { + $p->setAccessible(TRUE); + } + $collectors = $p->getValue($collect_task); $this->assertNotCount(1, $collectors); @@ -70,7 +76,10 @@ public function testContainer8() { $r = new \ReflectionObject($generate_module); $p = $r->getProperty('base'); - $p->setAccessible(TRUE); + if (version_compare(PHP_VERSION, '8.1.0', '<')) { + $p->setAccessible(TRUE); + } + $this->assertEquals('module', $p->getValue($generate_module)); $generate_profile = $container->get('Generate|profile'); @@ -78,7 +87,10 @@ public function testContainer8() { $r = new \ReflectionObject($generate_profile); $p = $r->getProperty('base'); - $p->setAccessible(TRUE); + if (version_compare(PHP_VERSION, '8.1.0', '<')) { + $p->setAccessible(TRUE); + } + $this->assertEquals('profile', $p->getValue($generate_profile)); } From f448e58ab56c4a24a1135ae35b7f82b393b4ed14 Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Fri, 27 Feb 2026 14:23:51 +0000 Subject: [PATCH 25/39] Fixed warning when Drupal's container namespaces contains array items. --- Task/Collect/CodeAnalyser.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Task/Collect/CodeAnalyser.php b/Task/Collect/CodeAnalyser.php index ea385042..49502898 100644 --- a/Task/Collect/CodeAnalyser.php +++ b/Task/Collect/CodeAnalyser.php @@ -113,20 +113,22 @@ protected function setupScript() { // This code is taken from DrupalKernel::attachSynthetic(). $container = $this->environment->getContainer(); $namespaces = $container->getParameter('container.namespaces'); + + // Build a list of data to pass to the script on STDIN. $psr4 = []; foreach ($namespaces as $prefix => $paths) { if (is_array($paths)) { foreach ($paths as $key => $value) { - $paths[$key] = $drupal_root . '/' . $value; + $path = $drupal_root . '/' . $value; + + $psr4[] = $prefix . '\\' . '::' . $path; } } elseif (is_string($paths)) { $paths = $drupal_root . '/' . $paths; - } - // Build a list of data to pass to the script on STDIN. - // $paths is never an array, AFAICT. - $psr4[] = $prefix . '\\' . '::' . $paths; + $psr4[] = $prefix . '\\' . '::' . $paths; + } } // Debug option for the script. From 4425a12c5bd62e5eb02511b704a629cb1fcb2f29 Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Wed, 11 Mar 2026 21:01:09 +0000 Subject: [PATCH 26/39] Added docs. --- Task/Collect/CollectorInterface.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Task/Collect/CollectorInterface.php b/Task/Collect/CollectorInterface.php index 0acced7e..8c85fccc 100644 --- a/Task/Collect/CollectorInterface.php +++ b/Task/Collect/CollectorInterface.php @@ -4,6 +4,9 @@ /** * Interface for collector task helpers. + * + * Task classes that implement this interface are automatically gathered and + * injected into the Collect task. */ interface CollectorInterface { From f3258546536f472fe18816df797b501b491c64c1 Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Wed, 11 Mar 2026 21:01:27 +0000 Subject: [PATCH 27/39] Added checking interface exists. --- Attribute/InjectImplementations.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Attribute/InjectImplementations.php b/Attribute/InjectImplementations.php index f9088a1e..69049b8f 100644 --- a/Attribute/InjectImplementations.php +++ b/Attribute/InjectImplementations.php @@ -27,7 +27,11 @@ #[Attribute(Attribute::TARGET_METHOD)] final class InjectImplementations { - public function __construct(private string $interface) {} + public function __construct(private string $interface) { + if (!interface_exists($interface)) { + throw new \InvalidArgumentException("The interface '{$interface}' used in an InjectImplementations attribute does not exist."); + } + } /** * Gets the name of the interface the marked method collects. From 2e9af4221813fdbbc9cd1cca67930fa0de4c77ab Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Mon, 16 Mar 2026 10:06:18 +0000 Subject: [PATCH 28/39] Fixed Drush command option description using wrong variable. --- Generator/DrushCommand.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Generator/DrushCommand.php b/Generator/DrushCommand.php index c15a0a75..11678554 100644 --- a/Generator/DrushCommand.php +++ b/Generator/DrushCommand.php @@ -291,7 +291,7 @@ protected function getFunctionAttributes(): array { [$option_name, ] = explode(':', $option); $attributes[] = PhpAttributes::method('\Drush\Attributes\Option', [ 'name' => $option_name, - 'description' => "TODO: description of {$parameter} option.", + 'description' => "TODO: description of {$option_name} option.", ]); } From 671f1cf6c77fa8960d75fdf5cb5b57dfd582942b Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Mon, 16 Mar 2026 13:13:33 +0000 Subject: [PATCH 29/39] Fixed failing tests. --- .../Unit/ComponentContentEntityType10Test.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Test/Unit/ComponentContentEntityType10Test.php b/Test/Unit/ComponentContentEntityType10Test.php index 5f2b6ea5..6c0d3932 100644 --- a/Test/Unit/ComponentContentEntityType10Test.php +++ b/Test/Unit/ComponentContentEntityType10Test.php @@ -1436,9 +1436,18 @@ public function testContentEntityTypeWithUI() { 'label_plural', 'label_count', 'base_table', + // The next 4 lines are here only as a workaround for an MTD bug: see + // https://github.com/joachim-n/mutable-typed-data/issues/22. + 'data_table', + 'revision_table', + 'revision_data_table', + 'translatable', 'handlers', 'admin_permission', 'entity_keys', + // Next 2 lines same as above. + 'revision_metadata_keys', + 'field_ui_base_route', 'links', ]); $annotation_tester->assertPropertyHasValue(['handlers', 'form', 'default'], 'Drupal\test_module\Form\KittyCatForm'); @@ -1692,10 +1701,20 @@ public function testEntityTypeWithUIAndBundleEntity() { 'label_count', 'bundle_label', 'base_table', + // The next 4 lines are here only as a workaround for an MTD bug: see + // https://github.com/joachim-n/mutable-typed-data/issues/22. + 'data_table', + 'revision_table', + 'revision_data_table', + 'translatable', 'handlers', 'admin_permission', 'entity_keys', + // Next line same as above. + 'revision_metadata_keys', 'bundle_entity_type', + // Next line same as above. + 'field_ui_base_route', 'links', ]); $annotation_tester->assertPropertyHasValue('bundle_label', "Kitty Cat Type"); From d166c53390782b74468008d3aeb0e02a896e75a6 Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Mon, 16 Mar 2026 13:16:47 +0000 Subject: [PATCH 30/39] Fixed surplus 'none' option appearing in UIs for entity handlers. --- Generator/EntityTypeBase.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Generator/EntityTypeBase.php b/Generator/EntityTypeBase.php index 52c0ac3c..496f5dbb 100644 --- a/Generator/EntityTypeBase.php +++ b/Generator/EntityTypeBase.php @@ -138,28 +138,34 @@ public static function addToGeneratorDefinition(PropertyListInterface $definitio // builder handler. $handler_property = PropertyDefinition::create('string') ->setLabel(ucfirst("{$handler_type_info['label']} handler")) + ->setRequired(TRUE) ->setOptionsArray([ + // We use an explicit empty option and make this required, so we + // can control the label used for this in the UI. 'none' => 'Do not use a handler', 'core' => 'Use the core handler class', 'custom' => 'Provide a custom handler class', - ]); + ]) + ->setLiteralDefault('none'); break; case 'custom_default': $default_handler_type = $handler_type_info['default_type']; $handler_property = PropertyDefinition::create('string') ->setLabel(ucfirst("{$handler_type_info['label']} handler")) + ->setRequired(TRUE) ->setOptionsArray([ 'none' => 'Do not use a handler', 'default' => "Use the '{$default_handler_type}' handler class (forces '{$default_handler_type}' to use the default if not set)", 'custom' => "Provide a custom handler class (forces '{$default_handler_type}' to use the default if not set)", ]) + ->setLiteralDefault('none') // Force the default type to at least be specified if it isn't // already. // TODO: this assumes the mode of the default handler type is // 'core_none'. ->setProcessing(function(DataItem $component_data) use ($default_handler_type) { - if ($component_data->isEmpty() || $component_data->value == 'none') { + if ($component_data->value == 'none') { // Nothing to do; this isn't set to use anything. return; } From 0af1b93e724516bf272bf684cd791bf50f8dbbde Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Mon, 16 Mar 2026 13:30:08 +0000 Subject: [PATCH 31/39] Fixed ordering of admin route handler option; converted entity handler options to use OptionDefinition objects. --- Generator/EntityTypeBase.php | 37 ++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/Generator/EntityTypeBase.php b/Generator/EntityTypeBase.php index 496f5dbb..50b032a6 100644 --- a/Generator/EntityTypeBase.php +++ b/Generator/EntityTypeBase.php @@ -139,13 +139,15 @@ public static function addToGeneratorDefinition(PropertyListInterface $definitio $handler_property = PropertyDefinition::create('string') ->setLabel(ucfirst("{$handler_type_info['label']} handler")) ->setRequired(TRUE) - ->setOptionsArray([ + ->setOptions( // We use an explicit empty option and make this required, so we // can control the label used for this in the UI. - 'none' => 'Do not use a handler', - 'core' => 'Use the core handler class', - 'custom' => 'Provide a custom handler class', - ]) + // Set weights and leave gaps so that static::getHandlerTypes() + // can insert options in between. + new OptionDefinition('none', 'Do not use a handler', weight: 0), + new OptionDefinition('core', 'Use the core handler class.', weight: 10), + new OptionDefinition('custom', 'Provide a custom handler class.', weight: 20), + ) ->setLiteralDefault('none'); break; @@ -154,11 +156,13 @@ public static function addToGeneratorDefinition(PropertyListInterface $definitio $handler_property = PropertyDefinition::create('string') ->setLabel(ucfirst("{$handler_type_info['label']} handler")) ->setRequired(TRUE) - ->setOptionsArray([ - 'none' => 'Do not use a handler', - 'default' => "Use the '{$default_handler_type}' handler class (forces '{$default_handler_type}' to use the default if not set)", - 'custom' => "Provide a custom handler class (forces '{$default_handler_type}' to use the default if not set)", - ]) + ->setOptions( + // We use an explicit empty option and make this required, so we + // can control the label used for this in the UI. + new OptionDefinition('none', 'Do not use a handler', weight: 0), + new OptionDefinition('default', "Use the '{$default_handler_type}' handler class (forces '{$default_handler_type}' to use the default if not set)", weight: 10), + new OptionDefinition('custom', "Provide a custom handler class (forces '{$default_handler_type}' to use the default if not set)", weight: 20), + ) ->setLiteralDefault('none') // Force the default type to at least be specified if it isn't // already. @@ -186,8 +190,8 @@ public static function addToGeneratorDefinition(PropertyListInterface $definitio // Add extra options specific to the handler type. if (isset($handler_type_info['options'])) { - foreach ($handler_type_info['options'] as $option_value => $option_label) { - $handler_property->addOption(new OptionDefinition($option_value, $option_label)); + foreach ($handler_type_info['options'] as $option) { + $handler_property->addOption($option); } } @@ -287,8 +291,9 @@ public static function addToGeneratorDefinition(PropertyListInterface $definitio * - 'custom_default': No handler is provided, but handler for another * type can be used. The option is whether to use that, or create a * custom handler. The 'default_type' property must also be given. - * - 'options': An array of additional options for the handler property. - * These are added to the options provided by the mode. + * - 'options': A array of additional OptionDefinition objects for the + * handler property. These are added to the options provided by the mode. + * Array keys are ignored. * - 'property_path': (optional) The path to set this into the annotation * beneath the 'handlers' key. Only required if this is not simply the * handler type key. @@ -315,8 +320,8 @@ protected static function getHandlerTypes() { 'options' => [ // Overwrite the label for the 'core' option which the mode provides. // This is OK because addOption() replaces an existing option. - 'core' => 'Default core route provider', - 'admin' => 'Admin route provider', + new OptionDefinition('core', 'Default core route provider', weight: 10), + new OptionDefinition('admin', 'Admin route provider', weight: 15), ], 'options_classes' => [ 'default' => '\Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider', From 3b5bd261cdb6896e2c5cc65d9da7eba202029801 Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Mon, 16 Mar 2026 13:30:15 +0000 Subject: [PATCH 32/39] Fixed typo. --- Generator/ConfigEntityType.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Generator/ConfigEntityType.php b/Generator/ConfigEntityType.php index 59c00789..66274106 100644 --- a/Generator/ConfigEntityType.php +++ b/Generator/ConfigEntityType.php @@ -112,7 +112,7 @@ protected static function getHandlerTypes() { $handler_types[$form_handler_type]['base_class'] = '\Drupal\Core\Entity\EntityForm'; $handler_types[$form_handler_type]['handler_properties'] = [ - // Config entity formss redirect to the collection page. + // Config entity forms redirect to the collection page. 'redirect_link_template' => 'collection', ]; } From 77df4c763aee6c644bcb62bc27e92d2546c761db Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Mon, 16 Mar 2026 13:36:56 +0000 Subject: [PATCH 33/39] Changed option label to be clearer. --- Generator/EntityTypeBase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Generator/EntityTypeBase.php b/Generator/EntityTypeBase.php index 50b032a6..829b8b00 100644 --- a/Generator/EntityTypeBase.php +++ b/Generator/EntityTypeBase.php @@ -321,7 +321,7 @@ protected static function getHandlerTypes() { // Overwrite the label for the 'core' option which the mode provides. // This is OK because addOption() replaces an existing option. new OptionDefinition('core', 'Default core route provider', weight: 10), - new OptionDefinition('admin', 'Admin route provider', weight: 15), + new OptionDefinition('admin', 'Core admin route provider', weight: 15), ], 'options_classes' => [ 'default' => '\Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider', From f173204d8044f7eba4747d89da69685e5fddbc85 Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Mon, 16 Mar 2026 13:37:25 +0000 Subject: [PATCH 34/39] Changed UI text about forcing handler classes to be on the option set description rather than repeated on each option. --- Generator/EntityTypeBase.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Generator/EntityTypeBase.php b/Generator/EntityTypeBase.php index 829b8b00..d272792f 100644 --- a/Generator/EntityTypeBase.php +++ b/Generator/EntityTypeBase.php @@ -155,13 +155,14 @@ public static function addToGeneratorDefinition(PropertyListInterface $definitio $default_handler_type = $handler_type_info['default_type']; $handler_property = PropertyDefinition::create('string') ->setLabel(ucfirst("{$handler_type_info['label']} handler")) + ->setDescription("Setting a handler class here will force the '{$default_handler_type}' handler to be set to use the default handler class, if it is not set.'") ->setRequired(TRUE) ->setOptions( // We use an explicit empty option and make this required, so we // can control the label used for this in the UI. new OptionDefinition('none', 'Do not use a handler', weight: 0), - new OptionDefinition('default', "Use the '{$default_handler_type}' handler class (forces '{$default_handler_type}' to use the default if not set)", weight: 10), - new OptionDefinition('custom', "Provide a custom handler class (forces '{$default_handler_type}' to use the default if not set)", weight: 20), + new OptionDefinition('default', "Use the '{$default_handler_type}' handler class", weight: 10), + new OptionDefinition('custom', "Provide a custom handler class", weight: 20), ) ->setLiteralDefault('none') // Force the default type to at least be specified if it isn't @@ -340,7 +341,7 @@ protected static function getHandlerTypes() { ], 'form_add' => [ 'label' => 'add form', - 'description' => "The entity form class for the 'add' operation.", + 'description' => "The entity form class for the 'add' operation. Setting a handler class here will force the 'default form' handler to be set to use the default handler class, if it is not set.", 'component_type' => 'EntityForm', 'property_path' => ['form', 'add'], 'class_name_suffix' => 'AddForm', @@ -350,7 +351,7 @@ protected static function getHandlerTypes() { ], 'form_edit' => [ 'label' => 'edit form', - 'description' => "The entity form class for the 'edit' operation.", + 'description' => "The entity form class for the 'edit' operation. Setting a handler class here will force the 'default form' handler to be set to use the default handler class, if it is not set.", 'component_type' => 'EntityForm', 'property_path' => ['form', 'edit'], 'class_name_suffix' => 'EditForm', From 6de57050adebf597537dfb355ab61ffdc4af9d73 Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Mon, 16 Mar 2026 13:47:35 +0000 Subject: [PATCH 35/39] Changed order of plugin types so deprecated annotation type is last. --- Generator/PluginType.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Generator/PluginType.php b/Generator/PluginType.php index a414ec79..c8fb1cf3 100644 --- a/Generator/PluginType.php +++ b/Generator/PluginType.php @@ -32,11 +32,6 @@ public static function addToGeneratorDefinition(PropertyListInterface $definitio ->setLabel('Plugin discovery type') ->setDescription("The way in which plugins of this type are formed.") ->setOptions( - OptionDefinition::create( - 'annotation', - 'Annotation plugin', - "Each plugin is a class with an annotation to declare the plugin data. WARNING: This plugin discovery type will soon be deprecated in Drupal core." - ), OptionDefinition::create( 'attribute', 'Attribute plugin', @@ -46,7 +41,12 @@ public static function addToGeneratorDefinition(PropertyListInterface $definitio 'yaml', 'YAML plugin', "Plugins are declared in a single YAML file, and usually share the same class." - ) + ), + OptionDefinition::create( + 'annotation', + 'Annotation plugin', + "Each plugin is a class with an annotation to declare the plugin data. WARNING: This plugin discovery type will soon be deprecated in Drupal core." + ), ) ]) ->setVariants([ From d90803da384d43ead34986995c2b8b9d78cd1dac Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Mon, 16 Mar 2026 15:05:48 +0000 Subject: [PATCH 36/39] Fixed typo. --- Generator/PHPUnitTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Generator/PHPUnitTest.php b/Generator/PHPUnitTest.php index 67d87b94..f8b0cf51 100644 --- a/Generator/PHPUnitTest.php +++ b/Generator/PHPUnitTest.php @@ -99,7 +99,7 @@ public static function addToGeneratorDefinition(PropertyListInterface $definitio ], ], 'javascript' => [ - 'label' => 'Javascript test', + 'label' => 'JavaScript test', 'data' => [ 'force' => [ 'relative_namespace' => [ From f2ba73618334f172cfdbcd9eee9aadd84d112ecb Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Wed, 18 Mar 2026 11:37:25 +0000 Subject: [PATCH 37/39] Fixed test dataset labels the wrong way round. --- Test/Unit/ComponentRouterItem10Test.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Test/Unit/ComponentRouterItem10Test.php b/Test/Unit/ComponentRouterItem10Test.php index bfa8afba..59543515 100644 --- a/Test/Unit/ComponentRouterItem10Test.php +++ b/Test/Unit/ComponentRouterItem10Test.php @@ -345,12 +345,9 @@ public static function dataRouteAccessTypes() { ], '_custom_access', '\Drupal\test_module\Controller\MyPathControllerController::access', - [ - 'controller_type' => 'controller', - ], + [], [ 'Controller\MyPathControllerController' => [ - 'content', 'access', ], ], @@ -365,9 +362,12 @@ public static function dataRouteAccessTypes() { ], '_custom_access', '\Drupal\test_module\Controller\MyPathControllerController::access', - [], + [ + 'controller_type' => 'controller', + ], [ 'Controller\MyPathControllerController' => [ + 'content', 'access', ], ], From 47cc4e177391c647cff856f575d77c044f9b8f0d Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Wed, 18 Mar 2026 11:37:38 +0000 Subject: [PATCH 38/39] Added future parameter from MTD. --- MutableTypedData/Data/MappingData.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MutableTypedData/Data/MappingData.php b/MutableTypedData/Data/MappingData.php index 8b787036..2d044247 100644 --- a/MutableTypedData/Data/MappingData.php +++ b/MutableTypedData/Data/MappingData.php @@ -34,7 +34,7 @@ public function items(): array { /** * {@inheritdoc} */ - public function validate(): array { + public function validate(?bool $include_internal = FALSE): array { return []; } From d78c29ecbe3d4e8cd11466c0bc0cd03e23ac02fc Mon Sep 17 00:00:00 2001 From: Joachim Noreiko Date: Sun, 5 Apr 2026 17:43:49 +0100 Subject: [PATCH 39/39] Converted PHPUnit annotations to attributes. --- Test/Unit/ComponentAPI10Test.php | 4 +- Test/Unit/ComponentAdminSettings10Test.php | 6 +-- Test/Unit/ComponentConfigEntityType10Test.php | 11 +++-- .../Unit/ComponentContentEntityType10Test.php | 38 +++++++--------- Test/Unit/ComponentContentEntityType9Test.php | 13 +++--- Test/Unit/ComponentCssLibrary10Test.php | 4 +- Test/Unit/ComponentDrushCommand11Test.php | 7 ++- Test/Unit/ComponentDrushCommand8Test.php | 7 ++- .../ComponentDynamicRouteProvider11Test.php | 4 +- Test/Unit/ComponentForm10Test.php | 13 +++--- Test/Unit/ComponentHooks11Test.php | 4 +- Test/Unit/ComponentHooks7Test.php | 4 +- Test/Unit/ComponentHooks8Test.php | 10 ++--- Test/Unit/ComponentInfo10Test.php | 6 +-- Test/Unit/ComponentInfo9Test.php | 12 +++--- Test/Unit/ComponentModule10Test.php | 7 ++- Test/Unit/ComponentModule7Test.php | 4 +- Test/Unit/ComponentPHPFile10Test.php | 4 +- Test/Unit/ComponentPermissions10Test.php | 4 +- Test/Unit/ComponentPermissions7Test.php | 4 +- Test/Unit/ComponentPluginType10Test.php | 9 ++-- Test/Unit/ComponentPluginsAnnotated9Test.php | 19 ++++---- Test/Unit/ComponentPluginsAttribute11Test.php | 19 ++++---- Test/Unit/ComponentPluginsYAML10Test.php | 9 ++-- Test/Unit/ComponentProfile10Test.php | 4 +- Test/Unit/ComponentReadme10Test.php | 4 +- Test/Unit/ComponentRouterItem10Test.php | 20 ++++----- Test/Unit/ComponentRouterItem7Test.php | 4 +- Test/Unit/ComponentService11Test.php | 43 ++++++++----------- .../ComponentServiceEventSubscriber10Test.php | 4 +- Test/Unit/ComponentTestsPHPUnit10Test.php | 29 ++++++------- Test/Unit/ComponentTestsPHPUnit9Test.php | 30 ++++++------- Test/Unit/ComponentThemeHook10Test.php | 3 +- Test/Unit/ComponentThemeHook11Test.php | 3 +- Test/Unit/ContainerCollectionTest.php | 4 +- Test/Unit/ContainerRebuildTest.php | 3 +- Test/Unit/ContainerTest.php | 3 +- Test/Unit/DrupalCodeBuilderAssertionsTest.php | 13 +++--- .../GenerateHelperComponentCollectorTest.php | 11 +++-- Test/Unit/ParserDocBlockTest.php | 4 +- Test/Unit/ParserPHPTest.php | 14 +++--- Test/Unit/ParserYamlTest.php | 7 ++- Test/Unit/UnitDataItemMergeTest.php | 13 +++--- .../UnitDependencyInjectionAnalysisTest.php | 4 +- Test/Unit/UnitMethodCollectorTest.php | 4 +- Test/Unit/UnitValidatorTest.php | 13 +++--- 46 files changed, 202 insertions(+), 257 deletions(-) diff --git a/Test/Unit/ComponentAPI10Test.php b/Test/Unit/ComponentAPI10Test.php index 1edd6eb8..0e2a2880 100644 --- a/Test/Unit/ComponentAPI10Test.php +++ b/Test/Unit/ComponentAPI10Test.php @@ -2,6 +2,7 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\Group; use DrupalCodeBuilder\Task\AnalyzeModule; use DrupalCodeBuilder\Test\Fixtures\File\MockableExtension; use DrupalCodeBuilder\Test\Unit\Parsing\PHPTester; @@ -62,9 +63,8 @@ public function testModuleGenerationApiFile() { /** * Tests with an existing api file. - * - * @group existing */ + #[Group('existing')] public function testExistingAPIFile() { // Assemble module data. $module_name = 'test_module'; diff --git a/Test/Unit/ComponentAdminSettings10Test.php b/Test/Unit/ComponentAdminSettings10Test.php index cd362c9a..69e2b0b8 100644 --- a/Test/Unit/ComponentAdminSettings10Test.php +++ b/Test/Unit/ComponentAdminSettings10Test.php @@ -2,15 +2,15 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\Group; use DrupalCodeBuilder\Test\Unit\Parsing\PHPTester; use DrupalCodeBuilder\Test\Unit\Parsing\YamlTester; /** * Tests the AdminSettingsForm generator class. - * - * @group form - * @group yaml */ +#[Group('form')] +#[Group('yaml')] class ComponentAdminSettings10Test extends TestBase { /** diff --git a/Test/Unit/ComponentConfigEntityType10Test.php b/Test/Unit/ComponentConfigEntityType10Test.php index d945785d..f61edd01 100644 --- a/Test/Unit/ComponentConfigEntityType10Test.php +++ b/Test/Unit/ComponentConfigEntityType10Test.php @@ -2,15 +2,15 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\Group; use DrupalCodeBuilder\Test\Unit\Parsing\PHPTester; use DrupalCodeBuilder\Test\Unit\Parsing\YamlTester; /** * Tests the config entity type generator class. - * - * @group yaml - * @group entity */ +#[Group('yaml')] +#[Group('entity')] class ComponentConfigEntityType10Test extends TestBase { /** @@ -340,10 +340,9 @@ public function testConfigEntityTypeWithHandlers() { /** * Test creating a config entity type with a UI. - * - * @group entity_ui - * @group form */ + #[Group('entity_ui')] + #[Group('form')] public function testConfigEntityTypeWithUI() { // Create a module. $module_name = 'test_module'; diff --git a/Test/Unit/ComponentContentEntityType10Test.php b/Test/Unit/ComponentContentEntityType10Test.php index 6c0d3932..ddc9cd2d 100644 --- a/Test/Unit/ComponentContentEntityType10Test.php +++ b/Test/Unit/ComponentContentEntityType10Test.php @@ -2,16 +2,17 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Group; use DrupalCodeBuilder\Test\Unit\Parsing\YamlTester; use DrupalCodeBuilder\Test\Unit\Parsing\PHPTester; /** * Tests the entity type generator class. - * - * @group yaml - * @group annotation - * @group entity */ +#[Group('yaml')] +#[Group('annotation')] +#[Group('entity')] class ComponentContentEntityType10Test extends TestBase { /** @@ -173,9 +174,8 @@ public function testBasicContentEntityType() { * Tests the parent interfaces. * * This covers the different combinations of options. - * - * @dataProvider providerContentEntityTypeFunctionalityOptions */ + #[DataProvider('providerContentEntityTypeFunctionalityOptions')] public function testContentEntityTypeFunctionalityOptions( $interface_option, $expected_parent_interfaces, @@ -780,9 +780,8 @@ public function testEntityTypeWithBundleEntityNoUI() { * Tests creating a content entity type with handlers. * * This covers the different combinations of options. - * - * @dataProvider providerHandlers */ + #[DataProvider('providerHandlers')] public function testContentEntityTypeHandlers($handler_properties, $expected_handlers_annotation, $expected_files_base_classes) { // Create a module. $module_name = 'test_module'; @@ -1321,9 +1320,8 @@ public function testContentEntityTypeCustomHandlers() { /** * Tests the handler namespace configuration setting. - * - * @group config */ + #[Group('config')] public function testContentEntityTypeHandlerNamespaceConfiguration() { // Create a module. $module_name = 'test_module'; @@ -1396,10 +1394,9 @@ public function testContentEntityTypeHandlerNamespaceConfiguration() { /** * Tests creating a content entity with a UI. - * - * @group entity_ui - * @group form */ + #[Group('entity_ui')] + #[Group('form')] public function testContentEntityTypeWithUI() { $module_name = 'test_module'; $module_data = [ @@ -1515,10 +1512,9 @@ public function testContentEntityTypeWithUI() { /** * Tests creating a content entity with a revision UI. - * - * @group entity_ui - * @group form */ + #[Group('entity_ui')] + #[Group('form')] public function testContentEntityTypeWithRevisionEntityUI() { $module_name = 'test_module'; $module_data = [ @@ -1556,10 +1552,9 @@ public function testContentEntityTypeWithRevisionEntityUI() { /** * Tests creating a content entity with a bundle entity UI. - * - * @group entity_ui - * @group form */ + #[Group('entity_ui')] + #[Group('form')] public function testContentEntityTypeWithBundleEntityUI() { $module_name = 'test_module'; $module_data = [ @@ -1631,10 +1626,9 @@ public function testContentEntityTypeWithBundleEntityUI() { /** * Test creating a content entity type with a bundle entity and UI for both. - * - * @group entity_ui - * @group form */ + #[Group('entity_ui')] + #[Group('form')] public function testEntityTypeWithUIAndBundleEntity() { // Create a module. $module_name = 'test_module'; diff --git a/Test/Unit/ComponentContentEntityType9Test.php b/Test/Unit/ComponentContentEntityType9Test.php index b9017571..6e634044 100644 --- a/Test/Unit/ComponentContentEntityType9Test.php +++ b/Test/Unit/ComponentContentEntityType9Test.php @@ -2,16 +2,16 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\Group; use DrupalCodeBuilder\Test\Unit\Parsing\YamlTester; use DrupalCodeBuilder\Test\Unit\Parsing\PHPTester; /** * Tests the D8/9 entity type generator class. - * - * @group yaml - * @group annotation - * @group entity */ +#[Group('yaml')] +#[Group('annotation')] +#[Group('entity')] class ComponentContentEntityType9Test extends TestBase { /** @@ -23,10 +23,9 @@ class ComponentContentEntityType9Test extends TestBase { /** * Tests creating a content entity with a revision UI. - * - * @group entity_ui - * @group form */ + #[Group('entity_ui')] + #[Group('form')] public function testContentEntityTypeWithRevisionEntityUI() { $module_name = 'test_module'; $module_data = [ diff --git a/Test/Unit/ComponentCssLibrary10Test.php b/Test/Unit/ComponentCssLibrary10Test.php index fdcb1d33..8c8a8ecd 100644 --- a/Test/Unit/ComponentCssLibrary10Test.php +++ b/Test/Unit/ComponentCssLibrary10Test.php @@ -2,13 +2,13 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\Group; use DrupalCodeBuilder\Test\Unit\Parsing\YamlTester; /** * Tests for library generation. - * - * @group yaml */ +#[Group('yaml')] class ComponentCssLibrary10Test extends TestBase { /** diff --git a/Test/Unit/ComponentDrushCommand11Test.php b/Test/Unit/ComponentDrushCommand11Test.php index 2f8ec428..31d50473 100644 --- a/Test/Unit/ComponentDrushCommand11Test.php +++ b/Test/Unit/ComponentDrushCommand11Test.php @@ -2,13 +2,13 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\Group; use DrupalCodeBuilder\Test\Unit\Parsing\PHPTester; /** * Tests for Drush command component. - * - * @group yaml */ +#[Group('yaml')] class ComponentDrushCommand11Test extends TestBase { /** @@ -152,9 +152,8 @@ function testCommandGenerationWithParameters() { /** * Test a command with with injected services. - * - * @group di */ + #[Group('di')] function testCommandGenerationWithServices() { // Assemble module data. $module_name = 'test_module'; diff --git a/Test/Unit/ComponentDrushCommand8Test.php b/Test/Unit/ComponentDrushCommand8Test.php index 873312fa..dc941115 100644 --- a/Test/Unit/ComponentDrushCommand8Test.php +++ b/Test/Unit/ComponentDrushCommand8Test.php @@ -2,14 +2,14 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\Group; use DrupalCodeBuilder\Test\Unit\Parsing\PHPTester; use DrupalCodeBuilder\Test\Unit\Parsing\YamlTester; /** * Tests for Drush command component. - * - * @group yaml */ +#[Group('yaml')] class ComponentDrushCommand8Test extends TestBase { /** @@ -173,9 +173,8 @@ function testCommandGenerationWithParameters() { /** * Test a command with with injected services. - * - * @group di */ + #[Group('di')] function testCommandGenerationWithServices() { // Assemble module data. $module_name = 'test_module'; diff --git a/Test/Unit/ComponentDynamicRouteProvider11Test.php b/Test/Unit/ComponentDynamicRouteProvider11Test.php index 4cfb970e..a01edf05 100644 --- a/Test/Unit/ComponentDynamicRouteProvider11Test.php +++ b/Test/Unit/ComponentDynamicRouteProvider11Test.php @@ -2,14 +2,14 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\Group; use DrupalCodeBuilder\Test\Unit\Parsing\PHPTester; use DrupalCodeBuilder\Test\Unit\Parsing\YamlTester; /** * Tests for dynamic route providers. - * - * @group yaml */ +#[Group('yaml')] class ComponentDynamicRouteProvider11Test extends TestBase { /** diff --git a/Test/Unit/ComponentForm10Test.php b/Test/Unit/ComponentForm10Test.php index f8d8c0b5..8125e507 100644 --- a/Test/Unit/ComponentForm10Test.php +++ b/Test/Unit/ComponentForm10Test.php @@ -2,14 +2,15 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Group; use DrupalCodeBuilder\Test\Unit\Parsing\PHPTester; use DrupalCodeBuilder\Test\Unit\Parsing\YamlTester; /** * Tests for Form component. - * - * @group form */ +#[Group('form')] class ComponentForm10Test extends TestBase { /** @@ -129,9 +130,8 @@ public function testFormGenerationWithCustomElements() { /** * Test Form component with injected services. - * - * @group di */ + #[Group('di')] function testFormGenerationWithServices() { // Assemble module data. $module_name = 'test_module'; @@ -255,10 +255,9 @@ public static function dataAdoptionMerge() { * Whether a generated component exists to have the adopted component merged * with. * - * @group adopt - * - * @dataProvider dataAdoptionMerge */ + #[Group('adopt')] + #[DataProvider('dataAdoptionMerge')] public function testExistingFormAdoption(bool $merge) { // First pass: generate the files we'll mock as existing. $module_name = 'existing'; diff --git a/Test/Unit/ComponentHooks11Test.php b/Test/Unit/ComponentHooks11Test.php index 83e87436..3076cb21 100644 --- a/Test/Unit/ComponentHooks11Test.php +++ b/Test/Unit/ComponentHooks11Test.php @@ -2,14 +2,14 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\Group; use DrupalCodeBuilder\Test\Unit\Parsing\PHPTester; use DrupalCodeBuilder\Test\Unit\Parsing\YamlTester; /** * Tests for Hooks component on Drupal 11. - * - * @group hooks */ +#[Group('hooks')] class ComponentHooks11Test extends TestBase { /** diff --git a/Test/Unit/ComponentHooks7Test.php b/Test/Unit/ComponentHooks7Test.php index 024c2565..1ac3d596 100644 --- a/Test/Unit/ComponentHooks7Test.php +++ b/Test/Unit/ComponentHooks7Test.php @@ -2,13 +2,13 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\Group; use DrupalCodeBuilder\Test\Unit\Parsing\PHPTester; /** * Tests for Hooks component. - * - * @group hooks */ +#[Group('hooks')] class ComponentHooks7Test extends TestBase { /** diff --git a/Test/Unit/ComponentHooks8Test.php b/Test/Unit/ComponentHooks8Test.php index 10ce5b5d..7f3adfca 100644 --- a/Test/Unit/ComponentHooks8Test.php +++ b/Test/Unit/ComponentHooks8Test.php @@ -2,15 +2,15 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\Group; use DrupalCodeBuilder\Test\Fixtures\File\MockableExtension; use DrupalCodeBuilder\Test\Unit\Parsing\PHPTester; use DrupalCodeBuilder\Test\Unit\Parsing\YamlTester; /** * Tests for Hooks component. - * - * @group hooks */ +#[Group('hooks')] class ComponentHooks8Test extends TestBase { /** @@ -173,9 +173,8 @@ public function testModuleGenerationHooks() { /** * Tests with an existing code file. - * - * @group existing */ + #[Group('existing')] public function testHooksWithExistingFunctions() { // Assemble module data. $module_name = 'test_module'; @@ -255,9 +254,8 @@ function test_module_element_info_alter(array &$info) { /** * Tests hook_update_N() existing implementations. - * - * @group existing */ + #[Group('existing')] public function testHooksWithExistingHookInstall() { // Assemble module data. $module_name = 'test_module'; diff --git a/Test/Unit/ComponentInfo10Test.php b/Test/Unit/ComponentInfo10Test.php index 26cff7e3..6c039954 100644 --- a/Test/Unit/ComponentInfo10Test.php +++ b/Test/Unit/ComponentInfo10Test.php @@ -2,14 +2,14 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\Group; use DrupalCodeBuilder\Test\Unit\Parsing\YamlTester; /** * Tests for Info component. - * - * @group yaml - * @group info */ +#[Group('yaml')] +#[Group('info')] class ComponentInfo10Test extends TestBase { /** diff --git a/Test/Unit/ComponentInfo9Test.php b/Test/Unit/ComponentInfo9Test.php index d47d6d41..41e80d51 100644 --- a/Test/Unit/ComponentInfo9Test.php +++ b/Test/Unit/ComponentInfo9Test.php @@ -2,16 +2,17 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Group; use DrupalCodeBuilder\Test\Fixtures\File\MockableExtension; use DrupalCodeBuilder\Test\Unit\Parsing\YamlTester; use Symfony\Component\Yaml\Yaml; /** * Tests for Info component. - * - * @group yaml - * @group info */ +#[Group('yaml')] +#[Group('info')] class ComponentInfo9Test extends TestBase { /** @@ -121,10 +122,9 @@ public static function dataExistingInfoFile() { /** * Tests with an existing info file. * - * @group existing - * - * @dataProvider dataExistingInfoFile */ + #[Group('existing')] + #[DataProvider('dataExistingInfoFile')] public function testExistingInfoFile($existing_dependencies, $generated_dependencies, $resulting_dependencies) { $module_name = 'test_module'; $module_data = [ diff --git a/Test/Unit/ComponentModule10Test.php b/Test/Unit/ComponentModule10Test.php index 92ac3077..77943069 100644 --- a/Test/Unit/ComponentModule10Test.php +++ b/Test/Unit/ComponentModule10Test.php @@ -2,14 +2,14 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\Group; use DrupalCodeBuilder\Test\Unit\Parsing\PHPTester; use MutableTypedData\Data\DataItem; /** * Tests basic module generation. - * - * @group hooks */ +#[Group('hooks')] class ComponentModule10Test extends TestBase { /** @@ -69,9 +69,8 @@ protected function simulateUiWalk(DataItem $data_item) { /** * Tests getting module configuration data. - * - * @group config */ + #[Group('config')] public function testConfiguration() { $config_data = \DrupalCodeBuilder\Factory::getTask('Configuration')->getConfigurationData('module'); $properties = $config_data->getProperties(); diff --git a/Test/Unit/ComponentModule7Test.php b/Test/Unit/ComponentModule7Test.php index a7a1cf1b..db52c5b0 100644 --- a/Test/Unit/ComponentModule7Test.php +++ b/Test/Unit/ComponentModule7Test.php @@ -2,13 +2,13 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\Group; use DrupalCodeBuilder\Test\Unit\Parsing\PHPTester; /** * Tests basic module generation. - * - * @group hooks */ +#[Group('hooks')] class ComponentModule7Test extends TestBase { /** diff --git a/Test/Unit/ComponentPHPFile10Test.php b/Test/Unit/ComponentPHPFile10Test.php index 677d0755..960e34ac 100644 --- a/Test/Unit/ComponentPHPFile10Test.php +++ b/Test/Unit/ComponentPHPFile10Test.php @@ -2,6 +2,7 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\DataProvider; use DrupalCodeBuilder\File\CodeFile; use DrupalCodeBuilder\Generator\PHPFile as RealPHPFile; use DrupalCodeBuilder\Test\Unit\Parsing\PHPTester; @@ -49,8 +50,6 @@ public static function setUpMockedComponent() { /** * Test the qualified class name extraction. * - * @dataProvider providerQualifiedClassNameExtraction - * * @param string $code * The code to extract class names from. * @param string $expected_changed_code @@ -64,6 +63,7 @@ public static function setUpMockedComponent() { * extracted. * - NULL if we do not expect extraction. */ + #[DataProvider('providerQualifiedClassNameExtraction')] public function testQualifiedClassNameExtraction($code, $expected_changed_code, $expected_qualified_class_names) { // Make the protected method we're testing callable. $method = new \ReflectionMethod(PHPFile::class, 'extractFullyQualifiedClasses'); diff --git a/Test/Unit/ComponentPermissions10Test.php b/Test/Unit/ComponentPermissions10Test.php index dddc9acb..9f4c319c 100644 --- a/Test/Unit/ComponentPermissions10Test.php +++ b/Test/Unit/ComponentPermissions10Test.php @@ -2,13 +2,13 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\Group; use DrupalCodeBuilder\Test\Unit\Parsing\YamlTester; /** * Tests the Permissions generator class. - * - * @group yaml */ +#[Group('yaml')] class ComponentPermissions10Test extends TestBase { /** diff --git a/Test/Unit/ComponentPermissions7Test.php b/Test/Unit/ComponentPermissions7Test.php index 7571ff06..42507ba8 100644 --- a/Test/Unit/ComponentPermissions7Test.php +++ b/Test/Unit/ComponentPermissions7Test.php @@ -2,13 +2,13 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\Group; use DrupalCodeBuilder\Test\Unit\Parsing\PHPTester; /** * Tests the Permissions generator class. - * - * @group hooks */ +#[Group('hooks')] class ComponentPermissions7Test extends TestBase { /** diff --git a/Test/Unit/ComponentPluginType10Test.php b/Test/Unit/ComponentPluginType10Test.php index d6145031..0a428fea 100644 --- a/Test/Unit/ComponentPluginType10Test.php +++ b/Test/Unit/ComponentPluginType10Test.php @@ -2,15 +2,15 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\Group; use DrupalCodeBuilder\Test\Unit\Parsing\PHPTester; use DrupalCodeBuilder\Test\Unit\Parsing\YamlTester; /** * Tests generation of plugin types. - * - * @group yaml - * @group di */ +#[Group('yaml')] +#[Group('di')] class ComponentPluginType10Test extends TestBase { /** @@ -586,9 +586,8 @@ function testMultiplePluginTypes() { /** * Test Plugin Type with DI in the plugin base class. - * - * @group di */ + #[Group('di')] function testAttributePluginTypeWithServices() { $module_data = [ 'base' => 'module', diff --git a/Test/Unit/ComponentPluginsAnnotated9Test.php b/Test/Unit/ComponentPluginsAnnotated9Test.php index 75019945..8f1f4394 100644 --- a/Test/Unit/ComponentPluginsAnnotated9Test.php +++ b/Test/Unit/ComponentPluginsAnnotated9Test.php @@ -2,6 +2,8 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Group; use DrupalCodeBuilder\Test\Unit\Parsing\PHPTester; use DrupalCodeBuilder\Test\Unit\Parsing\YamlTester; use MutableTypedData\Exception\InvalidInputException; @@ -15,10 +17,9 @@ * types left. * * TODO: Restore this to Drupal 10 if I CBA. - * - * @group yaml - * @group plugin */ +#[Group('yaml')] +#[Group('plugin')] class ComponentPluginsAnnotated9Test extends TestBase { /** @@ -128,9 +129,8 @@ function testPluginsGenerationClassName() { * Tests special cases where prefixing of the plugin name should be skipped. * * This also tests that derivative plugin IDs are handled correctly. - * - * @dataProvider providerPluginsGenerationNamePrefixing */ + #[DataProvider('providerPluginsGenerationNamePrefixing')] public function testPluginsGenerationNamePrefixing(string $plugin_id, string $filename) { // Create a module. $module_name = 'test_module'; @@ -496,9 +496,8 @@ function testPluginsGenerationBadPluginType() { /** * Test Plugins component with injected services. - * - * @group di */ + #[Group('di')] function testPluginsGenerationWithServices() { // Create a module. $module_name = 'test_module'; @@ -573,9 +572,8 @@ function testPluginsGenerationWithServices() { /** * Test Plugins component with a plugin base class with an existing create(). - * - * @group di */ + #[Group('di')] function testPluginsGenerationWithExistingCreate() { // Create a module. $module_name = 'test_module'; @@ -658,9 +656,8 @@ function testPluginsGenerationWithExistingCreate() { /** * Tests a plugin base class with nonstandard fixed constructor parameters. - * - * @group di */ + #[Group('di')] function testPluginsGenerationWithNonstandardFixedParameters() { // Create a module. $module_name = 'test_module'; diff --git a/Test/Unit/ComponentPluginsAttribute11Test.php b/Test/Unit/ComponentPluginsAttribute11Test.php index 09bbbe32..e48b586a 100644 --- a/Test/Unit/ComponentPluginsAttribute11Test.php +++ b/Test/Unit/ComponentPluginsAttribute11Test.php @@ -2,6 +2,8 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Group; use DrupalCodeBuilder\Test\Unit\Parsing\PHPTester; use DrupalCodeBuilder\Test\Unit\Parsing\YamlTester; use MutableTypedData\Exception\InvalidInputException; @@ -12,10 +14,9 @@ * Tests generation of attribute plugins. * * TODO: This is missing testing of the actual attributes! - * - * @group yaml - * @group plugin */ +#[Group('yaml')] +#[Group('plugin')] class ComponentPluginsAttribute11Test extends TestBase { /** @@ -206,9 +207,8 @@ function testPluginsGenerationClassName() { * Tests special cases where prefixing of the plugin name should be skipped. * * This also tests that derivative plugin IDs are handled correctly. - * - * @dataProvider providerPluginsGenerationNamePrefixing */ + #[DataProvider('providerPluginsGenerationNamePrefixing')] public function testPluginsGenerationNamePrefixing(string $plugin_id, string $filename) { // Create a module. $module_name = 'test_module'; @@ -264,9 +264,8 @@ public static function providerPluginsGenerationNamePrefixing() { /** * Tests plugin derivers. - * - * @group di */ + #[Group('di')] function testPluginsGenerationDeriver() { // Create a module. $module_name = 'test_module'; @@ -465,9 +464,8 @@ function testPluginsGenerationBadPluginType() { /** * Test Plugins component with injected services. - * - * @group di */ + #[Group('di')] function testPluginsGenerationWithServices() { // Create a module. $module_name = 'test_module'; @@ -598,9 +596,8 @@ function testPluginsGenerationWithOtherSchema() { /** * Test the validation constraint plugin variant. - * - * @group di */ + #[Group('di')] public function testPluginValidationConstraint(): void { // Create a module. $module_name = 'test_module'; diff --git a/Test/Unit/ComponentPluginsYAML10Test.php b/Test/Unit/ComponentPluginsYAML10Test.php index 71d661be..4e977181 100644 --- a/Test/Unit/ComponentPluginsYAML10Test.php +++ b/Test/Unit/ComponentPluginsYAML10Test.php @@ -2,15 +2,15 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\Group; use DrupalCodeBuilder\Test\Unit\Parsing\PHPTester; use DrupalCodeBuilder\Test\Unit\Parsing\YamlTester; /** * Tests the PluginYAMLDiscovery generator class. - * - * @group yaml - * @group plugin */ +#[Group('yaml')] +#[Group('plugin')] class ComponentPluginsYAML10Test extends TestBase { /** @@ -104,9 +104,8 @@ function testYamlPluginsGenerationDeriver() { /** * Tests a custom plugin class with DI. - * - * @group di */ + #[Group('di')] public function testCustomPluginClass(): void { // Create a module. $module_data = [ diff --git a/Test/Unit/ComponentProfile10Test.php b/Test/Unit/ComponentProfile10Test.php index 14923f87..7c37fcd5 100644 --- a/Test/Unit/ComponentProfile10Test.php +++ b/Test/Unit/ComponentProfile10Test.php @@ -2,6 +2,7 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\Group; use DrupalCodeBuilder\Test\Unit\Parsing\YamlTester; use MutableTypedData\Data\DataItem; @@ -67,9 +68,8 @@ protected function simulateUiWalk(DataItem $data_item) { /** * Tests getting module configuration data. - * - * @group config */ + #[Group('config')] public function testConfiguration() { $config_data = \DrupalCodeBuilder\Factory::getTask('Configuration')->getConfigurationData('profile'); $properties = $config_data->getProperties(); diff --git a/Test/Unit/ComponentReadme10Test.php b/Test/Unit/ComponentReadme10Test.php index 62183bc6..77270648 100644 --- a/Test/Unit/ComponentReadme10Test.php +++ b/Test/Unit/ComponentReadme10Test.php @@ -2,6 +2,7 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\DataProvider; /** * Tests the README file. @@ -143,8 +144,6 @@ public static function dataReadmeWithDependencies() { /** * Tests the README file with dependencies. * - * @dataProvider dataReadmeWithDependencies - * * @param boolean $readme * The value for the readme property in the module data. * @param array $dependencies @@ -156,6 +155,7 @@ public static function dataReadmeWithDependencies() { * @param boolean $expect_requirements_dependencies * Whether to expect a list of dependencies in the Requirements section. */ + #[DataProvider('dataReadmeWithDependencies')] function testReadmeWithDependencies(bool $readme, array $dependencies, bool $expect_readme, bool $expect_requirements_section, bool $expect_requirements_dependencies) { // Create a module. $module_data = [ diff --git a/Test/Unit/ComponentRouterItem10Test.php b/Test/Unit/ComponentRouterItem10Test.php index 59543515..f6e11cfb 100644 --- a/Test/Unit/ComponentRouterItem10Test.php +++ b/Test/Unit/ComponentRouterItem10Test.php @@ -2,14 +2,15 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Group; use DrupalCodeBuilder\Test\Unit\Parsing\PHPTester; use DrupalCodeBuilder\Test\Unit\Parsing\YamlTester; /** * Tests for Router item component. - * - * @group yaml */ +#[Group('yaml')] class ComponentRouterItem10Test extends TestBase { /** @@ -227,9 +228,8 @@ public function testRouteControllerTypes() { * @param array $class_names_and_methods * (optional) An array of data about expected classes and their methods. * Keys are the relative class names. Values are arrays of method names. - * - * @dataProvider dataRouteAccessTypes */ + #[DataProvider('dataRouteAccessTypes')] public function testRouteAccessTypes( array $access, string $yaml_property, @@ -514,9 +514,8 @@ public function testRouteControllerClass() { /** * Test options for the controller class - * - * @group di */ + #[Group('di')] public function testRouteControllerClassWithDI() { // Assemble module data. $module_name = 'test_module'; @@ -634,9 +633,8 @@ public function testRouteForm() { /** * Test generating a route with a menu link. - * - * @group plugin */ + #[Group('plugin')] public function testRouteGenerationWithMenuLink() { // Assemble module data. $module_name = 'test_module'; @@ -692,9 +690,8 @@ public function testRouteGenerationWithMenuLink() { /** * Test generating a route with a menu tab. - * - * @group plugin */ + #[Group('plugin')] public function testRouteGenerationWithMenuTab() { // Assemble module data. $module_name = 'test_module'; @@ -742,9 +739,8 @@ public function testRouteGenerationWithMenuTab() { /** * Tests adoption of existing form. - * - * @group adopt */ + #[Group('adopt')] public function testExistingRouterItemAdoption() { // First pass: generate the files we'll mock as existing. $module_name = 'existing'; diff --git a/Test/Unit/ComponentRouterItem7Test.php b/Test/Unit/ComponentRouterItem7Test.php index 388ff874..7b8a8b73 100644 --- a/Test/Unit/ComponentRouterItem7Test.php +++ b/Test/Unit/ComponentRouterItem7Test.php @@ -2,13 +2,13 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\Group; use DrupalCodeBuilder\Test\Unit\Parsing\PHPTester; /** * Tests for Router item component. - * - * @group hooks */ +#[Group('hooks')] class ComponentRouterItem7Test extends TestBase { /** diff --git a/Test/Unit/ComponentService11Test.php b/Test/Unit/ComponentService11Test.php index 87a34133..6015bfd0 100644 --- a/Test/Unit/ComponentService11Test.php +++ b/Test/Unit/ComponentService11Test.php @@ -2,15 +2,16 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Group; use DrupalCodeBuilder\Test\Fixtures\File\MockableExtension; use DrupalCodeBuilder\Test\Unit\Parsing\PHPTester; use DrupalCodeBuilder\Test\Unit\Parsing\YamlTester; /** * Tests for Service component. - * - * @group yaml */ +#[Group('yaml')] class ComponentService11Test extends TestBase { /** @@ -70,9 +71,8 @@ public function testBasicServiceGeneration() { /** * Test namespace configuration for service generation. - * - * @group config */ + #[Group('config')] public function testServiceGenerationNamespaceConfiguration() { // Assemble module data. $module_name = 'test_module'; @@ -152,9 +152,8 @@ public function testServiceGenerationNamespaceConfiguration() { /** * Test YAML linebreaks configuration for service generation. - * - * @group config */ + #[Group('config')] public function testServiceGenerationYamlLinebreaksConfiguration() { $module_data = [ 'base' => 'module', @@ -192,9 +191,8 @@ public function testServiceGenerationYamlLinebreaksConfiguration() { /** * Test service parameter expansion configuration. - * - * @group config */ + #[Group('config')] public function testServiceGenerationYamlParameterLinebreaksConfiguration() { $module_data = [ 'base' => 'module', @@ -236,9 +234,8 @@ public function testServiceGenerationYamlParameterLinebreaksConfiguration() { /** * Test generating a module with a service using a preset. - * - * @group presets */ + #[Group('presets')] public function testServiceGenerationFromPreset() { // Assemble module data. $module_name = 'test_module'; @@ -484,10 +481,9 @@ public static function providerServiceGenerationWithServices() { /** * Test a service with with injected services. * - * @group di - * - * @dataProvider providerServiceGenerationWithServices */ + #[Group('di')] + #[DataProvider('providerServiceGenerationWithServices')] function testServiceGenerationWithServices($injected_services, bool $property_promotion, $yaml_arguments, $assert_injected_services) { // Assemble module data. $module_name = 'test_module'; @@ -539,9 +535,8 @@ function testServiceGenerationWithServices($injected_services, bool $property_pr /** * Test several services injecting the same services. - * - * @group di */ + #[Group('di')] function testServiceGenerationRepeatedInjectedServies() { $module_name = 'test_module'; $module_data = [ @@ -827,9 +822,8 @@ class: Drupal\existing\Alpha /** * Test a service that decorates another. - * - * @group di */ + #[Group('di')] function testServiceGenerationWithDecoration() { // Assemble module data: decoration without any injected services. $module_data = [ @@ -941,11 +935,10 @@ function testServiceGenerationWithDecoration() { * The expected YAML defining the list of existing services, without the * initial 'services' key. NULL if no file is expected to be generated. * - * @group existing - * - * @dataProvider dataExistingServicesYamlFile * */ + #[Group('existing')] + #[DataProvider('dataExistingServicesYamlFile')] public function testExistingServicesYamlFile(?string $existing, ?array $generated, ?string $resulting) { $module_name = 'existing'; $module_data = [ @@ -1079,9 +1072,6 @@ public static function dataExistingServiceMerge() { /** * Test merging of injected services in an existing service. * - * @group existing - * - * @dataProvider dataExistingServiceMerge * * @param array $existing_service_data * The module data for a single service to generate as the mocked existing @@ -1092,6 +1082,8 @@ public static function dataExistingServiceMerge() { * The expected injected services, in the format expected by * assertInjectedServices(). */ + #[Group('existing')] + #[DataProvider('dataExistingServiceMerge')] public function testExistingServiceMerge($existing_service_data, $generated_service_data, $expected_injected_services) { // First pass: generate the files we'll mock as existing. $module_name = 'existing'; @@ -1233,10 +1225,9 @@ public static function dataExistingServicesAdoption() { * @param string $adopted_relative_class * The relative class name of the adopted service. * - * @group adopt - * - * @dataProvider dataExistingServicesAdoption */ + #[Group('adopt')] + #[DataProvider('dataExistingServicesAdoption')] public function testExistingServicesAdoption(array $data_services, string $adopted_relative_class) { // Mock an existing module. $extension = new MockableExtension('module', __DIR__ . '/../Fixtures/modules/existing/'); diff --git a/Test/Unit/ComponentServiceEventSubscriber10Test.php b/Test/Unit/ComponentServiceEventSubscriber10Test.php index 130560b1..b8efd469 100644 --- a/Test/Unit/ComponentServiceEventSubscriber10Test.php +++ b/Test/Unit/ComponentServiceEventSubscriber10Test.php @@ -2,14 +2,14 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\Group; use DrupalCodeBuilder\Test\Unit\Parsing\PHPTester; use DrupalCodeBuilder\Test\Unit\Parsing\YamlTester; /** * Tests for event subscriber component. - * - * @group yaml */ +#[Group('yaml')] class ComponentServiceEventSubscriber10Test extends TestBase { /** diff --git a/Test/Unit/ComponentTestsPHPUnit10Test.php b/Test/Unit/ComponentTestsPHPUnit10Test.php index 8a8b44e9..7194dbdb 100644 --- a/Test/Unit/ComponentTestsPHPUnit10Test.php +++ b/Test/Unit/ComponentTestsPHPUnit10Test.php @@ -2,6 +2,8 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Group; use DrupalCodeBuilder\Test\Fixtures\File\MockableExtension; use DrupalCodeBuilder\Test\Unit\Parsing\PHPTester; use DrupalCodeBuilder\Test\Unit\Parsing\YamlTester; @@ -271,10 +273,9 @@ public static function dataModuleGenerationTestsWithServices(): array { /** * Create a test class with services. * - * @group di - * - * @dataProvider dataModuleGenerationTestsWithServices */ + #[Group('di')] + #[DataProvider('dataModuleGenerationTestsWithServices')] function testModuleGenerationTestsWithServices(bool $container_services = FALSE, bool $mocked_services = FALSE) { // Create a module. $module_name = 'test_module'; @@ -340,9 +341,8 @@ function testModuleGenerationTestsWithServices(bool $container_services = FALSE, /** * Create a test class with a test module. - * - * @group test */ + #[Group('test')] function testModuleGenerationTestsWithBasicTestModule() { // Create a module. $module_name = 'generated_module'; @@ -375,9 +375,8 @@ function testModuleGenerationTestsWithBasicTestModule() { /** * Create a test class with a test module and module components. - * - * @group test */ + #[Group('test')] function testModuleGenerationTestsWithTestModuleComponents() { // Create a module. $module_name = 'generated_module'; @@ -554,11 +553,6 @@ public static function dataTestModuleWithExistingFunctions() { * This generates a hook in either the main or the test module, with an * existing function is either the main or test module file. * - * @group existing - * @group test - * - * @dataProvider dataTestModuleWithExistingFunctions - * * @param string $generated * Where the generated hook goes. One of: * - 'main': The main generated module. @@ -568,6 +562,9 @@ public static function dataTestModuleWithExistingFunctions() { * - 'main': The main generated module. * - 'test': The test module. */ + #[Group('existing')] + #[Group('test')] + #[DataProvider('dataTestModuleWithExistingFunctions')] public function testTestModuleWithExistingFunctions(string $generated, string $existing_code) { // Create a module. $module_data = [ @@ -680,11 +677,6 @@ function $existing_function_name() { * This generates a service in either the main or the test module, with an * existing service is either the main or test module. * - * @group existing - * @group test - * - * @dataProvider dataTestModuleWithExistingFunctions - * * @param string $generated * Where the generated service goes. One of: * - 'main': The main generated module. @@ -694,6 +686,9 @@ function $existing_function_name() { * - 'main': The main generated module. * - 'test': The test module. */ + #[Group('existing')] + #[Group('test')] + #[DataProvider('dataTestModuleWithExistingFunctions')] public function testTestModuleWithExistingServices(string $generated, string $existing_code) { $services_value = [ [ diff --git a/Test/Unit/ComponentTestsPHPUnit9Test.php b/Test/Unit/ComponentTestsPHPUnit9Test.php index 3155128d..c73a8475 100644 --- a/Test/Unit/ComponentTestsPHPUnit9Test.php +++ b/Test/Unit/ComponentTestsPHPUnit9Test.php @@ -2,6 +2,8 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Group; use DrupalCodeBuilder\Test\Fixtures\File\MockableExtension; use DrupalCodeBuilder\Test\Unit\Parsing\PHPTester; use DrupalCodeBuilder\Test\Unit\Parsing\YamlTester; @@ -163,9 +165,8 @@ function testModuleGenerationKernelTest() { /** * Create a kernel test with creation traits. - * - * @group test */ + #[Group('test')] function testKernelTestWithTraits() { // Create a module. $module_name = 'test_module'; @@ -204,9 +205,8 @@ function testKernelTestWithTraits() { /** * Create a test class with services. - * - * @group di */ + #[Group('di')] function testModuleGenerationTestsWithServices() { // Create a module. $module_name = 'test_module'; @@ -261,9 +261,8 @@ function testModuleGenerationTestsWithServices() { /** * Create a test class with a test module. - * - * @group test */ + #[Group('test')] function testModuleGenerationTestsWithBasicTestModule() { // Create a module. $module_name = 'generated_module'; @@ -296,9 +295,8 @@ function testModuleGenerationTestsWithBasicTestModule() { /** * Create a test class with a test module and module components. - * - * @group test */ + #[Group('test')] function testModuleGenerationTestsWithTestModuleComponents() { // TODO: Figure out why this works on 8 but not on 9! $this->markTestSkipped(); @@ -478,11 +476,6 @@ public static function dataTestModuleWithExistingFunctions() { * This generates a hook in either the main or the test module, with an * existing function is either the main or test module file. * - * @group existing - * @group test - * - * @dataProvider dataTestModuleWithExistingFunctions - * * @param string $generated * Where the generated hook goes. One of: * - 'main': The main generated module. @@ -492,6 +485,9 @@ public static function dataTestModuleWithExistingFunctions() { * - 'main': The main generated module. * - 'test': The test module. */ + #[Group('existing')] + #[Group('test')] + #[DataProvider('dataTestModuleWithExistingFunctions')] public function testTestModuleWithExistingFunctions(string $generated, string $existing_code) { // Create a module. $module_data = [ @@ -604,11 +600,6 @@ function $existing_function_name() { * This generates a service in either the main or the test module, with an * existing service is either the main or test module. * - * @group existing - * @group test - * - * @dataProvider dataTestModuleWithExistingFunctions - * * @param string $generated * Where the generated service goes. One of: * - 'main': The main generated module. @@ -618,6 +609,9 @@ function $existing_function_name() { * - 'main': The main generated module. * - 'test': The test module. */ + #[Group('existing')] + #[Group('test')] + #[DataProvider('dataTestModuleWithExistingFunctions')] public function testTestModuleWithExistingServices(string $generated, string $existing_code) { $services_value = [ [ diff --git a/Test/Unit/ComponentThemeHook10Test.php b/Test/Unit/ComponentThemeHook10Test.php index 11552953..2d8635ee 100644 --- a/Test/Unit/ComponentThemeHook10Test.php +++ b/Test/Unit/ComponentThemeHook10Test.php @@ -2,12 +2,13 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\Group; use DrupalCodeBuilder\Test\Unit\Parsing\PHPTester; /** * Tests the theme hook generator class. - * @group hooks */ +#[Group('hooks')] class ComponentThemeHook10Test extends TestBase { /** diff --git a/Test/Unit/ComponentThemeHook11Test.php b/Test/Unit/ComponentThemeHook11Test.php index 39b69c62..16767eb1 100644 --- a/Test/Unit/ComponentThemeHook11Test.php +++ b/Test/Unit/ComponentThemeHook11Test.php @@ -2,12 +2,13 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\Group; use DrupalCodeBuilder\Test\Unit\Parsing\PHPTester; /** * Tests the theme hook generator class. - * @group hooks */ +#[Group('hooks')] class ComponentThemeHook11Test extends TestBase { /** diff --git a/Test/Unit/ContainerCollectionTest.php b/Test/Unit/ContainerCollectionTest.php index 62025d6a..1a8b036e 100644 --- a/Test/Unit/ContainerCollectionTest.php +++ b/Test/Unit/ContainerCollectionTest.php @@ -2,12 +2,12 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\Group; /** * Tests the container collection. - * - * @group container */ +#[Group('container')] class ContainerCollectionTest extends TestBase { protected $drupalMajorVersion = 9; diff --git a/Test/Unit/ContainerRebuildTest.php b/Test/Unit/ContainerRebuildTest.php index 36d4eeae..f7ef77eb 100644 --- a/Test/Unit/ContainerRebuildTest.php +++ b/Test/Unit/ContainerRebuildTest.php @@ -2,12 +2,13 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\TestCase; /** * Tests rebuilding the cached container. - * @group container */ +#[Group('container')] class ContainerRebuildTest extends TestCase { /** diff --git a/Test/Unit/ContainerTest.php b/Test/Unit/ContainerTest.php index 524059fd..d88b22a5 100644 --- a/Test/Unit/ContainerTest.php +++ b/Test/Unit/ContainerTest.php @@ -2,6 +2,7 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\TestCase; /** @@ -10,8 +11,8 @@ * In particular, this needs to test that two separate test cases with different * core major versions set on the environment don't cross-pollute the * container's versionned services. - * @group container */ +#[Group('container')] class ContainerTest extends TestCase { /** diff --git a/Test/Unit/DrupalCodeBuilderAssertionsTest.php b/Test/Unit/DrupalCodeBuilderAssertionsTest.php index 4ca90cdd..f3cb7e9b 100644 --- a/Test/Unit/DrupalCodeBuilderAssertionsTest.php +++ b/Test/Unit/DrupalCodeBuilderAssertionsTest.php @@ -2,6 +2,7 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\ExpectationFailedException; use PHPUnit\Framework\TestCase; @@ -15,13 +16,12 @@ class DrupalCodeBuilderAssertionsTest extends TestCase { /** * Tests the assertNoTrailingWhitespace() assertion. * - * @dataProvider providerAssertNoTrailingWhitespace - * * @param $code * The code to test with the assertion. * @param $pass * Whether the assertion is expected to pass (TRUE) or fail (FALSE). */ + #[DataProvider('providerAssertNoTrailingWhitespace')] public function testAssertNoTrailingWhitespace($code, $pass) { try { TestBase::assertNoTrailingWhitespace($code); @@ -54,13 +54,12 @@ public static function providerAssertNoTrailingWhitespace() { /** * Tests the assertFunctionParameter() assertion. * - * @dataProvider providerAssertFunctionParameter - * * @param $code * The code to test with the assertion. * @param $pass * Whether the assertion is expected to pass (TRUE) or fail (FALSE). */ + #[DataProvider('providerAssertFunctionParameter')] public function testAssertFunctionParameter($code, $pass) { // TODO: adapt these to cover PHPTester. $this->markTestSkipped(); @@ -102,8 +101,6 @@ public static function providerAssertFunctionParameter() { /** * Tests the assertDocBlock() assertion. * - * @dataProvider providerAssertDocBlock - * * @param $lines * The docblock lines to test with the assertion. * @param $code @@ -111,6 +108,7 @@ public static function providerAssertFunctionParameter() { * @param $pass * Whether the assertion is expected to pass (TRUE) or fail (FALSE). */ + #[DataProvider('providerAssertDocBlock')] public function testAssertDocBlock($lines, $code, $indent, $pass) { // TODO: adapt these to cover PHPTester. $this->markTestSkipped(); @@ -251,13 +249,12 @@ function myMethod { /** * Tests the assertFunction() assertion. * - * @dataProvider providerAssertFunction - * * @param $code * The code to test with the assertion. * @param $pass * Whether the assertion is expected to pass (TRUE) or fail (FALSE). */ + #[DataProvider('providerAssertFunction')] public function testAssertFunction($code, $pass) { // TODO: adapt these to cover PHPTester. $this->markTestSkipped(); diff --git a/Test/Unit/GenerateHelperComponentCollectorTest.php b/Test/Unit/GenerateHelperComponentCollectorTest.php index 69a97792..42748436 100644 --- a/Test/Unit/GenerateHelperComponentCollectorTest.php +++ b/Test/Unit/GenerateHelperComponentCollectorTest.php @@ -2,6 +2,8 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\DataProvider; use DrupalCodeBuilder\Definition\MergingGeneratorDefinition; use DrupalCodeBuilder\Definition\PropertyDefinition; use DrupalCodeBuilder\Definition\DeferredGeneratorDefinition; @@ -180,9 +182,8 @@ public static function providerGeneratorChildNoRequests() { /** * Request with nested component properties. - * - * @dataProvider providerGeneratorChildNoRequests */ + #[DataProvider('providerGeneratorChildNoRequests')] public function testGeneratorChildNoRequests($data_value, $expected_paths) { $definition = MergingGeneratorDefinition::createFromGeneratorType('my_root') ->setName('my_root') @@ -256,9 +257,8 @@ public function testMultipleStringGeneratorChildNoRequests() { /** * Request with only the root generator, with a single-value preset. - * - * @group presets */ + #[Group('presets')] public function testSingleGeneratorSinglePresetsNoRequirements() { $definition = MergingGeneratorDefinition::createFromGeneratorType('my_root') ->setProperties([ @@ -343,9 +343,8 @@ public function testSingleGeneratorSinglePresetsNoRequirements() { /** * Request with only the root generator, with a multi-valued preset. - * - * @group presets */ + #[Group('presets')] public function testSingleGeneratorMultiPresetsNoRequirements() { $definition = MergingGeneratorDefinition::createFromGeneratorType('my_root') ->setProperties([ diff --git a/Test/Unit/ParserDocBlockTest.php b/Test/Unit/ParserDocBlockTest.php index f781e63c..c81aaa2f 100644 --- a/Test/Unit/ParserDocBlockTest.php +++ b/Test/Unit/ParserDocBlockTest.php @@ -2,6 +2,7 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\Group; use DrupalCodeBuilder\Test\Unit\Parsing\DocBlockTester; use PHPUnit\Framework\TestCase; use PHPUnit\Framework\ExpectationFailedException; @@ -10,9 +11,8 @@ /** * Unit tests for the DocBlockTester test helper. - * - * @group php_tester_docblocks */ +#[Group('php_tester_docblocks')] class ParserDocBlockTest extends TestCase { /** diff --git a/Test/Unit/ParserPHPTest.php b/Test/Unit/ParserPHPTest.php index abfa9e1e..9b3f0dd2 100644 --- a/Test/Unit/ParserPHPTest.php +++ b/Test/Unit/ParserPHPTest.php @@ -2,6 +2,8 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use PHPUnit\Framework\ExpectationFailedException; use DrupalCodeBuilder\Test\Unit\Parsing\PHPTester; @@ -17,9 +19,8 @@ class ParserPHPTest extends TestCase { * * This is fairly simple for now, and is just to sanity check that Coder * and PHP Codersniffer run ok. - * - * @dataProvider providerAssertDrupalCodingStandards */ + #[DataProvider('providerAssertDrupalCodingStandards')] public function testAssertDrupalCodingStandards($code, $pass) { $php_tester = new PHPTester(8, $code); @@ -180,9 +181,8 @@ class Foo implements Plain, WithSpace { /** * Tests the assertClassHasInterfaces() assertion. - * - * @dataProvider providerAssertClassInterfaces */ + #[DataProvider('providerAssertClassInterfaces')] public function testAssertClassInterfaces($expected_interfaces, $pass_has, $pass_has_not) { $php = <<setMultiple(TRUE); @@ -147,9 +147,8 @@ public static function dataMultipleSimpleData() { /** * Tests single-valued complex data. - * - * @dataProvider dataSingleComplexData */ + #[DataProvider('dataSingleComplexData')] public function testSingleComplexData(array $original_values, array $other_values, ?array $end_values, ?bool $expected_result, bool $expect_exception) { $definition = PropertyDefinition::create('complex') ->setProperties([ @@ -219,9 +218,8 @@ public static function dataSingleComplexData() { /** * Tests multi-valued complex data. - * - * @dataProvider dataMultipleComplexData */ + #[DataProvider('dataMultipleComplexData')] public function testMultipleComplexData(array $original_values, array $other_values, ?array $end_values, ?bool $expected_result) { $definition = PropertyDefinition::create('complex') ->setMultiple(TRUE) @@ -353,9 +351,8 @@ public static function dataMultipleComplexData() { * Tests merging mapping data. * * We only cover single-valued as mapping data is rarely if ever multiple. - * - * @dataProvider dataMappingData */ + #[DataProvider('dataMappingData')] public function testMappingData(array $original_values, array $other_values, ?array $end_values, ?bool $expected_result, bool $expect_exception) { $definition = PropertyDefinition::create('mapping'); diff --git a/Test/Unit/UnitDependencyInjectionAnalysisTest.php b/Test/Unit/UnitDependencyInjectionAnalysisTest.php index 817e5d40..f8f1f8c6 100644 --- a/Test/Unit/UnitDependencyInjectionAnalysisTest.php +++ b/Test/Unit/UnitDependencyInjectionAnalysisTest.php @@ -2,6 +2,7 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; /** @@ -12,14 +13,13 @@ class UnitDependencyInjectionAnalysisTest extends TestCase { /** * Tests the method analysis. * - * @dataProvider dataDependencyInjection - * * @param object $class_object * An instance of an anonymous class to analyse. This is an object because * passing the class name of anonymous class is fiddly. * @param array $result * The expected result. */ + #[DataProvider('dataDependencyInjection')] public function testDependencyInjection($class_object, $result) { $parent_construction_parameters = \DrupalCodeBuilder\Utility\CodeAnalysis\DependencyInjection::getInjectedParameters($class_object::class, 0); diff --git a/Test/Unit/UnitMethodCollectorTest.php b/Test/Unit/UnitMethodCollectorTest.php index 1937c2a4..4eb9cead 100644 --- a/Test/Unit/UnitMethodCollectorTest.php +++ b/Test/Unit/UnitMethodCollectorTest.php @@ -2,6 +2,7 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; use DrupalCodeBuilder\Task\Collect\MethodCollector; use DrupalCodeBuilder\Test\Fixtures\MethodCollectorInterface; @@ -13,9 +14,8 @@ class UnitMethodCollectorTest extends TestCase { /** * Tests the method analysis. - * - * @dataProvider providerMethodCollector */ + #[DataProvider('providerMethodCollector')] public function testMethodCollector($method_name, $declaration_result) { $method_collector = new MethodCollector(); diff --git a/Test/Unit/UnitValidatorTest.php b/Test/Unit/UnitValidatorTest.php index 82e97501..637f2fbf 100644 --- a/Test/Unit/UnitValidatorTest.php +++ b/Test/Unit/UnitValidatorTest.php @@ -2,6 +2,7 @@ namespace DrupalCodeBuilder\Test\Unit; +use PHPUnit\Framework\Attributes\DataProvider; use MutableTypedData\Definition\DataDefinition; use PHPUnit\Framework\TestCase; @@ -33,9 +34,8 @@ public static function providerClassNameValidator() { /** * Tests the class name validator. - * - * @dataProvider providerClassNameValidator */ + #[DataProvider('providerClassNameValidator')] public function testClassNameValidator($value, $expected_pass) { $validator = new \DrupalCodeBuilder\MutableTypedData\Validator\ClassName(); @@ -84,9 +84,8 @@ public static function providerMachineNameValidator() { /** * Tests the machine name validator. - * - * @dataProvider providerMachineNameValidator */ + #[DataProvider('providerMachineNameValidator')] public function testMachineNameValidator($value, $expected_pass) { $validator = new \DrupalCodeBuilder\MutableTypedData\Validator\MachineName(); @@ -166,9 +165,8 @@ public static function providerPluginNameValidator() { /** * Tests the plugin name validator. - * - * @dataProvider providerPluginNameValidator */ + #[DataProvider('providerPluginNameValidator')] public function testPluginNameValidator($value, $expected_pass) { $validator = new \DrupalCodeBuilder\MutableTypedData\Validator\PluginName(); @@ -233,9 +231,8 @@ public static function providerYamlPluginNameValidator() { /** * Tests the YAML plugin name validator. - * - * @dataProvider providerYamlPluginNameValidator */ + #[DataProvider('providerYamlPluginNameValidator')] public function testYamlPluginNameValidator($value, $expected_pass) { $validator = new \DrupalCodeBuilder\MutableTypedData\Validator\YamlPluginName();