Skip to content

Commit

Permalink
Merge pull request #122 from chesn0k/plugin-discovery-attribute
Browse files Browse the repository at this point in the history
Plugin manager using attributes for plugins
  • Loading branch information
Chi-teck authored Jan 9, 2024
2 parents 089d2e9 + 362033b commit 896eb3a
Show file tree
Hide file tree
Showing 14 changed files with 285 additions and 6 deletions.
7 changes: 7 additions & 0 deletions src/Command/PluginManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ protected function generate(array &$vars, Assets $assets): void {

$discovery_types = [
'annotation' => 'Annotation',
'attribute' => 'Attribute',
'yaml' => 'YAML',
'hook' => 'Hook',
];
Expand All @@ -53,6 +54,12 @@ protected function generate(array &$vars, Assets $assets): void {
$assets->addFile('src/Plugin/{class_prefix}/Foo.php', 'annotation/src/Plugin/Example/Foo.php.twig');
break;

case 'attribute':
$assets->addFile('src/Attribute/{class_prefix}.php', 'attribute/src/Attribute/Example.php.twig');
$assets->addFile('src/{class_prefix}PluginBase.php', 'attribute/src/ExamplePluginBase.php.twig');
$assets->addFile('src/Plugin/{class_prefix}/Foo.php', 'attribute/src/Plugin/Example/Foo.php.twig');
break;

case 'yaml':
$assets->addFile('{machine_name}.{plugin_type|pluralize}.yml', 'yaml/model.examples.yml.twig');
$assets->addFile('src/{class_prefix}Default.php', 'yaml/src/ExampleDefault.php.twig');
Expand Down
4 changes: 4 additions & 0 deletions templates/_plugin-manager/attribute/model.services.yml.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
services:
plugin.manager.{{ plugin_type }}:
class: Drupal\{{ machine_name }}\{{ class_prefix }}PluginManager
parent: default_plugin_manager
23 changes: 23 additions & 0 deletions templates/_plugin-manager/attribute/src/Attribute/Example.php.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php declare(strict_types = 1);

namespace Drupal\{{ machine_name }}\Attribute;

use Drupal\Component\Plugin\Attribute\AttributeBase;
use Drupal\Core\StringTranslation\TranslatableMarkup;

/**
* The {{ plugin_type }} attribute.
*/
#[\Attribute(\Attribute::TARGET_CLASS)]
final class {{ class_prefix }} extends AttributeBase {

/**
* Constructs a new {{ class_prefix }} instance.
*/
public function __construct(
public readonly string $id,
public readonly ?TranslatableMarkup $label,
public readonly ?TranslatableMarkup $description = NULL,
) {}

}
15 changes: 15 additions & 0 deletions templates/_plugin-manager/attribute/src/ExampleInterface.php.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php declare(strict_types = 1);

namespace Drupal\{{ machine_name }};

/**
* Interface for {{ plugin_type }} plugins.
*/
interface {{ class_prefix }}Interface {

/**
* Returns the translated plugin label.
*/
public function label(): string;

}
20 changes: 20 additions & 0 deletions templates/_plugin-manager/attribute/src/ExamplePluginBase.php.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php declare(strict_types = 1);

namespace Drupal\{{ machine_name }};

use Drupal\Component\Plugin\PluginBase;

/**
* Base class for {{ plugin_type }} plugins.
*/
abstract class {{ class_prefix }}PluginBase extends PluginBase implements {{ class_prefix }}Interface {

/**
* {@inheritdoc}
*/
public function label(): string {
// Cast the label to a string since it is a TranslatableMarkup object.
return (string) $this->pluginDefinition['label'];
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php declare(strict_types = 1);

namespace Drupal\{{ machine_name }};

{% sort %}
use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Plugin\DefaultPluginManager;
use Drupal\{{ machine_name }}\Attribute\{{ class_prefix }};
{% endsort %}

/**
* {{ class_prefix }} plugin manager.
*/
final class {{ class_prefix }}PluginManager extends DefaultPluginManager {

/**
* Constructs the object.
*/
public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
parent::__construct('Plugin/{{ class_prefix }}', $namespaces, $module_handler, {{ class_prefix }}Interface::class, {{ class_prefix }}::class);
$this->alterInfo('{{ plugin_type }}_info');
$this->setCacheBackend($cache_backend, '{{ plugin_type }}_plugins');
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php declare(strict_types = 1);

namespace Drupal\{{ machine_name }}\Plugin\{{ class_prefix }};

{% sort %}
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\{{ machine_name }}\Attribute\{{ class_prefix }};
use Drupal\{{ machine_name }}\{{ class_prefix }}PluginBase;
{% endsort %}

/**
* Plugin implementation of the {{ plugin_type }}.
*/
#[{{ class_prefix }}(
id: "foo",
label: new TranslatableMarkup("Foo"),
description: new TranslatableMarkup("Foo description."),
)]
final class Foo extends {{ class_prefix }}PluginBase {

}
70 changes: 64 additions & 6 deletions tests/functional/Generator/PluginManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,9 @@ public function testAnnotationDiscovery(): void {
Discovery type [Annotation]:
[1] Annotation
[2] YAML
[3] Hook
[2] Attribute
[3] YAML
[4] Hook
The following directories and files have been created or updated:
Expand All @@ -66,6 +67,61 @@ public function testAnnotationDiscovery(): void {
$this->assertGeneratedFile('src/Plugin/Bar/Foo.php');
}

/**
* Test callback.
*/
public function testAttributeDiscovery(): void {
$input = [
'foo',
'Foo',
'bar',
'Attribute',
];
$this->execute(PluginManager::class, $input);

$expected_display = <<< 'TXT'
Welcome to plugin-manager generator!
––––––––––––––––––––––––––––––––––––––
Module machine name:
Module name [Foo]:
Plugin type [foo]:
Discovery type [Annotation]:
[1] Annotation
[2] Attribute
[3] YAML
[4] Hook
The following directories and files have been created or updated:
–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
• foo.info.yml
• foo.services.yml
• src/BarInterface.php
• src/BarPluginBase.php
• src/BarPluginManager.php
• src/Attribute/Bar.php
• src/Plugin/Bar/Foo.php

TXT;
$this->assertDisplay($expected_display);

$this->fixtureDir .= '/_attribute';
$this->assertGeneratedFile('foo.services.yml');
$this->assertGeneratedFile('src/BarInterface.php');
$this->assertGeneratedFile('src/BarPluginBase.php');
$this->assertGeneratedFile('src/BarPluginManager.php');
$this->assertGeneratedFile('src/Attribute/Bar.php');
$this->assertGeneratedFile('src/Plugin/Bar/Foo.php');
}

/**
* Test callback.
*/
Expand Down Expand Up @@ -94,8 +150,9 @@ public function testYamlDiscovery(): void {
Discovery type [Annotation]:
[1] Annotation
[2] YAML
[3] Hook
[2] Attribute
[3] YAML
[4] Hook
The following directories and files have been created or updated:
Expand Down Expand Up @@ -146,8 +203,9 @@ public function testHookDiscovery(): void {
Discovery type [Annotation]:
[1] Annotation
[2] YAML
[3] Hook
[2] Attribute
[3] YAML
[4] Hook
The following directories and files have been created or updated:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
services:
plugin.manager.bar:
class: Drupal\foo\BarPluginManager
parent: default_plugin_manager
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php declare(strict_types = 1);

namespace Drupal\foo\Attribute;

use Drupal\Component\Plugin\Attribute\AttributeBase;
use Drupal\Core\StringTranslation\TranslatableMarkup;

/**
* The bar attribute.
*/
#[\Attribute(\Attribute::TARGET_CLASS)]
final class Bar extends AttributeBase {

/**
* Constructs a new Bar instance.
*/
public function __construct(
public readonly string $id,
public readonly ?TranslatableMarkup $label,
public readonly ?TranslatableMarkup $description = NULL,
) {}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php declare(strict_types = 1);

namespace Drupal\foo;

/**
* Interface for bar plugins.
*/
interface BarInterface {

/**
* Returns the translated plugin label.
*/
public function label(): string;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php declare(strict_types = 1);

namespace Drupal\foo;

use Drupal\Component\Plugin\PluginBase;

/**
* Base class for bar plugins.
*/
abstract class BarPluginBase extends PluginBase implements BarInterface {

/**
* {@inheritdoc}
*/
public function label(): string {
// Cast the label to a string since it is a TranslatableMarkup object.
return (string) $this->pluginDefinition['label'];
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php declare(strict_types = 1);

namespace Drupal\foo;

use Drupal\Core\Cache\CacheBackendInterface;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\Core\Plugin\DefaultPluginManager;
use Drupal\foo\Attribute\Bar;

/**
* Bar plugin manager.
*/
final class BarPluginManager extends DefaultPluginManager {

/**
* Constructs the object.
*/
public function __construct(\Traversable $namespaces, CacheBackendInterface $cache_backend, ModuleHandlerInterface $module_handler) {
parent::__construct('Plugin/Bar', $namespaces, $module_handler, BarInterface::class, Bar::class);
$this->alterInfo('bar_info');
$this->setCacheBackend($cache_backend, 'bar_plugins');
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php declare(strict_types = 1);

namespace Drupal\foo\Plugin\Bar;

use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\foo\Attribute\Bar;
use Drupal\foo\BarPluginBase;

/**
* Plugin implementation of the bar.
*/
#[Bar(
id: "foo",
label: new TranslatableMarkup("Foo"),
description: new TranslatableMarkup("Foo description."),
)]
final class Foo extends BarPluginBase {

}

0 comments on commit 896eb3a

Please sign in to comment.