Как упростить конфигурацию нескольких пакетов
Дата обновления перевода 2024-06-24
Как упростить конфигурацию нескольких пакетов
При построении повтроно используемых и расширяемых приложений, разработчики часто сталкиваются с выбором: либо создать один большой пакет, либо несколько меньших пакетов. Создание одного пакета имеет недостаток в виде невозможности выбора пользователями удаления неиспользуемой функциональности. Создание нескольких пакетов имеет недостаток в виде утомительно длинной конфигурации и необходимости повторения настроек для разных пакетов.
Существует возможность удалить недостаток подхода нескольких пакетов, включив
одно расширение, которое добавляло бы вначале настроек любого пакета некоторую
информацию. Оно может использовать настройки, определённые в файлах 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): void
{
// ...
}
}
Внутри метода 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
// src/Acme/HelloBundle/DependencyInjection/AcmeHelloExtension.php
public function prepend(ContainerBuilder $container): void
{
// получить все пакеты
$bundles = $container->getParameter('kernel.bundles');
// определить, зарегистрирован ли AcmeGoodbyeBundle
if (!isset($bundles['AcmeGoodbyeBundle'])) {
// отключить AcmeGoodbyeBundle в пакетах
$config = ['use_acme_goodbye' => false];
foreach ($container->getExtensions() as $name => $extension) {
match ($name) {
// установить use_acme_goodbye, как false в конфигурации
// acme_something и acme_other
//
// заметьте, что если пользователь вручную сконфигурировал
// use_acme_goodbye, как true в config/services.yaml,
// то установка в итоге будет true, а не false
'acme_something', 'acme_other' => $container->prependExtensionConfig($name, $config),
default => null
};
}
}
// получить конфигурацию 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
:
1 2 3 4 5 6 7 8 9
# config/packages/acme_something.yaml
acme_something:
# ...
use_acme_goodbye: false
entity_manager_name: non_default
acme_other:
# ...
use_acme_goodbye: false
Добавление расширения к началку класса пакета
Вы такоже можете добавлять добавлять к конфигурации расширения прямо в классе Пакета, если расширяете из класса 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 $containerConfigurator, ContainerBuilder $containerBuilder): void
{
// добавить к началу
$containerBuilder->prependExtensionConfig('framework', [
'cache' => ['prefix_seed' => 'foo/bar'],
]);
// добавить
$containerConfigurator->extension('framework', [
'cache' => ['prefix_seed' => 'foo/bar'],
]);
// добавить из файла
$containerConfigurator->import('../config/packages/cache.php');
}
}
Note
Метод prependExtension()
, как и prepend()
, вызывается только
во время компиляции.
В качестве альтернативы можно использовать параметр prepend
метода
extension():
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
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 $containerConfigurator, ContainerBuilder $containerBuilder): void
{
// ...
$containerConfigurator->extension('framework', [
'cache' => ['prefix_seed' => 'foo/bar'],
], prepend: true);
// ...
}
}
7.1
Параметр prepend
метода
extension()
был представлен в Symfony 7.1.
Больше о пакетах и использованием PrependExtensionInterface
Если существует более одного пакета, который добавляет одно и то же расширение, и определяет один и тот же ключ, то первый зарегистрированный пакет получит приоритет: последующие пакеты не будут пеоепределять эту конкретную настройку конфигурации.