Если вы откроете конфигурационный файл вашего приложения ( обычно app/config/config.yml ), вы увидете несколько конфигурационных “простанства имен”, такие как frameworktwig and doctrine. Каждый из них настраивает определенный бандл, позволяя вам настраивать их и позволяя бандлам самим выполнять все черную работу.

Например, следующий код говорить FrameWorkBundle включить интеграцию форм, что позволяет включять несколько сервисом так же интегрировать другие связанные компоненты:

Когда вы создаете бандл, у вас есть 2 варианта как обрабатывать конфигурацию:

1. Нормальноя сервисная настройка (easy):

Вы можете указать ваши сервисы в файле настроек (например services.yml), который находится в вашем бандле и затем импортировать его в ваше основное приложение. Это реально просто, быстро и эффективно. Если вы используете параметр, тогда вы все еще имеете гибкую для костомизацию ваших бандлов из конфигурации вашего приложения. Смотри Importing Configuration with imports

2. Семантическая конфигурация (advance):

Этот путь конфигурирует с ядром бандлов (как описано выше). Основная идея в том, вместо того чтобы юзер перезаписывал определенные параметры, вы можете позволить пользователю конфигурировать лишь некоторые, определнные созжанные опции. Как создатель бандлов, вы парсите через конфигурацию и загрузаете сервисы внути “Расширений” класса. Благодаря этому методоу, вам не надо импортировать любые конфигурационные ресурсы из главного приложения: расширенный класс может включать из все.

Второй пункт, который будет рассмотрен в этой статье – более гибок, но требует больше времени для установки. Если вы не знаете какой метод использовать вам, возможно вам лучше сначало использовать метод №1, а потом поменять на метод №2, если понадобиться. Если же в ваших планах распротранять бандл, то сразу переходите ко второму варианту.

Второй вариант имеет несколько специфичных преимущества:

  • Более мощное определение параметров: определенные значения могут вызвать создание множества определенных сервисов;
  • Возможность иметь конфигурационную иерархию;
  • Элегантное соединения, если несколько конфигурационных файлов переопределют друг друга ( например config_dev.yml и config.yml )ж
  • Конфигурация проверок ( если вы используете Configuration Class );
  • IDE авто-комплит, если вы создаете XSD и разрабатываете использую XML.

[su_spoiler open=”yes” icon=”” class=”my-spoiler note” title=”Перезаписывание параметров бандла”]

Если бандл предоставляет Расширенный класс, тогда вы должны обычно не переопределять сервис контейнера из этого бандла. Идея в том что, если Расширенный класс существует, каждая настройка  должна быть конфигурируема этим классом. Другими словами класс расширение определяет все публично поддержал параметры конфигурации
для которых обратная совместимость будет сохранена.

Для параметров опрабатываемых в Dependency Injection class смотри Using Parameters within a Dependency Injection Class

[/su_spoiler]

Создание Расширенного класса

Если вы решили выбрать семантическую конфигурацию для вашего бандла, перво-наперво вы должны создать новый “Расширенный” класс, который будет обрабатывать процесс. Этот класс должен находиться в DependencyInjection  вашего бандла, и его имя должно быть по контсрукции таким же как бандл, только вместо Bundle использовать суффикс Extension. Например, Расширенный класс для AcmeHelloBundle будет AcmeHelloExtension:

[su_spoiler open=”yes” icon=”” class=”my-spoiler note” title=””]

Методы getXsdValidationBasePath и getNamespace нужны только если бандл предоставляет опции через XSD

[/su_spoiler]

Наличие предыдущего класса означает что вы можете определить acme_hello конфигурационное пространство имен в любом конфигурационном файлы. Пространство имен acme_hello собирается из имени расширенного класса, путем удаления слова Extension, перевод в нижний регистр и добавление нижнего подчеркивания. Другими словами, AcmeHelloExtension стало acme_hello.

Вы можете начать задание настроек в соответствии с пространством имен:

[su_spoiler open=”yes” icon=”” class=”my-spoiler tip” title=””]

Если вы будете следовать соглашению о прастранстве имен, тогда метод load() вашего расширенного класса всегда будут вызываться при условие что ваш бандл был зарегистрирован в Kernel. Дгурими словами, даже если пользователь не предоставил никакой конфигурации ( например acme_hello не существует ), метод load() будет вызван и передаст пустой массив $config. Вы можете все еще использовать настройки по умолчанию если хотите.

[/su_spoiler]

Регистрация расширенного класса

Расширенный класс автоматически зарегистрирует Symfony2, если будут соблюдены следующие пункты:

  • Расширение должно быть сохранено в пространстве имен DependencyInjection
  • Расширение должно иметь имя такое же как бандл, только вместо суффикса Bundle иметь Extension (AcmeHelloExtension – AcmeHelloBuncle)
  • Расширение должно предоставлять XSD схему ( но реситрация будет независима )

Ручная регистрация Расширенного класса

Если вы не следовали этим правилам, то можно добавить класс вручную. Чтобы зарестрировать расширение нужно переопределить метод Bundle::build() в вашем бандле:

В этом случае, расширенный класс должен реализовывать метод getAlias() и возвращать уникальное сокращение бандла ( например acme_hello ). Это требование обязательно, т.к. имя класса не следует второму правилу.

Кроме того, метод load() будет выполнен если пользователь задаст ваш псевдонимм acme_hello хотя бы в одном конфигурационном файле. Еще раз, это потому что Расширенный класс не следует соглашениям выше, и ничего не происходит автоматически.

Парсинг массива $configs

Всякий раз когда пользователь использует acme_hello в конфигурационном файле, вызывался метод load() и передавался туда массив конфигураций ( Symfony2 автоматически конвертирует XML и YAML в массив ).

Например, вот эта конфигурация:

Преобразуется в такой массив:

Заметьте что это многомерный массив, не просто сплошной одномерный. Это сделанно преднамеренно. Например, если есть acme_hello в другом конфигурационном файле – скажем в config_dev.yml – с другими значениями, тогда массив должен выглядить так:

Порядок двух массивов зависит от того какой установлен первый.

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

Ниже, в части Configuration Class, вы узнаете более надежный способ обрабатывать их. Но пока, мы можем только смержить их вручную:

[su_spoiler open=”yes” icon=”” class=”my-spoiler caution” title=””]

Убедитесь что способ тредставленный выше подходит для вашего бандла. Это только пример, не стоит слепо следовать ему.

[/su_spoiler]

 Использования метода load()

В load(), переменная $container  ссылается на контэйнер, который только знает о пространстве имен ( т.е. он не содержит информацию о сервисах, загруженных из других бандов ). Цель метода load() это манипулировать контэйнером, добавлять и конфигурировать любые методы или сервису, необходимые вашему бандлу.

Загрузка внешних конфигураций

Обычно нужно загрущить внешний конфигурационный файл, которые содержит большинство необходимых сервисов вашему бандлу. Например, предполошим у вас есть service.xml, который содержит конфигурацию сервисов вашего бандла:

Вы даже можете делать это в зависимости от значия в конфигурациях. Например, предположим вы хотите загружить набор сервисов только, если опция enabled имеет значение true:

Конфигурирование сервисов и задание параметров

Сейчас вы загрузии настройки сервиса, теперь вы должны модифицировать конфигурации согласно полученным значениям. Например, предположим у вас есть сервис, у вас есть сервис, у которого первый аргумент это строка “тип”, который используется внутри его. Вы бы хотели что это легко настроивалось пользователем бандла, тогда в вашем конфигурационном файле ( например services.xml ), вы определяете сервис и используете пустой параметр – acme_hello.my_service_type – это первый параметр:

Но почему вы определили пустой параметр и передали его в ваш сервис? Ответ состоит в том, что устанавливать этот параметр вы будете в расширенном классе, основываясь на входящем значении настройки. Предположим, что вы хотите позволить пользователю определять тип с ключом my_type. Добавьте обработку в метод load():

Теперь пользователь может эффективно настраивать сервис указывая значения в my_type:

Глобальные параметры

Когда вы настраиваете контэйнер, знайте что вы можете использовать следующие глобальные переменные:

  • kernel.name
  • kernel.environment
  • kernel.debug
  • kernel.root_dir
  • kernel.cache_dir
  • kernel.logs_dir
  • kernel.bundles
  • kernel.charset

[su_spoiler open=”yes” icon=”” class=”my-spoiler caution” title=””]

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

[/su_spoiler]

Валидация и Мерж с классом Конфигурации

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

[su_spoiler open=”yes” icon=”” class=”my-spoiler note” title=””]

Формат нормализации ссылается на факт использования определенного формата – в основном XML – результаты слегка различны должны быть “нормализованы” чтобы соотвествовать остальным

[/su_spoiler]

Чтобы воспользоваться преимуществами этой систему, создайте класс Configuration и постройте дерефо определяющее конфигурацию в этом классе:

Это очень простой пример, но вы теперь вы можете использовать в вашем классе метод load() чтобы смерживать ваши настройки и валидации. Если будет какое-нибудь не валидное значение в my_type, то юзер будет информирован что расширение не поддерживает данную опцию:

Метод processConfiguration() используется для конфигурации дерева, которое вы определили в классе Configuration для валидации, нормализации и соединения всех массивов настроек вместе.

Класс Configuration может быть намного сложнее чем показанные здесь, может поддерживать узлы массивов, “прототипные” узлы, сложную валидацию, XML нормализацию и сложный мерж. Вы можете прочитать об этом в the Config component documentation. Вы так же можете посмотреть в деле в Конфигурационных класса ядра, таких как FrameWorkBundle Configuration или TwigBundle Configuration.

Модификация конфигураций других Бандлов

Если у вас несколько бандлов зависящих друг от друга, тогда ля вас может быть полезно использовать один Расширенный класс чтобы модифицировать конфигурации Расширенные классы других бандлов, как будто конфигурации были взяти из app/config/config.yml.

Для этого рекомндуем почитать How to simplify configuration of multiple Bundles

Настройки dump

Команда config:dump-reference позволяет бандлу записать значени по умолчанию в YAML.

До тех пор пока конфигурация вашего бандла находится в положенной ей месте ( YourBundle\DependencyInjection\Configuration ) и нету __construct() все будет работать автоматически. Если же что-то отличается, то ваш Расширенный класс должет переопределить метод Extension::getConfiguration() и вернуть пример вашей конфигурации.

Комментарии и примеры могут быть добавлены в узлы при помощи методов ->info() и ->example():

Эотт пример показывает YAML комментарий в выходном файле при использовании команды config:dump-reference.