Как управлять общими зависимостями с родительскими сервисами
Дата обновления перевода 2024-07-27
Как управлять общими зависимостями с родительскими сервисами
По мере добавление функционала в ваше приложение, вы также можете заиметь
родственные классы, которые имеют некоторые общие зависимости. Например,
вы можете иметь несколько классов хранилища, которым нужен сервис
doctrine.entity_manager
и необязательный сервис logger
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
// src/Repository/BaseDoctrineRepository.php
namespace App\Repository;
use Doctrine\ORM\EntityManager;
use Psr\Log\LoggerInterface;
// ...
abstract class BaseDoctrineRepository
{
protected LoggerInterface $logger;
public function __construct(
protected EntityManager $entityManager,
) {
}
public function setLogger(LoggerInterface $logger): void
{
$this->logger = $logger;
}
// ...
}
Классы вашего дочернего сервиса могут выглядеть так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
// src/Repository/DoctrineUserRepository.php
namespace App\Repository;
use App\Repository\BaseDoctrineRepository;
// ...
class DoctrineUserRepository extends BaseDoctrineRepository
{
// ...
}
// src/Repository/DoctrinePostRepository.php
namespace App\Repository;
use App\Repository\BaseDoctrineRepository;
// ...
class DoctrinePostRepository extends BaseDoctrineRepository
{
// ...
}
Сервис-контейнер позволяет вам расширять родительские сервисы, чтобы избежать дублирования определений сервисов:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
# config/services.yaml
services:
App\Repository\BaseDoctrineRepository:
abstract: true
arguments: ['@doctrine.orm.entity_manager']
calls:
- setLogger: ['@logger']
App\Repository\DoctrineUserRepository:
# расширяет сервис App\Repository\BaseDoctrineRepository
parent: App\Repository\BaseDoctrineRepository
App\Repository\DoctrinePostRepository:
parent: App\Repository\BaseDoctrineRepository
# ...
В этом контексте, наличие сервиса parent
предполагает, что аргументы и
вызовы метода родительского сервиса должны быть использованы для дочерних
сервисов. В особенности, EntityManager
будет внедрён, а setLogger()
будет вызван, когда будет инстанциирован AppBundle\Repository\DoctrineUserRepository
.
Все атрибуты родительского сервиса являются общими с дочерним, кроме
shared
, abstract
и tags
. Они не наследуются от родителя.
Tip
В показанных примерах, класс, которые имеют общую конфигурацию, ткакже расширяются из одного родительского класса в PHP. Это вовсе не обязательно. Вы можете просто извлечь общие части схожих определений сервиса в родительский сервис, не расширяя также родительский класс в PHP.
Переопределение родительских зависимостей
Могут быть времена, когда вы захотите переопределить то, какой сервис внедряется только для одного из дочерних сервисов. Вы можете пеоепределить болошиниство настроек просто указав их в дочернем классе:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
# config/services.yaml
services:
# ...
App\Repository\DoctrineUserRepository:
parent: App\Repository\BaseDoctrineRepository
# переопределяет публичную настройку родительского сервиса
public: false
# добавляет аргумент '@app.username_checker' к родительскому
# списку аргументов
arguments: ['@app.username_checker']
App\Repository\DoctrinePostRepository:
parent: App\Repository\BaseDoctrineRepository
# переопределяет первый аргумент (используя специальный ключ index_N)
arguments:
index_0: '@doctrine.custom_entity_manager'