Allow defining injected services with PHP attributes

Created on 17 July 2022, over 2 years ago
Updated 12 July 2024, 4 months ago

That would make class boilerplate much less verbose. See examples below.

ContainerInjectionInterface

class Example implements ContainerInjectionInterface {

  public function __construct(
    protected EntityTypeManagerInterface $entityTypeManager,
    protected CronInterface $cron,
  ) {}

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container): static {
    return new static(
      $container->get('entity_type.manager'),
      $container->get('cron'),
    );
  }

}

PHP Attributes

class Example {

  #[Services('entity_type.manager', 'cron')]
  public function __construct(
    protected EntityTypeManagerInterface $entityTypeManager,
    protected CronInterface $cron,
  ) {}

}
Feature request
Status

Closed: duplicate

Version

11.0 🔥

Component
Base 

Last updated about 1 hour ago

Created by

🇷🇺Russia Chi

Live updates comments and jobs are added and updated live.
  • 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

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • The Needs Review Queue Bot tested this issue. It either no longer applies to Drupal core, or fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".

    Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.

    Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

  • 🇮🇳India pooja saraah Chennai

    Fixed failed commands on #2
    Attached patch against Drupal 10.0.x

  • Status changed to Needs review almost 2 years ago
  • Status changed to Needs work almost 2 years ago
  • 🇷🇺Russia Chi

    This still needs tests.

  • 🇬🇧United Kingdom joachim

    Should be postponed on 📌 [policy, no patch] Decide on a namespace for PHP Attribute classes Fixed .

    +++ b/core/lib/Drupal/Core/DependencyInjection/ClassResolver.php
    @@ -28,7 +29,7 @@ public function getInstanceFromDefinition($definition) {
           else {
    -        $instance = new $definition();
    +        $instance = $this->getInstanceFromAttributes($definition) ?? new $definition();
           }
    

    Since we're already in an if/else block, this would read better if it was an extra block. The current change imposes two different levels of conditions.

  • 🇦🇺Australia dpi Perth, Australia

    Can I ask why this pattern was chosen?

      #[Services('entity_type.manager', 'cron')]
        protected EntityTypeManagerInterface $entityTypeManager,
        protected CronInterface $cron,
    

    over something like in https://symfony.com/blog/new-in-symfony-6-1-service-autowiring-attributes, wherein each parameter is tagged:

    public function __construct(
       #[SomeAttr(service: 'some_service')]
        protected EntityTypeManagerInterface $entityTypeManager,
       #[SomeAttr(service: 'some_service')]
        protected CronInterface $cron,
    )
    

    It seems like the latter option would be better for refactoring, make git diffs less disruptive.

  • 🇬🇧United Kingdom joachim

    +1 to #8 -- clear git diffs and simpler refactoring are both important.

    I've just thought of a BIG DX enhancement this change would bring. At the moment it's a PITA to find the service name for a class if I am looking at a class where the service is injected. With a module it's not TOO bad -- I have to go look in MODULE.services.yml. But with core components, I have to dig up core.services.yml, find the class name in that HUGE file.

    This proposal would mean I can see the service name in the class constructor -- easy!

    (Changing title to make this easier to find.)

  • 🇩🇪Germany geek-merlin Freiburg, Germany

    #8: Great reference! +1 for adopting the pattern.

    Moreover, let's not invent another drupalism, but adopt that very attribute including its namespace.

  • 🇦🇺Australia dpi Perth, Australia

    title typo

  • 🇬🇧United Kingdom longwave UK

    This appears to be a duplicate of 📌 Allow plugin service wiring via constructor parameter attributes Needs work . Over there I propose using the Symfony #[Autowire] attribute syntax to replace the plugin factory method.

  • Status changed to Needs review over 1 year ago
  • Open in Jenkins → Open on Drupal.org →
    Environment: PHP 8.1 & MySQL 5.7
    last update over 1 year ago
    29,366 pass
  • 🇬🇧United Kingdom longwave UK

    It turns out we can start using the Symfony #[Autowire] attribute already, see a single example in the attached patch.

    I propose closing this as a duplicate of 📌 Use autowiring for core modules and services Needs work where I want to make this change across all of core.

  • Status changed to Postponed over 1 year ago
  • 🇩🇪Germany geek-merlin Freiburg, Germany

    #13: Great plan and totally makes sense. Sounds like postponing on the other though.
    Making it so.

  • 🇯🇵Japan tyler36 Osaka

    This seems like a great way to reduce boilerplate and help IDEs help us.

    +1 #13 to follow #[Autowire] pattern
    +1 #8 to tagging each parameter

  • Status changed to Closed: duplicate 4 months ago
  • 🇩🇪Germany geek-merlin Freiburg, Germany

    See #13, we have paramter level #[Autowire].

Production build 0.71.5 2024