Change record status: 
Project: 
Introduced in branch: 
11.4.x
Introduced in version: 
11.4.0
Description: 

Classes using AutowireTrait or AutowiredInstanceTrait can now inject dependencies via setter methods marked with Symfony's #[Required] attribute, eliminating the need to override constructors in subclasses. This includes controllers that extend \Drupal\Core\Controller\ControllerBase and plugins that extend \Drupal\Core\Plugin\PluginBase.

For example, if there is a base plugin class like this:

abstract class ExamplePluginBase extends PluginBase {

  public function __construct(
    protected readonly Service1Interface $service1,
    protected readonly Service2Interface $service2,
    protected readonly Service3Interface $service3,
  ) {}
  ...
}

a plugin class extending ExamplePluginBase would previously need to inject additional services by appending parameters to the constructor:

class ExamplePlugin1 extends ExamplePluginBase {

  public function __construct(
    Service1Interface $service1,
    Service2Interface $service2,
    Service3Interface $service3,
    protected readonly SubclassOnlyServiceInterface $subclassOnlyService,
  ) {
    parent::__construct($service1, $service2, $service3);
  }
  ...
}

Now the plugin can do this instead:

use Symfony\Contracts\Service\Attribute\Required;

class ExamplePlugin1 extends ExamplePluginBase {

  protected SubclassOnlyServiceInterface $subclassOnlyService;

  #[Required]
  public function setSubclassOnlyService(SubclassOnlyServiceInterface $subclassOnlyService): void {
    $this->subclassOnlyService = $subclassOnlyService
  }
  ...
}

The trait will ensure that all #[Required] functions are called automatically when the controller or plugin is instantiated.

Services in the setter function are resolved by typehint or the #[Autowire] attribute, in the same way as the constructor.

Impacts: 
Module developers