AttributeClassDiscovery should throw an exception if it finds more than one plugin type annotation

Created on 16 April 2024, 10 months ago
Updated 7 August 2024, 6 months ago

Problem/Motivation

AttributeClassDiscovery does this:

    if ($attributes = $reflection_class->getAttributes($this->pluginDefinitionAttributeName, \ReflectionAttribute::IS_INSTANCEOF)) {
      /** @var \Drupal\Component\Plugin\Attribute\AttributeInterface $attribute */
      $attribute = $attributes[0]->newInstance();

Our plugin attributes aren't marked as repeatable, so there can be only one Drupal\Core\Action\Attribute\Action attribute on an action plugin, for example. But we're passing the ReflectionAttribute::IS_INSTANCEOF parameter, which allows subclasses.

So, a developer could mistakenly write:


#[Action()]
#[ActionSubclass()]
class myActionPlugin {
}

Steps to reproduce

Proposed resolution

Throw an InvalidPluginDefinitionException if $attributes is > 1.

Remaining tasks

User interface changes

API changes

Data model changes

Release notes snippet

๐Ÿ“Œ Task
Status

Needs work

Version

11.0 ๐Ÿ”ฅ

Component
Pluginย  โ†’

Last updated 1 day ago

Created by

๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom joachim

Live updates comments and jobs are added and updated live.
  • Novice

    It would make a good project for someone who is new to the Drupal contribution process. It's preferred over Newbie.

  • Needs tests

    The change is currently missing an automated test that fails when run with the original code, and succeeds when the bug has been fixed.

Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @joachim
  • First commit to issue fork.
  • ๐Ÿ‡ฎ๐Ÿ‡ณIndia Sandeep Sanwale

    Sandeep Sanwale โ†’ made their first commit to this issueโ€™s fork.

  • Pipeline finished with Failed
    9 months ago
    Total: 1116s
    #159383
  • Status changed to RTBC 9 months ago
  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom joachim

    Thanks for the MR.

    LGTM!

  • Pipeline finished with Failed
    9 months ago
    #159444
  • ๐Ÿ‡ฎ๐Ÿ‡ณIndia Sandeep Sanwale

    updated the docblock for InvalidPluginDefinitionException .

  • Status changed to Needs work 9 months ago
  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom alexpott ๐Ÿ‡ช๐Ÿ‡บ๐ŸŒ

    What is the impact of having more than one attribute? What actually breaks?

  • Pipeline finished with Failed
    9 months ago
    Total: 258s
    #159513
  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom joachim

    > What is the impact of having more than one attribute? What actually breaks?

    Nothing breaks, but only the first attribute is read:

        if ($attributes = $reflection_class->getAttributes($this->pluginDefinitionAttributeName, \ReflectionAttribute::IS_INSTANCEOF)) {
          /** @var \Drupal\Component\Plugin\Attribute\AttributeInterface $attribute */
          $attribute = $attributes[0]->newInstance();
    

    This change is just for DX, so developers understand why the code they've added does nothing.

  • ๐Ÿ‡บ๐Ÿ‡ธUnited States xjm

    This is also failing static analysis:

     ------ ------------------------------------------------------------------------ 
      Line   core/lib/Drupal/Component/Plugin/Discovery/AttributeClassDiscovery.php  
     ------ ------------------------------------------------------------------------ 
      131    Instantiated class                                                      
             Drupal\Component\Plugin\Discovery\InvalidPluginDefinitionException      
             not found.                                                              
             ๐Ÿ’ก Learn more at https://phpstan.org/user-guide/discovering-symbols     
     ------ ------------------------------------------------------------------------ 
  • ๐Ÿ‡บ๐Ÿ‡ธUnited States xjm

    Both adding test coverage for the expected exception and fixing #10 could be good novice contributor tasks.

  • ๐Ÿ‡ฌ๐Ÿ‡งUnited Kingdom joachim

    Fixed the missing class.

    Not sure what to do about tests, as the current MR is actually causing AttributeClassDiscoveryTest::testGetDefinitions() to fail, because it's doing **PRECISELY** what this MR sets out to prevent from happening!

    The problem is that we have:

    class CustomPlugin extends Plugin {
    

    and

    #[Plugin(
      id: "discovery_test_1",
    )]
    #[CustomPlugin(
      id: "discovery_test_1",
      title: "Discovery test plugin"
    )]
    class AttributeDiscoveryTest1 {}
    

    Some git digging is required to understand what that test is trying to test and why it was set up that way. Is it specifically trying to test a class with two different attributes (and why??)? Or was that just a space-saving shortcut which we can change?

  • Pipeline finished with Failed
    6 months ago
    Total: 554s
    #246982
Production build 0.71.5 2024