From 5a8749ad556175d417285aa7393189a3c74db525 Mon Sep 17 00:00:00 2001
From: Michael Strelan <28650-mstrelan@users.noreply.drupalcode.org>
Date: Tue, 5 Nov 2024 08:35:34 +0000
Subject: [PATCH] Issue #3425292 by mstrelan, dpi: Use attributes for
 DateRecurInterpreter plugin discovery

---
 src/Attribute/DateRecurInterpreter.php        | 36 +++++++++++++++++++
 .../DateRecurInterpreter/RlInterpreter.php    | 10 +++---
 src/Plugin/DateRecurInterpreterManager.php    |  2 ++
 .../Functional/DateRecurBasicWidgetTest.php   | 31 +++++++---------
 4 files changed, 56 insertions(+), 23 deletions(-)
 create mode 100644 src/Attribute/DateRecurInterpreter.php

diff --git a/src/Attribute/DateRecurInterpreter.php b/src/Attribute/DateRecurInterpreter.php
new file mode 100644
index 0000000..780e40d
--- /dev/null
+++ b/src/Attribute/DateRecurInterpreter.php
@@ -0,0 +1,36 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\date_recur\Attribute;
+
+use Drupal\Component\Plugin\Attribute\Plugin;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+
+/**
+ * Attribute for defining an interpreter for Recurring date field.
+ *
+ * @see plugin_api
+ */
+#[\Attribute(\Attribute::TARGET_CLASS)]
+final class DateRecurInterpreter extends Plugin {
+
+  private const USE_NAMED_PARAMETERS = 'Using this attribute without named parameters is not supported.';
+
+  /**
+   * @phpstan-param class-string<\Drupal\Component\Plugin\Derivative\DeriverInterface>|null $deriver
+   */
+  public function __construct(
+    string $id,
+    public readonly TranslatableMarkup $label,
+    ?string $useNamedParameters = self::USE_NAMED_PARAMETERS,
+    ?string $deriver = NULL,
+  ) {
+    parent::__construct($id, $deriver);
+
+    if (self::USE_NAMED_PARAMETERS !== $useNamedParameters) {
+      throw new \LogicException(self::USE_NAMED_PARAMETERS);
+    }
+  }
+
+}
diff --git a/src/Plugin/DateRecurInterpreter/RlInterpreter.php b/src/Plugin/DateRecurInterpreter/RlInterpreter.php
index b061384..5e8bc43 100644
--- a/src/Plugin/DateRecurInterpreter/RlInterpreter.php
+++ b/src/Plugin/DateRecurInterpreter/RlInterpreter.php
@@ -13,6 +13,7 @@ use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Plugin\PluginFormInterface;
 use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\date_recur\Attribute\DateRecurInterpreter;
 use Drupal\date_recur\Plugin\DateRecurInterpreterPluginBase;
 use RRule\RRule;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -20,14 +21,13 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
 /**
  * Provides an interpreter implemented by rlanvin/php-rrule.
  *
- * @DateRecurInterpreter(
- *  id = "rl",
- *  label = @Translation("RL interpreter"),
- * )
- *
  * @ingroup RLanvinPhpRrule
  * @phpstan-property array{show_start_date: bool, show_until: bool, date_format: string, show_infinite: bool} $configuration
  */
+#[DateRecurInterpreter(
+  id: 'rl',
+  label: new TranslatableMarkup('RL interpreter'),
+)]
 class RlInterpreter extends DateRecurInterpreterPluginBase implements ContainerFactoryPluginInterface, PluginFormInterface {
 
   use DependencyTrait;
diff --git a/src/Plugin/DateRecurInterpreterManager.php b/src/Plugin/DateRecurInterpreterManager.php
index c587bd5..f2d8a6d 100644
--- a/src/Plugin/DateRecurInterpreterManager.php
+++ b/src/Plugin/DateRecurInterpreterManager.php
@@ -7,6 +7,7 @@ namespace Drupal\date_recur\Plugin;
 use Drupal\Core\Cache\CacheBackendInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Plugin\DefaultPluginManager;
+use Drupal\date_recur\Attribute\DateRecurInterpreter;
 
 //@codingStandardsIgnoreStart
 /**
@@ -26,6 +27,7 @@ class DateRecurInterpreterManager extends DefaultPluginManager implements DateRe
       $namespaces,
       $module_handler,
       'Drupal\date_recur\Plugin\DateRecurInterpreterPluginInterface',
+      DateRecurInterpreter::class,
       'Drupal\date_recur\Annotation\DateRecurInterpreter',
     );
     $this->setCacheBackend($cache_backend, 'date_recur_interpreter_info', ['config:date_recur_interpreter_list']);
diff --git a/tests/src/Functional/DateRecurBasicWidgetTest.php b/tests/src/Functional/DateRecurBasicWidgetTest.php
index 7b3399f..76f55a6 100644
--- a/tests/src/Functional/DateRecurBasicWidgetTest.php
+++ b/tests/src/Functional/DateRecurBasicWidgetTest.php
@@ -173,13 +173,10 @@ final class DateRecurBasicWidgetTest extends BrowserTestBase {
   /**
    * Data provider for testFields.
    *
-   * @return array
-   *   Data for testing.
+   * @phpstan-return \Generator<array{0: array<mixed>, 1: bool, 2?: string|null}>
    */
-  public function providerFields(): array {
-    $scenarios = [];
-
-    $scenarios['Test no failures if nothing is filled.'] = [
+  public static function providerFields(): \Generator {
+    yield 'Test no failures if nothing is filled.' => [
       [
         'dr[0][value][date]' => '',
         'dr[0][value][time]' => '',
@@ -191,7 +188,7 @@ final class DateRecurBasicWidgetTest extends BrowserTestBase {
       TRUE,
     ];
 
-    $scenarios['Test failure when only start date field filled.'] = [
+    yield 'Test failure when only start date field filled.' => [
       [
         'dr[0][value][date]' => '2008-06-17',
         'dr[0][value][time]' => '',
@@ -204,7 +201,7 @@ final class DateRecurBasicWidgetTest extends BrowserTestBase {
       'Missing time zone for date.',
     ];
 
-    $scenarios['Test failure when only start time field filled.'] = [
+    yield 'Test failure when only start time field filled.' => [
       [
         'dr[0][value][date]' => '',
         'dr[0][value][time]' => '10:00:00',
@@ -217,7 +214,7 @@ final class DateRecurBasicWidgetTest extends BrowserTestBase {
       'Missing time zone for date.',
     ];
 
-    $scenarios['Test failure when start date and time field filled.'] = [
+    yield 'Test failure when start date and time field filled.' => [
       [
         'dr[0][value][date]' => '2008-06-17',
         'dr[0][value][time]' => '10:00:00',
@@ -230,7 +227,7 @@ final class DateRecurBasicWidgetTest extends BrowserTestBase {
       'Missing time zone for date.',
     ];
 
-    $scenarios['Test failure when end date filled.'] = [
+    yield 'Test failure when end date filled.' => [
       [
         'dr[0][value][date]' => '',
         'dr[0][value][time]' => '',
@@ -243,7 +240,7 @@ final class DateRecurBasicWidgetTest extends BrowserTestBase {
       'Missing time zone for date.',
     ];
 
-    $scenarios['Test failure when end time filled.'] = [
+    yield 'Test failure when end time filled.' => [
       [
         'dr[0][value][date]' => '',
         'dr[0][value][time]' => '',
@@ -256,7 +253,7 @@ final class DateRecurBasicWidgetTest extends BrowserTestBase {
       'Missing time zone for date.',
     ];
 
-    $scenarios['Test success when start date and time and time zone field filled.'] = [
+    yield 'Test success when start date and time and time zone field filled.' => [
       [
         'dr[0][value][date]' => '2008-06-17',
         'dr[0][value][time]' => '10:00:00',
@@ -268,7 +265,7 @@ final class DateRecurBasicWidgetTest extends BrowserTestBase {
       TRUE,
     ];
 
-    $scenarios['Test failure when end date and time and time zone field filled.'] = [
+    yield 'Test failure when end date and time and time zone field filled.' => [
       [
         'dr[0][value][date]' => '',
         'dr[0][value][time]' => '',
@@ -281,14 +278,14 @@ final class DateRecurBasicWidgetTest extends BrowserTestBase {
       'Start date must be set if end date is set.',
     ];
 
-    $scenarios['Tests failure on invalid rule.'] = [
+    yield 'Tests failure on invalid rule.' => [
       [
         'dr[0][value][date]' => '2008-06-17',
         'dr[0][value][time]' => '12:00:00',
         'dr[0][end_value][date]' => '2008-06-17',
         'dr[0][end_value][time]' => '12:00:00',
         'dr[0][timezone]' => 'America/Chicago',
-        'dr[0][rrule]' => $this->randomMachineName(),
+        'dr[0][rrule]' => '123FAKE_RRULE321',
       ],
       FALSE,
       'Repeat rule is formatted incorrectly.',
@@ -296,7 +293,7 @@ final class DateRecurBasicWidgetTest extends BrowserTestBase {
 
     // Tests validation that comes automatically from date range. Specifically,
     // assert end date comes on or after start date.
-    $scenarios['Tests inherited validation: end before start'] = [
+    yield 'Tests inherited validation: end before start' => [
       [
         'dr[0][value][date]' => '2008-06-17',
         'dr[0][value][time]' => '03:00:00',
@@ -308,8 +305,6 @@ final class DateRecurBasicWidgetTest extends BrowserTestBase {
       FALSE,
       'end date cannot be before the start date',
     ];
-
-    return $scenarios;
   }
 
   /**
-- 
GitLab