Встроенные сервис-теги Symfony
Дата обновления перевода 2024-07-26
Встроенные сервис-теги Symfony
Сервис-теги - это механизм, используемый компонентом DependencyInjection component, чтобы отмечать сервисы, которые требуют особой обработки, вроде консольных команд или расширений Twig.
Эта статья демонстрирует наиболее распространённые теги, предоставленные компонентами Symfony, но в вашем приложении может быть доступно больше тегов, предоставленных сторонними пакетами.
Выполните эту команду, чтобы отобразить тегированные сервисы в вашем приложении:
1
$ php bin/console debug:container --tags
Чтобы найти конкретный тег, повторно выполните эту команду с поисковым запросом:
1
$ php bin/console debug:container --tag=form.type
assets.package
Цель: Добавить пакет ресурса к приложению
Это альтернативный способ заявить о пакете ресурсов . Имя пакета устанавливается в таком порядке:
- сначала, атрибут тега
package
; - затем, значение, возвращённое статичным методом
getDefaultPackageName()
, если он определён; - наконец, имя сервиса.
1 2 3 4
services:
App\Assets\AvatarPackage:
tags:
- { name: assets.package, package: avatars }
Теперь вы можете использовать пакет avatars
в ваших шаблонах:
1
<img src="{{ asset('...', 'avatars') }}">
auto_alias
Цель: Определить союзников, основываясь на значении параметров контейнера
Рассмотрите следующую конфигурацию, определяющие три разных, но связанных сервиса:
1 2 3 4 5 6 7
services:
app.mysql_lock:
class: App\Lock\MysqlLock
app.postgresql_lock:
class: App\Lock\PostgresqlLock
app.sqlite_lock:
class: App\Lock\SqliteLock
Вместо того, чтобы работать с этими сервисами, вашему приложению требуется общий
сервис app.lock
, который будет союзником одного из этих сервисов, в зависимости
от некоторой конфигурации. Благодаря опции auto_alias
, вы можете автоматически
создать этого союзника, основываясь на значении параметра конфигурации.
Предположим, что параметр конфигурации, под названием database_type
, существует.
Тогда, общий сервис app.lock
может быть определён следующим образом:
1 2 3 4 5 6 7 8 9 10
services:
app.mysql_lock:
# ...
app.postgresql_lock:
# ...
app.sqlite_lock:
# ...
app.lock:
tags:
- { name: auto_alias, format: "app.%database_type%_lock" }
Опция format
определяет выражение, использованное для создания имени
сервиса для союзника. Это выражение может использовать любой параметр контейнера
(как обычно, заключая их имена в символы %
).
Note
При использовании тега auto_alias
,определять союзные сервисы приватными не
обязательно. Однако, это в большинстве случаев имеет смысл сделать (как в примере
выше), чтобы предотвратить полчение доступа к этим сервисам напрямую вместо
использования общего союзника сервиса.
console.command
Цель: Добавить команду в приложение
Чтобы узнать детали о регистрации ваших собственных команд в сервис-контейнере, прочтите Как определять команды, как сервисы.
container.hot_path
Цель: Добавить к списку всегда необходимых сервисов
Этот тег идентифицирует сервисы, которые необходимы всегда. Он применяется только
к очень короткому списку сервисов начальной загрузки (вроде router
, event_dispatcher
,
http_kernel
, request_stack
, и т.д.). Затем, он распространяется на все зависимости
этих сервисов, со специальным случаем для слушателей событий, где только перечисленные
события распространяются на слушателей, связанных с ними.
Он заменит, в кеше для сгенеированных фабрик сервисов, автозагрузку PHP на обычный встроенный
include_once
. Преимуществом есть полный обход автозагрузчика для сервисов и их иерархии
классов. Результатом становится значительное улучшение производительности.
Используйте этот тег с большой осторожностью, вам нужно быть уверенными, что тегированный сервис используется всегда.
container.no_preload
Цель: Удалить класс из списка классов, предварительно загруженных PHP
Добавьте этот тег к сервису и его класс не будет предварительно загружен при использовании предварительной загрузки классов PHP:
1 2 3
services:
App\SomeNamespace\SomeService:
tags: ['container.no_preload']
Если вы добавите какой-то сервис с тегом container.no_preload
в качестве
аргумента другого сервиса, тег container.no_preload
автоматически применяется
и к этому сервису.
container.preload
Цель: Добавить какой-то класс к списку классов, предварительно загруженных PHP
При использовании предварительной загрузки классов PHP, этот тег позволяет вам определять, какие классы должны быть предварительно загружены. Это может улучшить производительность, сделав некоторые из классов. используемых вашим сервисом, всегда доступнпыми для всех запросов (до перезаргузки сервера):
1 2 3 4 5 6
services:
App\SomeNamespace\SomeService:
tags:
- { name: 'container.preload', class: 'App\SomeClass' }
- { name: 'container.preload', class: 'App\Some\OtherClass' }
# ...
controller.argument_value_resolver
Цель: Зарегистрировать разрешитель значений для аргументов контроллера вроде Request
Разрешители значений реализуют ValueResolverInterface и используются для разрешения значений аргументов для контроллеров, как описано тут: Расширения разрешения аргумента действия.
data_collector
Цель: Создать класс, собирающий пользовательские данные для профилировщика
Для того, чтобы узнать детали о создании вашей собственной пользовательской коллекции данных, прочтите статью Как создать пользовательский сборщик данных.
doctrine.event_listener
Цель: Добавить слушателя событий Doctrine
Для того, чтобы узнать детали о создании слушателей событий Doctrine, прочтите статью События Doctrine.
doctrine.event_subscriber
Цель: Добавить подписчика событий Doctrine
Для того, чтобы узнать детали о создании подписчиков событий Doctrine, прочтите статью События Doctrine.
form.type
Цель: Cоздать пользовательский тип поля формы
Для того, чтобы узнать детали о создании вашего собственного пользовательского типа формы, прочтите статью Как создать пользовательский тип поля формы.
form.type_extension
Цель: Создать пользовательское "расширение формы"
Для того, чтобы узнать детали о создании расширений типов формы, прочтите статью Как создать расширение типа формы.
form.type_guesser
Цель: Добавить вашу собственную логику для "отгадывания типа формы"
Этот тег позволяет вам добавлять вашу собственную логику в процесс.По умолчанию, угадывание угадывание формы проводится "отгадывателями", основываясь на метаданных валидации и Doctrine (если вы используете Doctrine) или Propel (если вы используете Propel).
See also
Чтобы узнать, как создать ваш собственный отгадыватель типов, см. Создание пользовательского отгадывателя типа.
kernel.cache_clearer
Цель: Зарегистрировать ваш сервис для вызова во время процесса очистки кеша
Очистка кеша происходит каждый раз, когда вы вызываете команду cache:clear
.
Если ваш пакет кеширует файлы, вам нужно добавить пользовательского очистителя
кеша для очистки этих файлов во время процесса очистки кеша.
Для того, чтобы зарегистрировать вашего пользовательского очистителя кеша, для начала вам нужно создать класс сервиса:
1 2 3 4 5 6 7 8 9 10 11 12
// src/Cache/MyClearer.php
namespace App\Cache;
use Symfony\Component\HttpKernel\CacheClearer\CacheClearerInterface;
class MyClearer implements CacheClearerInterface
{
public function clear(string $cacheDirectory): void
{
// очистите ваш кеш
}
}
Если вы используетет конфигурацию services.yaml по умолчанию ,
то ваш сервис будет автоматически тегирован kernel.cache_clearer
. Но, вы также
можете зарегистрировать его вручную:
1 2 3
services:
App\Cache\MyClearer:
tags: [kernel.cache_clearer]
kernel.cache_warmer
Цель: Зарегистрировать ваш сервис для вызова во время процесса разогрева кеша
Разогрев кеша происходит каждый раз, когда вы выполняете команду cache:warmup
или cache:clear
(разве только вы не передаёте --no-warmup
в cache:clear
).
Он также выполняется при обработке запроса, если он ещё не был проведен одной из
команд.
Целью является инициализация любого кеша, который будет необходим приложению, и предотвратить первого пользователя от существенной "нагрузки кеша". когда кеш генерируется динамически.
Зарегистрируйте ваш собственный разогреватель кеша, для начала создайте сервис, реализующий интерфейс CacheWarmerInterface:
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
// src/Cache/MyCustomWarmer.php
namespace App\Cache;
use App\Foo\Bar;
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface;
class MyCustomWarmer implements CacheWarmerInterface
{
public function warmUp($cacheDirectory): array
{
// ... сделайте какие-то оперции, чтобы "разогреть" ваш кеш
$filesAndClassesToPreload = [];
$filesAndClassesToPreload[] = Bar::class;
foreach (scandir($someCacheDir) as $file) {
if (!is_dir($file = $someCacheDir.'/'.$file)) {
$filesAndClassesToPreload[] = $file;
}
}
return $filesAndClassesToPreload;
}
public function isOptional(): bool
{
return true;
}
}
Метод warmUp()
должен возвращать массив с файлами и классами для предварительной
загрузки. Файлы должны быть абсолютными путями, а классы должны быть полностью
квалифицированными именами классов. Единственное ограничение - файлы должны храниться
в каталоге кеша. Если вам не нужно ничего предварительно загружать, возвращает пустой
массив.
Метод isOptional()
должен возвращать true, если возможо использовать приложение
не вызывая этого разогревателя кеша. В Symfony, необязательные разогреватели всегда
выполняются по умолчанию (вы можете изменить это, используя опцию --no-optional-warmers
при выполнении команды).
Если вы используете конфигурацию services.yaml по умолчанию ,
то ваш сервис будет автоматически тегирован kernel.cache_warmer
. Но вы также
можете зарегистрировать его вручную:
1 2 3 4
services:
App\Cache\MyCustomWarmer:
tags:
- { name: kernel.cache_warmer, priority: 0 }
Note
Значение priority
необязательно, и по умолчанию равняется 0.
Чем выше приоритет, тем скорее оно будет выполнено.
Caution
Если ваш разогреватель кеша не будет выполнен из-за исключения, то Symfony не будет пытаться выполнить его опять для следующих запросов. Следовательно, ваше приложение и/или пакеты должны быть готовы к тому, что содержимое, сгенерированное разогревателем кеша, может быть недоступно.
В дополнение к вашим собственным разогревателям кеша, компоненты Symfony и сторонние пакеты тоже определяют разогреватели кеша в собственных целях. Вы можете перечислить их все с помощью следующей команды:
1
$ php bin/console debug:container --tag=kernel.cache_warmer
kernel.event_listener
Цель: Слушать разные события/привязки в Symfony
Во время выполнения приложения Symfony, вызываются разные события, и вы также можете диспетчеризировать пользовательские события. Этот тег позволяе вам привязать ваши собственные классы к любому из этих событий.
Для того, чтобы увидеть полный пример этого слушателя, прочтите статью События и слушатели событий.
Справочник базовых слушателей событий
Чтобы увидеть справочник слушателей событий, связанных с каждым событием ядра, смотрите Справочник событий Symfony.
kernel.event_subscriber
Цель: Подписаться на набор разных событий/привязок в Symfony
Это альтернативный способ создать слушателя событий, и он является рекомендованным
(вместо использования kernel.event_listener
). См. .
kernel.fragment_renderer
Цель: Добавить новые стратегии отображение HTTP-содержимого
Для того, чтобы добавить новую стратегию отображения - в дополнение к базовым
стратегиям вроде EsiFragmentRenderer
- создайте класс, реализующий
FragmentRendererInterface,
зарегистрируйте его как сервис, а потом тегируйте его kernel.fragment_renderer
.
kernel.locale_aware
Цель: Получить доступ к текущей локали
Установка и получение локали могут быть проведены через конфигурацию или с использованием параметров контейнера, слушателей, параметров маршрута или текущего пользователя.
Благодаря контракту Translation
, локаль может быть установлена через сервисы.
Чтобы зарегистрировать вашу собственный сервис, знающий о локали, для начала создайте сервис, реализующий интерфейс LocaleAwareInterface:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
// src/Locale/MyCustomLocaleHandler.php
namespace App\Locale;
use Symfony\Contracts\Translation\LocaleAwareInterface;
class MyCustomLocaleHandler implements LocaleAwareInterface
{
public function setLocale(string $locale): void
{
$this->locale = $locale;
}
public function getLocale(): string
{
return $this->locale;
}
}
Если вы используете конфигурацию services.yaml по умолчанию ,
ваш сервис будет автоматически тегирован kernel.locale_aware
. Но вы также
можете зарегистрировать его вручную:
1 2 3
services:
App\Locale\MyCustomLocaleHandler:
tags: [kernel.locale_aware]
kernel.reset
Цель: Очистить сервисы между запросами
Во всех основных запросах (не sub-requests ), кроме
первого, Symfony ищет любой сервис, помеченный тегом kernel.reset
для повторной
инициализации их состояния. Это делается путём вызовом метода, имя которого задано
в аргументе method
этого тега.
Это наиболее полезно при запуске ваших проектов на серверах приложений, которые повторно используют приложение Symfony между запросами, чтобы улучшить производительность. Этот тег применяется, к примеру, ко встроенным коллекторам данных профилировщика, чтобы удалить всю их информацию.
mime.mime_type_guesser
Цель: Добавить вашу собственную логику для угадывания MIME-типа
Этот тег используется для регистрации ваших собственных угадывателей MIME-типа в случае, если угадыватели, предоставленные компоненетом Mime, вам не подходят.
monolog.logger
Цель: Логировать пользовательским каналом логирования c Monolog
Monolog позволяет вам делить обработчиковм между несколькими каналами
логирования. Сервис логирования использует канал app
, но вы можете
изменить канал при внедрении логгера в сервис.
1 2 3 4 5
services:
App\Log\CustomLogger:
arguments: ['@logger']
tags:
- { name: monolog.logger, channel: app }
Tip
Вы также можете сконфигурировать пользовательские каналы в конфигурации и извлечь соответствующий сервис логирования напрямую из сервис-контейнера (см. ).
monolog.processor
Цель: Добавить пользовательский процессор для логирования
Monolog позволяет вам добавлять процессы в логгер или в обработчики для
добавления дополнительных данных в записи. Процессор получает запись в
качестве аргумента и должен вернуть его после добавления некоторых дополнительных
данных в атрибуте записи extra
.
Встроенный IntrospectionProcessor
может быть использован, чтобы добавить
файл, строку, класс и метод, где был вызван логгер.
Вы можете добавить процессор глобально:
1 2 3
services:
Monolog\Processor\IntrospectionProcessor:
tags: [monolog.processor]
Tip
Если ваш сервис не является вызываемым (используя __invoke()
), то вы
можете добавить атрибут method
в тег, чтобы использовать специальный
метод.
Вы также можете добавить процессор для конкретного обработчика, используя
атрибут handler
:
1 2 3 4
services:
Monolog\Processor\IntrospectionProcessor:
tags:
- { name: monolog.processor, handler: firephp }
Вы также можете добавить процессор для конкретного канала логирования, используя
атрибут channel
. Он зарегистрирует процессор только для канала логирования
security
, используемого в компоненте Безопасность:
1 2 3 4
services:
Monolog\Processor\IntrospectionProcessor:
tags:
- { name: monolog.processor, channel: security }
Note
Вы не можете использовать оба атрибута handler
и channel
для одного
тега, так как обработчики общие для всех каналов.
routing.loader
Цель: Зарегистрировать пользовательский сервис, загружающий маршруты
Чтобы подключить пользовательский загрузчик маршрутов, добавьте его в качестве
регулярного сервиса к одной из ваших конфигураций, и тегируйте его routing.loader
:
1 2 3
services:
App\Routing\CustomLoader:
tags: [routing.loader]
Чтобы узнать больше, см. Как создать пользовательский загрузчик маршрутов.
routing.expression_language_provider
Цель: Зарегистрировать провайдер для функций языка выражений в маршрутизации
Этот тег используется для автоматической регистрации провайдеров функции выражений для компонента маршрутизации выражений. Используя эти провайдеры, вы можете добавлять пользовательские функции в язык маршрутизации выражений.
security.expression_language_provider
Цель: Зарегистрировать провайдер для функций языка выражений в безопасности
Этот тег используется для автоматической регистрации провайдеров функции выражений для компонента безопасности выражений. Используя эти провайдеры, вы можете добавлять пользовательские функции в язык безопасности выражений.
security.voter
Цель: Добавить пользовательского избирателя в логику авторизации Symfony
Когда вы вызываете isGranted()
в контролёре авторизации Symfony, за кулисами
используется система "избирателей", чтобы определить, есть ли у пользователя доступ.
Тег security.voter
позволяет вам добавлять вашего пользователького избирателя в
эту систему.
Чтобы узнать больше, прочтите статью Как использовать избирателей для проверки разрешений пользователей.
serializer.encoder
Цель: Зарегистрировать новый кодировщик в сервисе serializer
Тегированный класс должен реализовать EncoderInterface и DecoderInterface.
Чтобы узнать больше, см. Как использовать Serializer.
serializer.normalizer
Цель: Зарегистрировать новый нормализатор в сервисе serializer
Тегированный класс должен реализовать NormalizerInterface и DenormalizerInterface.
Чтобы узнать больше, см. Как использовать Serializer.
Выполните следующую команду для проверки приоритетов нормализаторов по умолчанию:
1
$ php bin/console debug:container --tag serializer.normalizer
translation.loader
Цель: Зарегистрировать пользовательский сервис, загружающий переводы
По умолчанию, переводы загрузаются из файловой системы во множестве разных форматов (YAML, XLIFF, PHP, и др.).
See also
Узнайте, как загружать пользовательские форматы в разделе компонентов.
Теперь, зарегистрируйте ваш загрузчик как сервис и тегируйте его translation.loader
:
1 2 3 4
services:
App\Translation\MyCustomLoader:
tags:
- { name: translation.loader, alias: bin }
Опция alias
обязательна и очень важна: она определяет "суффикс" файла, который
будет использован для файлов-источников, использующих этот загрузчик. Например,
представьте, что у вас есть некоторый пользовательский формат bin
, который вам
нужно загрузить. Если у ввс есть файл bin
, содержащий французские переводы для
домена messages
, то у вас может быть файл translations/messages.fr.bin
.
Когда Symfony пытается загрузить файл bin
, то она передаёт путь вашему
пользовательскому загрузчику в качестве аргумента $resource
. Вы можете
выполнить любую необходимую вам логику в этом файле, чтобы загрузить ваши
переводы.
Если вы загружаете переводы из DB, то вам всё равно нужен файл-источник, но
он может быть либо пустым, либо содержать немного информации о загрузке этих
источников из DB. Цель файла - запустить метод load()
в вашем пользовательском
загрузчике.
translation.extractor
Цель: Зарегистрировать пользовательский сервис, извлекающий сообщения перевода из файла
При выполнении команды translation:extract
она использует экстракторы для
извлечения сообщений перевода из файла. По умолчанию фреймворк Symfony имеет
TwigExtractor и PHP-экстрактор для
поиска и извлечения ключей перевода из шаблонов Twig и файлов PHP.
Symfony включает в себя два PHP-экстрактора: PhpExtractor и PhpAstExtractor. Первый прост и не требует установки каких-либо пакетов, а второй является более продвинутым, но требует установки данной зависимости в проекте:
1
$ composer require nikic/php-parser
Вы можете создать собственную функцию извлечения, создав класс, реализующий
ExtractorInterface
и тегировав сервис translation.extractor
. Тег имеет одну обязательную
опцию: alias
, которая определяет имя функции извлечения:
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
// src/Acme/DemoBundle/Translation/FooExtractor.php
namespace Acme\DemoBundle\Translation;
use Symfony\Component\Translation\Extractor\ExtractorInterface;
use Symfony\Component\Translation\MessageCatalogue;
class FooExtractor implements ExtractorInterface
{
protected string $prefix;
/**
* Извлекает сообщения перевода из каталога шаблонов в каталог.
*/
public function extract(string $directory, MessageCatalogue $catalog): void
{
// ...
}
/**
* Устанавливает префикс, который должен быть использован для новонайденных сообщений.
*/
public function setPrefix(string $prefix): void
{
$this->prefix = $prefix;
}
}
1 2 3 4
services:
App\Translation\CustomExtractor:
tags:
- { name: translation.extractor, alias: foo }
translation.dumper
Цель: Зарегистрировать пользоветельский сервис, сбрасывающий сообщения перевода
После того, как извлекатель переводов извлёк все сообщения из шаблонов, выполняется сброссообщений в файл перевода в специальном формате.
Symfony уже имеет несколько дамперов:
- CsvFileDumper
- IcuResFileDumper
- IniFileDumper
- MoFileDumper
- PoFileDumper
- QtFileDumper
- XliffFileDumper
- YamlFileDumper
Вы можете создать пользовательский дампер, расширив
FileDumper или реализовав
DumperInterface и тегировав
сервис с помощью translation.dumper
. Тег имеет одну опцию: alias
. Это
имя, которое использовалось для определения, какой дампер применять.
1 2 3 4
services:
App\Translation\JsonFileDumper:
tags:
- { name: translation.dumper, alias: json }
See also
Узнайте, как сбрасывать пользовательские форматы в разделе компонентов.
translation.provider_factory
Цель: зарегистрировать фабрику, связанную с пользовательскими поставщиками переводов
При создании пользовательских поставщиков перевода , вы должны
зарегистрировать свою фабрику как сервис и добавить к ней тег translation.provider_factory
:
1 2 3 4
services:
App\Translation\CustomProviderFactory:
tags:
- { name: translation.provider_factory }
twig.extension
Цель: Зарегистрировать пользовательское расширение Twig
Чтобы подключить расширение Twig, добавьте его в качестве регулярного сервиса
к одной из ваших конфигураций и тегируйте его с помощью twig.extension
.
Если вы используете конфигурацию services.yaml по умолчанию ,
то сервис регистрируется и тегируется автоматически. Но вы также можете зарегистрировать
его вручную:
1 2 3 4 5 6 7 8 9
services:
App\Twig\AppExtension:
tags: [twig.extension]
# по желанию вы можете определить приоритетность расширения (по умолчанию = 0).
# Расширения с более высокими приоритетами регистрируются раньше. Наиболее
# полезно регистрировать поздние расширения, переопределяющие другие расширения.
App\Twig\AnotherExtension:
tags: [{ name: twig.extension, priority: -100 }]
Чтобы узнать, как создать сам класс расширения Twig, см. Документацию Twig по этой теме, или прочтите статью Как написать пользовательское расширение Twig.
twig.loader
Цель: Зарегистрировать пользовательский сервис, загружающий шаблоны Twig
По умолчанию, Symfony использует только один Загрузчик Twig -
FilesystemLoader. Если вам нужно
загрузить шаблоны Twig из другого источника, вы можете создать сервис для нового
загрузчика, и тегировать его twig.loader
.
Если вы используете конфигурацию services.yaml по умолчанию , то сервис будет автоматически тегирован благодаря автоконфигурации. Но вы можете также зарегистрировать его вручную:
1 2 3 4
services:
App\Twig\CustomLoader:
tags:
- { name: twig.loader, priority: 0 }
Note
Значение priority
необязательно и по умолчанию равняется 0.
Загрузчики с более высоким приоритетом загрудаются первыми.
twig.runtime
Цель: Зарегистрировать пользовательское ленивозагружаемое расширение Twig
Ленивозагружаемые расширения Twig определяются как
обычные сервисы, но должны иметь тег twig.runtime
. Если вы используете
конфигурацию services.yaml по умолчанию ,
сервис автоматически регистрируется и тегируется. Но вы также можете зарегистрировать
его вручную:
1 2 3
services:
App\Twig\AppExtension:
tags: [twig.runtime]
validator.constraint_validator
Цель: Создать собственное пользовательское ограничение валидации
Этот тег позволяет вам создавать и регистрировать ваше собственное ограничение валидации. Чтобы узнать больше, прочтите статью Как создать пользовательское ограничение валидации.
validator.initializer
Цель: Зарегистрировать сервис, инициализирующий объекты до валидации
Этот тег предоставляет очень нетипичную часть функциональности, позволяющую вам выполнять некоторые действия с объектом прямо перед его валидацие. Например, он используется Doctrine, чтобы запросить все лениво загруженные данные объекта до его валидации. Без этого, некоторые данные в сущности Doctrine будут казаться "отсутствующими" при валидации, несмотря на то, что это не так.
Если вам нужно использовать этот тег, просто создайте новый класс, реализующий
интерфейс ObjectInitializerInterface.
Потом, тегируйте его тегом validator.initializer
(не имеет опций).
Для того, чтобы увидеть пример, смотрите класс DoctrineInitializer
внутри
Doctrine Bridge.