Як спростити конфігурацію декількох пакетів
Дата оновлення перекладу 2022-12-11
Як спростити конфігурацію декількох пакетів
При побудові повторно використовуваних та розширюваних додатків, розробники часто стикаються з вибором: або створити один великий пакет, або декілька менших пакетів. Створення одного пакета має недолік у вигляді неможливості вибору користувачами видалення невикористовуваної функції. Створення декількох пакетів має недолік у вигляді втмвлююче довгої конфігурації та необхідності повторення налаштувань для різних пакетів.
Існує можливість видалити недолік підходу декількох пакетів, додавши одне розширення,
яке додавало б на початку налаштувань будь-якого пакета деяку інформацію. Воно може
використовувати налаштування, визначені у файлах config/*
, щоб додавати до налаштувань
інформацію так само, як якби вона була чітко написана користувачем у конфігурації додатку.
Наприклад, це може бути використано для конфігурації імені менеджера сутностей для використання у декількох пакетах. Або для включення обовʼязкової іункції, яка залежить від іншого завантажуваного пакета.
Для того, щоб надати розширенню можливість робити це, воно має реалізовувати PrependExtensionInterface:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// src/Acme/HelloBundle/DependencyInjection/AcmeHelloExtension.php
namespace Acme\HelloBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
class AcmeHelloExtension extends Extension implements PrependExtensionInterface
{
// ...
public function prepend(ContainerBuilder $container)
{
// ...
}
}
Всередині методу prepend(),
розробники мають повний доступ до екземпляру ContainerBuilder
прямо перед викликом методу load()
в кожному із зареєсстрованих розширень пакета. Для того, щоб додати спочатку налаштування
до пакета, розробники розширень можуть використати метод
prependExtensionConfig()
в екземплярі ContainerBuilder. Так як
цей метод додає лише налаштування, будь-які інші налаштування, чітко вказані у файлах
config/*
, будуть перевизначати їх.
Наступний приклад демонструє, як додати спочатку налаштування конфігурації у декількох пакетах, а також як відключити прапорець у декількох пакетах, на випадок, якщо не зареєстровано інший конкретний пакет:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
// src/Acme/HelloBundle/DependencyInjection/AcmeHelloExtension.php
public function prepend(ContainerBuilder $container)
{
// отримати всі пакети
$bundles = $container->getParameter('kernel.bundles');
// визначити, чи зареєстровано AcmeGoodbyeBundle
if (!isset($bundles['AcmeGoodbyeBundle'])) {
// відключити AcmeGoodbyeBundle в пакетах
$config = array('use_acme_goodbye' => false);
foreach ($container->getExtensions() as $name => $extension) {
switch ($name) {
case 'acme_something':
case 'acme_other':
// встановити use_acme_goodbye, як false у конфігурації
// acme_something та acme_other
//
// відмітьте, що якщо користувач вручну сконфігурував
// use_acme_goodbye, як true в config/services.yaml,
// то установка зрештою буде true, а не false
$container->prependExtensionConfig($name, $config);
break;
}
}
}
// отримати конфігурацію AcmeHelloExtension (це список конфігурації)
$configs = $container->getExtensionConfig($this->getAlias());
// повторити у зворотному порядку, щоб зберегти початковий порядок після додавання конфігурації
foreach (array_reverse($configs) as $config) {
// перевірити, чи встановлено entity_manager_name у конфігурації "acme_hello"
if (isset($config['entity_manager_name'])) {
// додати на початку налаштувань acme_something entity_manager_name
$container->prependExtensionConfig('acme_something', [
'entity_manager_name' => $config['entity_manager_name'],
]);
}
}
}
Вищенаписане буде еквівалентно написанню наступного у config/packages/acme_something.yaml
у випадку, якщо AcmeGoodbyeBundle не зареєстровано, а налаштування entity_manager_name
для acme_hello
встановлене, як non_default
:
- # config/packages/acme_something.yaml
- acme_something:
- # ... use_acme_goodbye: false entity_manager_name: non_default
- acme_other:
- # ... use_acme_goodbye: false
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
<!-- config/packages/acme_something.xml --> <?xml version="1.0" encoding="UTF-8" ?> <container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:acme-something="http://example.org/schema/dic/acme_something" xmlns:acme-other="http://example.org/schema/dic/acme_other" xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd http://example.org/schema/dic/acme_something https://example.org/schema/dic/acme_something/acme_something-1.0.xsd http://example.org/schema/dic/acme_other https://example.org/schema/dic/acme_something/acme_other-1.0.xsd" > <acme-something:config use-acme-goodbye="false"> <!-- ... --> <acme-something:entity-manager-name>non_default</acme-something:entity-manager-name> </acme-something:config> <acme-other:config use-acme-goodbye="false"> <!-- ... --> </acme-other:config> </container>
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// config/packages/acme_something.php namespace Symfony\Component\DependencyInjection\Loader\Configurator; return static function (ContainerConfigurator $container) { $container->extension('acme_something', [ // ... 'use_acme_goodbye' => false, 'entity_manager_name' => 'non_default', ]); $container->extension('acme_other', [ // ... 'use_acme_goodbye' => false, ]); };
Додавання розширення у класі пакета
6.1
Клас AbstractBundle
було представлено в Symfony 6.1.
Ви також можете додавати до конфігурації розширення напряму у вашому класі Пакета, якщо ви розширюєте з класу AbstractBundle і визначаєте метод prependExtension():
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Symfony\Component\HttpKernel\Bundle\AbstractBundle;
class FooBundle extends AbstractBundle
{
public function prependExtension(ContainerConfigurator $container, ContainerBuilder $builder): void
{
// додати наприкінці
$builder->prependExtensionConfig('framework', [
'cache' => ['prefix_seed' => 'foo/bar'],
]);
// додати на початку
$container->extension('framework', [
'cache' => ['prefix_seed' => 'foo/bar'],
]);
// додати на початку з файлу
$container->import('../config/packages/cache.php');
}
}
Note
Метод prependExtension()
, як і prepend()
, викликається тільки під час компіляції.
Використання PrependExtensionInterface більше, ніж одним пакетом
Якщо існує більше одного пакета, який додає одне й те саме розширення, та визначає один і той самій ключ, то перший зареєстрований пакет отримає пріоритет: наступні пакети не будуть перевизначати це конкретне налаштування конфігурації.