From e71b1d399634bde945495685b040b23d23bc973e Mon Sep 17 00:00:00 2001 From: Adam G-H <32250-phenaproxima@users.noreply.drupalcode.org> Date: Thu, 13 Feb 2025 19:11:04 +0000 Subject: [PATCH] Issue #3506511: Use attributes for source plugin definitions --- .../project_browser.admin_settings.yml | 1 + .../ProjectBrowserSource/RandomDataPlugin.php | 19 +++--- .../ProjectBrowserSourceExample.php | 13 ++-- project_browser.install | 18 ------ project_browser.module | 19 ------ src/Annotation/ProjectBrowserSource.php | 60 ------------------- src/Attribute/ProjectBrowserSource.php | 41 +++++++++++++ .../ProjectBrowserSource/DrupalCore.php | 21 +++---- .../DrupalDotOrgJsonApi.php | 19 +++--- src/Plugin/ProjectBrowserSource/Recipes.php | 10 ++++ src/Plugin/ProjectBrowserSourceManager.php | 3 +- .../ProjectBrowserTestMock.php | 19 +++--- tests/src/Kernel/RecipesSourceTest.php | 19 ------ 13 files changed, 100 insertions(+), 162 deletions(-) delete mode 100644 src/Annotation/ProjectBrowserSource.php create mode 100644 src/Attribute/ProjectBrowserSource.php diff --git a/config/install/project_browser.admin_settings.yml b/config/install/project_browser.admin_settings.yml index 1abc75ca3..e90d04658 100644 --- a/config/install/project_browser.admin_settings.yml +++ b/config/install/project_browser.admin_settings.yml @@ -1,5 +1,6 @@ enabled_sources: - drupalorg_jsonapi + - recipes allow_ui_install: false allowed_projects: {} max_selections: null diff --git a/modules/project_browser_devel/src/Plugin/ProjectBrowserSource/RandomDataPlugin.php b/modules/project_browser_devel/src/Plugin/ProjectBrowserSource/RandomDataPlugin.php index 188a5ca34..2ca646992 100644 --- a/modules/project_browser_devel/src/Plugin/ProjectBrowserSource/RandomDataPlugin.php +++ b/modules/project_browser_devel/src/Plugin/ProjectBrowserSource/RandomDataPlugin.php @@ -4,7 +4,9 @@ namespace Drupal\project_browser_devel\Plugin\ProjectBrowserSource; use Drupal\Component\Utility\Random; use Drupal\Core\Cache\CacheBackendInterface; +use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\Core\Url; +use Drupal\project_browser\Attribute\ProjectBrowserSource; use Drupal\project_browser\Plugin\ProjectBrowserSourceBase; use Drupal\project_browser\ProjectBrowser\Filter\BooleanFilter; use Drupal\project_browser\ProjectBrowser\Filter\MultipleChoiceFilter; @@ -14,18 +16,13 @@ use Symfony\Component\DependencyInjection\ContainerInterface; /** * Random data plugin. Used mostly for testing. - * - * To enable this source use the following drush command. - * phpcs:ignore - * drush config:set project_browser.admin_settings enabled_source random_data - * - * @ProjectBrowserSource( - * id = "random_data", - * label = @Translation("Random data"), - * description = @Translation("Gets random project and filters information"), - * local_task = {} - * ) */ +#[ProjectBrowserSource( + id: 'random_data', + label: new TranslatableMarkup('Random data'), + description: new TranslatableMarkup('Gets random project and filters information'), + local_task: [], +)] final class RandomDataPlugin extends ProjectBrowserSourceBase { /** diff --git a/modules/project_browser_source_example/src/Plugin/ProjectBrowserSource/ProjectBrowserSourceExample.php b/modules/project_browser_source_example/src/Plugin/ProjectBrowserSource/ProjectBrowserSourceExample.php index 6d5b207e5..375f6b633 100644 --- a/modules/project_browser_source_example/src/Plugin/ProjectBrowserSource/ProjectBrowserSourceExample.php +++ b/modules/project_browser_source_example/src/Plugin/ProjectBrowserSource/ProjectBrowserSourceExample.php @@ -2,7 +2,9 @@ namespace Drupal\project_browser_source_example\Plugin\ProjectBrowserSource; +use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\Core\Url; +use Drupal\project_browser\Attribute\ProjectBrowserSource; use Drupal\project_browser\Plugin\ProjectBrowserSourceBase; use Drupal\project_browser\ProjectBrowser\Project; use Drupal\project_browser\ProjectBrowser\ProjectsResultsPage; @@ -11,13 +13,12 @@ use Symfony\Component\HttpFoundation\RequestStack; /** * Project Browser Source Plugin example code. - * - * @ProjectBrowserSource( - * id = "project_browser_source_example", - * label = @Translation("Example source"), - * description = @Translation("Example source plugin for Project Browser."), - * ) */ +#[ProjectBrowserSource( + id: 'project_browser_source_example', + label: new TranslatableMarkup('Example source'), + description: new TranslatableMarkup('Example source plugin for Project Browser.'), +)] final class ProjectBrowserSourceExample extends ProjectBrowserSourceBase { /** diff --git a/project_browser.install b/project_browser.install index 8c5e62d7a..6c142cadb 100644 --- a/project_browser.install +++ b/project_browser.install @@ -5,24 +5,6 @@ * Contains install and update functions for Project Browser. */ -use Drupal\Core\Recipe\Recipe; - -/** - * Implements hook_install(). - * - * Populates the project_browser_projects using a fixture with PHP serialized - * items. - */ -function project_browser_install(): void { - if (class_exists(Recipe::class)) { - $config = \Drupal::configFactory() - ->getEditable('project_browser.admin_settings'); - $enabled_sources = $config->get('enabled_sources'); - $enabled_sources[] = 'recipes'; - $config->set('enabled_sources', $enabled_sources)->save(); - } -} - /** * Implements hook_update_last_removed(). */ diff --git a/project_browser.module b/project_browser.module index e168a2f1c..5ff0bb0b2 100644 --- a/project_browser.module +++ b/project_browser.module @@ -5,10 +5,8 @@ * Provides hook implementations for the Project Browser module. */ -use Drupal\Core\Recipe\Recipe; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Url; -use Drupal\project_browser\Plugin\ProjectBrowserSource\Recipes; /** * Implements hook_help(). @@ -43,23 +41,6 @@ function project_browser_theme(): array { ]; } -/** - * Implements hook_project_browser_source_info_alter(). - */ -function project_browser_project_browser_source_info_alter(array &$definitions): void { - if (class_exists(Recipe::class)) { - $definitions['recipes'] = [ - 'id' => 'recipes', - 'label' => t('Recipes'), - 'description' => t('Recipes available in the local code base'), - 'local_task' => [ - 'weight' => ($definitions['drupalorg_jsonapi']['local_task']['weight'] ?? 5) + 2, - ], - 'class' => Recipes::class, - ]; - } -} - /** * Preprocess function for the project_browser_main_app theme hook. * diff --git a/src/Annotation/ProjectBrowserSource.php b/src/Annotation/ProjectBrowserSource.php deleted file mode 100644 index aab59a016..000000000 --- a/src/Annotation/ProjectBrowserSource.php +++ /dev/null @@ -1,60 +0,0 @@ -<?php - -namespace Drupal\project_browser\Annotation; - -use Drupal\Component\Annotation\Plugin; - -/** - * Defines a Project Browser source plugin annotation object. - * - * Project Browser sources are used to provide information about - * available projects that can be installed on a Drupal site. - * Typically, these come from Drupal.org, but may also come - * from a private repository, etc. - * - * Plugin Namespace: Plugin\ProjectBrowserSource - * - * For a working example, see: - * \Drupal\project_browser\Plugin\ProjectBrowserSource\MockDrupalDotOrg - * - * @see \Drupal\project_browser\Plugin\ProjectBrowserSourceInterface - * @see \Drupal\project_browser\Plugin\ProjectBrowserSourceManager - * @see plugin_api - * - * @Annotation - */ -class ProjectBrowserSource extends Plugin { - - /** - * The plugin ID. - * - * @var string - */ - public $id; - - /** - * The human-readable name of the source. - * - * @var \Drupal\Core\Annotation\Translation - * @ingroup plugin_translatable - */ - public $label; - - /** - * A short description of the source. - * - * @var \Drupal\Core\Annotation\Translation - * @ingroup plugin_translatable - */ - public $description; - - /** - * The local task definition at which this source should be exposed. - * - * If NULL, the source will never be exposed as a local task. - * - * @var array|null - */ - public ?array $local_task = NULL; - -} diff --git a/src/Attribute/ProjectBrowserSource.php b/src/Attribute/ProjectBrowserSource.php new file mode 100644 index 000000000..f7b738a73 --- /dev/null +++ b/src/Attribute/ProjectBrowserSource.php @@ -0,0 +1,41 @@ +<?php + +declare(strict_types=1); + +namespace Drupal\project_browser\Attribute; + +use Drupal\Component\Plugin\Attribute\Plugin; +use Drupal\Core\StringTranslation\TranslatableMarkup; + +/** + * Defines an attribute to identify Project Browser source plugins. + */ +#[\Attribute(\Attribute::TARGET_CLASS)] +final class ProjectBrowserSource extends Plugin { + + /** + * Constructs a ProjectBrowserSource attribute. + * + * @param string $id + * The plugin ID. + * @param \Drupal\Core\StringTranslation\TranslatableMarkup $label + * The plugin's human-readable name. + * @param \Drupal\Core\StringTranslation\TranslatableMarkup $description + * A brief description of the plugin and what it does. + * @param array|null $local_task + * A local task definition at which this source should be exposed in the UI. + * If NULL, the source will not be shown as a local task. + * @param class-string|null $deriver + * The plugin's deriver class, if any. + */ + public function __construct( + string $id, + public TranslatableMarkup $label, + public TranslatableMarkup $description, + public ?array $local_task = NULL, + ?string $deriver = NULL, + ) { + parent::__construct($id, $deriver); + } + +} diff --git a/src/Plugin/ProjectBrowserSource/DrupalCore.php b/src/Plugin/ProjectBrowserSource/DrupalCore.php index 48868d196..d71c36c67 100644 --- a/src/Plugin/ProjectBrowserSource/DrupalCore.php +++ b/src/Plugin/ProjectBrowserSource/DrupalCore.php @@ -6,24 +6,25 @@ use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Extension\Extension; use Drupal\Core\Extension\ModuleExtensionList; use Drupal\Core\Site\Settings; +use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\Core\Url; +use Drupal\project_browser\Attribute\ProjectBrowserSource; use Drupal\project_browser\Plugin\ProjectBrowserSourceBase; use Drupal\project_browser\ProjectBrowser\Project; use Drupal\project_browser\ProjectBrowser\ProjectsResultsPage; use Symfony\Component\DependencyInjection\ContainerInterface; /** - * The source plugin to get Drupal core projects list. - * - * @ProjectBrowserSource( - * id = "drupal_core", - * label = @Translation("Core modules"), - * description = @Translation("Modules included in Drupal core"), - * local_task = { - * "title" = @Translation("Core modules"), - * } - * ) + * A source that lists Drupal core modules. */ +#[ProjectBrowserSource( + id: 'drupal_core', + label: new TranslatableMarkup('Core modules'), + description: new TranslatableMarkup('Modules included in Drupal core'), + local_task: [ + 'title' => new TranslatableMarkup('Core modules'), + ], +)] final class DrupalCore extends ProjectBrowserSourceBase { public function __construct( diff --git a/src/Plugin/ProjectBrowserSource/DrupalDotOrgJsonApi.php b/src/Plugin/ProjectBrowserSource/DrupalDotOrgJsonApi.php index 8e53b48ee..69074fedd 100644 --- a/src/Plugin/ProjectBrowserSource/DrupalDotOrgJsonApi.php +++ b/src/Plugin/ProjectBrowserSource/DrupalDotOrgJsonApi.php @@ -9,7 +9,9 @@ use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Extension\ExtensionVersion; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; +use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\Core\Url; +use Drupal\project_browser\Attribute\ProjectBrowserSource; use Drupal\project_browser\Plugin\ProjectBrowserSourceBase; use Drupal\project_browser\ProjectBrowser\Filter\BooleanFilter; use Drupal\project_browser\ProjectBrowser\Filter\MultipleChoiceFilter; @@ -23,16 +25,15 @@ use Symfony\Component\HttpFoundation\Response; /** * Drupal.org JSON:API endpoint. - * - * @ProjectBrowserSource( - * id = "drupalorg_jsonapi", - * label = @Translation("Contrib modules"), - * description = @Translation("Modules on Drupal.org queried via the JSON:API endpoint"), - * local_task = { - * "title" = @Translation("Contrib modules"), - * } - * ) */ +#[ProjectBrowserSource( + id: 'drupalorg_jsonapi', + label: new TranslatableMarkup('Contrib modules'), + description: new TranslatableMarkup('Modules on Drupal.org queried via the JSON:API endpoint'), + local_task: [ + 'title' => new TranslatableMarkup('Contrib modules'), + ], +)] final class DrupalDotOrgJsonApi extends ProjectBrowserSourceBase { use StringTranslationTrait; diff --git a/src/Plugin/ProjectBrowserSource/Recipes.php b/src/Plugin/ProjectBrowserSource/Recipes.php index b5bf79c62..f8283a8a3 100644 --- a/src/Plugin/ProjectBrowserSource/Recipes.php +++ b/src/Plugin/ProjectBrowserSource/Recipes.php @@ -13,7 +13,9 @@ use Drupal\Core\Extension\ModuleExtensionList; use Drupal\Core\File\FileSystemInterface; use Drupal\Core\Recipe\Recipe; use Drupal\Core\Site\Settings; +use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\Core\Url; +use Drupal\project_browser\Attribute\ProjectBrowserSource; use Drupal\project_browser\Plugin\ProjectBrowserSourceBase; use Drupal\project_browser\ProjectBrowser\Project; use Drupal\project_browser\ProjectBrowser\ProjectsResultsPage; @@ -24,6 +26,14 @@ use Symfony\Component\Finder\Finder; /** * A source plugin that exposes recipes installed locally. */ +#[ProjectBrowserSource( + id: 'recipes', + label: new TranslatableMarkup('Recipes'), + description: new TranslatableMarkup('Recipes available in the local code base'), + local_task: [ + 'weight' => 2, + ] +)] final class Recipes extends ProjectBrowserSourceBase { public function __construct( diff --git a/src/Plugin/ProjectBrowserSourceManager.php b/src/Plugin/ProjectBrowserSourceManager.php index e7b10717f..96c93384d 100644 --- a/src/Plugin/ProjectBrowserSourceManager.php +++ b/src/Plugin/ProjectBrowserSourceManager.php @@ -5,6 +5,7 @@ namespace Drupal\project_browser\Plugin; use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Plugin\DefaultPluginManager; +use Drupal\project_browser\Attribute\ProjectBrowserSource; /** * Provides a Project Browser Source Manager. @@ -32,7 +33,7 @@ class ProjectBrowserSourceManager extends DefaultPluginManager { $namespaces, $module_handler, 'Drupal\project_browser\Plugin\ProjectBrowserSourceInterface', - 'Drupal\project_browser\Annotation\ProjectBrowserSource', + ProjectBrowserSource::class, ); $this->alterInfo('project_browser_source_info'); diff --git a/tests/modules/project_browser_test/src/Plugin/ProjectBrowserSource/ProjectBrowserTestMock.php b/tests/modules/project_browser_test/src/Plugin/ProjectBrowserSource/ProjectBrowserTestMock.php index 4894e234b..72a77815f 100644 --- a/tests/modules/project_browser_test/src/Plugin/ProjectBrowserSource/ProjectBrowserTestMock.php +++ b/tests/modules/project_browser_test/src/Plugin/ProjectBrowserSource/ProjectBrowserTestMock.php @@ -9,7 +9,9 @@ use Drupal\Component\Utility\Html; use Drupal\Core\Database\Connection; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\State\StateInterface; +use Drupal\Core\StringTranslation\TranslatableMarkup; use Drupal\Core\Url; +use Drupal\project_browser\Attribute\ProjectBrowserSource; use Drupal\project_browser\Plugin\ProjectBrowserSourceBase; use Drupal\project_browser\ProjectBrowser\Filter\BooleanFilter; use Drupal\project_browser\ProjectBrowser\Filter\MultipleChoiceFilter; @@ -22,16 +24,15 @@ use Symfony\Component\DependencyInjection\ContainerInterface; /** * Database driven plugin. - * - * @ProjectBrowserSource( - * id = "project_browser_test_mock", - * label = @Translation("Project Browser Mock Plugin"), - * description = @Translation("Gets project and filters information from a database"), - * local_task = { - * "title" = @Translation("Browse"), - * } - * ) */ +#[ProjectBrowserSource( + id: 'project_browser_test_mock', + label: new TranslatableMarkup('Project Browser Mock Plugin'), + description: new TranslatableMarkup('Gets project and filters information from a database'), + local_task: [ + 'title' => new TranslatableMarkup('Browse'), + ], +)] final class ProjectBrowserTestMock extends ProjectBrowserSourceBase { /** diff --git a/tests/src/Kernel/RecipesSourceTest.php b/tests/src/Kernel/RecipesSourceTest.php index cd8818901..e167d58bc 100644 --- a/tests/src/Kernel/RecipesSourceTest.php +++ b/tests/src/Kernel/RecipesSourceTest.php @@ -5,10 +5,8 @@ declare(strict_types=1); namespace Drupal\Tests\project_browser\Kernel; use Drupal\Component\FileSystem\FileSystem; -use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Recipe\Recipe; use Drupal\KernelTests\KernelTestBase; -use Drupal\project_browser\EnabledSourceHandler; use Drupal\project_browser\Plugin\ProjectBrowserSourceManager; use Drupal\project_browser\ProjectType; use Symfony\Component\Filesystem\Filesystem as SymfonyFilesystem; @@ -44,23 +42,6 @@ class RecipesSourceTest extends KernelTestBase { $this->installConfig('project_browser'); } - /** - * @covers \project_browser_install - * @covers \project_browser_project_browser_source_info_alter - */ - public function testRecipeSourceIsEnabledAtInstallTime(): void { - $this->assertNotContains('recipes', $this->config('project_browser.admin_settings')->get('enabled_sources')); - - $this->container->get(ModuleHandlerInterface::class) - ->loadInclude('project_browser', 'install'); - project_browser_install(); - $this->assertContains('recipes', $this->config('project_browser.admin_settings')->get('enabled_sources')); - - $enabled_sources = $this->container->get(EnabledSourceHandler::class) - ->getCurrentSources(); - $this->assertArrayHasKey('recipes', $enabled_sources); - } - /** * Tests that recipes are discovered by the plugin. */ -- GitLab