Как упростить конфигурацию нескольких пакетов¶
При построении повтроно используемых и расширяемых приложений, разработчики часто сталкиваются с выбором: либо создать один большой пакет, либо несколько меньших пакетов. Создание одного пакета имеет недостаток в виде невозможности выбора пользователями удаления неиспользуемой функциональности. Создание нескольких пакетов имеет недостаток в виде утомительно длинной конфигурации и необходимости повторения настроек для разных пакетов.
Существует возможность удалить недостаток подхода нескольких пакетов, включив
одно расширение, которое добавляло бы вначале настроек любого пакета некоторую
информацию. Оно может использовать настройки, определённые в файлах config/*
,
чтобы добавлять к настройкам информацию так же, как если бы они были ясно написаны
пользователем в конфигурации приложения.
Например, это можеть быть использовано для конфигурации имени менеджера сущностей для использования в нескольких пакетах. Или для включения необязательной функции, зависящей от другого загружаемого пакета.
Для того, чтобы дать расширению возможность делать это, оно должно реализовывать
PrependExtensionInterface
:
// src/Acme/HelloBundle/DependencyInjection/AcmeHelloExtension.php
namespace Acme\HelloBundle\DependencyInjection;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Extension\PrependExtensionInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
class AcmeHelloExtension extends Extension implements PrependExtensionInterface
{
// ...
public function prepend(ContainerBuilder $container)
{
// ...
}
}
Внутри метода prepend()
,
разработчики имеют полный доступ к экземпляру
ContainerBuilder
прямо перед вызовом метода load()
в каждом из зарегистрированных расширений пакета. Для того, чтобы добавить
вначале настройки к пакету, разработчики расширений могут использовать метод
prependExtensionConfig()
в экземпляре ContainerBuilder
.
Так как этот метод добавляет только настройки,любые другие настройки, ясно указанные
в файлах config/*
, будут переопределять их.
Следующий пример демонстрирует, как добавить вначале настройки конфигурации в нескольких пакетах, а также как отключить флажок в нескольких пакетах, на случай если не зарегистрирован другой конкретный пакет:
// 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());
// использовать класс Конфигурации, чтобы сгенерировать массив конфигурации с
// настройками "acme_hello"
$config = $this->processConfiguration(new Configuration(), $configs);
// проверить, установлено ли entity_manager_name в конфигурации "acme_hello"
if (isset($config['entity_manager_name'])) {
// добавить к настройкам acme_something entity_manager_name
$config = array('entity_manager_name' => $config['entity_manager_name']);
$container->prependExtensionConfig('acme_something', $config);
}
} }
}
Вышенаписанное будет эквивалентно написанию следующего в config/packages/acme_something.yaml
в случае, если AcmeGoodbyeBundle не зарегистрирован, а настройка entity_manager_name
для acme_hello
установлена, как non_default
:
- YAML
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
- XML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
<!-- 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 http://symfony.com/schema/dic/services/services-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" /> </container>
- PHP
1 2 3 4 5 6 7 8 9 10
// config/packages/acme_something.php $container->loadFromExtension('acme_something', array( // ... 'use_acme_goodbye' => false, 'entity_manager_name' => 'non_default', )); $container->loadFromExtension('acme_other', array( // ... 'use_acme_goodbye' => false, ));
Больше о пакетах и использованием PrependExtensionInterface¶
Если существует более одного пакета, который добавляет одно и то же расширение, и определяет один и тот же ключ, то первый зарегистрированный пакет получит приоритет: последующие пакеты не будут пеоепределять эту конкретную настройку конфигурации.
Эта документация является переводом официальной документации Symfony и предоставляется по свободной лицензии CC BY-SA 3.0.