В Drupal 11 три способа внедрения зависимостей в контроллер:
1. Классический, с помощью метода create()
class ExampleController implements ContainerInjectionInterface {
public function __construct(
protected EntityTypeManagerInterface $entityTypeManager,
protected MessengerInterface $messenger,
) {}
public static function create(ContainerInterface $container): static {
return new static(
$container->get(EntityTypeManagerInterface::class),
$container->get(MessengerInterface::class),
);
}
}
Минусы — необходимость реализации метода ContainerInjectionInterface::create().
Плюсы — работает в Drupal 8+.
2. Новый, с помощью AutowireTrait
use Drupal\Core\DependencyInjection\AutowireTrait;
class ExampleController implements ContainerInjectionInterface {
use AutowireTrait;
public function __construct(
#[Autowire(service: EntityTypeManagerInterface::class)]
protected EntityTypeManagerInterface $entityTypeManager,
#[Autowire(service: MessengerInterface::class)]
protected MessengerInterface $messenger,
) {}
}
Если имя сервиса совпадает с именем класса или у сервиса есть соответствующий синоним, то #[Autowire(...)] можно опустить:
use Drupal\Core\DependencyInjection\AutowireTrait;
class ExampleController implements ContainerInjectionInterface {
use AutowireTrait;
public function __construct(
protected EntityTypeManagerInterface $entityTypeManager,
protected MessengerInterface $messenger,
) {}
}
Минусы — рефлексия в рантайме, урезанный autowire (например нельзя сделать так #[Autowire(param: 'app.root')).
3. Symfony-way, с помощью регистрации контроллера в качестве сервиса
// src/Controller/ExampleController.php
class ExampleController {
public function __construct(
protected EntityTypeManagerInterface $entityTypeManager,
protected MessengerInterface $messenger,
) {}
}# MODULENAME.services.yml
services:
_defaults:
autowire: true
# Without leading slash
Drupal\MODULENAME\Controller\ExampleController: ~Плюсы — полноценный autowire.
Важное замечание — в MODULENAME.routing.yml, как и в MODULENAME.services.yml, путь к контроллеру не должен содержать начальный слэш:
MODULENAME.my_page:
path: '/my-page'
defaults:
_title: 'My page'
# Without leading slash
_controller: Drupal\MODULENAME\Controller\ExampleController
requirements:
_access: 'TRUE'
Подробнее про autowire:
— AutowireTrait allows ContainerInjectionInterface classes to be autowired
— Services can be autowired
— Defining Services Dependencies Automatically (Autowiring)
- FAQ по тестированию
- Выдача CSV файла по мере генерации
- Производительность EntityStorageInterface::load() vs EntityStorageInterface::loadMultiple()
- Производительность Entity Query vs Query Builder vs Sql query
- Отличие методов BaseFieldDefinition::setDefaultValue() и BaseFieldDefinition::setInitialValue()
Комментарии
> Минусы — рефлексия в рантайме, урезанный autowire (например нельзя сделать так #[Autowire(param: 'app.root')).
В чистом виде Symfony сохраняет собранный контейнер в кеш и никакой рефлексии в рантайме нету. Аттрибут #[Autowire] судя по названию, это атрибут симфони, а значит никакой рефлексии в рантайме быть не должно, или в Drupal это работает иначе?
Контейнер к контроллерам никакого отношения не имеет. См
\Drupal\Core\DependencyInjection\AutowireTrait::create()Добавить комментарий