Как управлять общими зависимостями с родительскими сервисами

Как управлять общими зависимостями с родительскими сервисами

По мере добавление функционала в ваше приложение, вы также можете заиметь родственные классы, которые имеют некоторые общие зависимости. Например, вы можете иметь несколько классов хранилища, которым нужен сервис 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
// src/AppBundle/Repository/BaseDoctrineRepository.php
namespace AppBundle\Repository;

// ...
abstract class BaseDoctrineRepository
{
    protected $entityManager;
    protected $logger;

    public function __construct(EntityManagerInterface $manager)
    {
        $this->entityManager = $manager;
    }

    public function setLogger(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }

    // ...
}

Так же, как вы используете наследование PHP, чтобы избежать дубликатов в вашем PHP-коде, сервис-контейнер позволяет вам расширить родительские сервисы, чтобы избежать дубликатов определений сервиса:

  • YAML
  • XML
  • PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
services:
    AppBundle\Repository\BaseDoctrineRepository:
        abstract:  true
        arguments: ['@doctrine.entity_manager']
        calls:
            - [setLogger, ['@logger']]

    AppBundle\Repository\DoctrineUserRepository:
        # расширить сервис AppBundle\Repository\BaseDoctrineRepository
        parent: AppBundle\Repository\BaseDoctrineRepository

    AppBundle\Repository\DoctrinePostRepository:
        parent: AppBundle\Repository\BaseDoctrineRepository

    # ...

В этом контексте, наличие сервиса parent предполагает, что аргументы и вызовы метода родительского сервиса должны быть использованы для дочерних сервисов. В особенности, EntityManager будет внедрён, а setLogger() будет вызван, когда будет инстанциирован AppBundle\Repository\DoctrineUserRepository.

Все атрибуты родительского сервиса являются общими с дочерним, кроме shared, abstract и tags. Они не наследуются от родителя.

Note

Если у вас есть раздел _defaults в вашем файле, все дочерние сервисы должны ясно переопределять эти значения, чтобы избежать двусмысленности. Вы увидите чёткое сообщение ошибки об этом.

Tip

В показанных примерах, класс, которые имеют общую конфигурацию, ткакже расширяются из одного родительского класса в PHP. Это вовсе не обязательно. Вы можете просто извлечь общие части схожих определений сервиса в родительский сервис, не расширяя также родительский класс в PHP.

Переопределение родительских зависимостей

Могут быть времена, когда вы захотите переопределить то, какой сервис внедряется только для одного из дочерних сервисов. Вы можете пеоепределить болошиниство настроек просто указав их в дочернем классе:

  • YAML
  • XML
  • PHP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
services:
    # ...

    AppBundle\Repository\DoctrineUserRepository:
        parent: AppBundle\Repository\BaseDoctrineRepository

        # переопределяет публичную настройку родительского сервиса
        public: false

        # добавляет аргумент '@app.username_checker' к родительскому
        # списку аргументов
        arguments: ['@app.username_checker']

    AppBundle\Repository\DoctrinePostRepository:
        parent: AppBundle\Repository\BaseDoctrineRepository

        # переопределяет первый аргумент (используя специальный ключ index_N)
        arguments:
            index_0: '@doctrine.custom_entity_manager'