Вбудовані теги сервісів Symfony

Дата оновлення перекладу 2024-05-29

Вбудовані теги сервісів Symfony

Сервіс-теги - це механізм, використовуваний компонентом DependencyInjection, щоб відмічати сервіси, які вимагають особливої обробки, на кшталт консольних команд або розширень 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, цей тег дозволяє вам визначати, які 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

Ціль: Створити користувацький тип поля форми

Для того, щоб дізнатися деталі про створення вашого власного користувацького типу форми, прочитайте статтю Як створити користувацький тип поля форми.

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
// 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

Ціль: Логувати користувацьким каналом логування з 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, використовуваного у компоненті 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

Ціль: Зареєструвати постачальник для функцій мови виразів у маршрутизації

Цей тег використовується для автоматичної реєстрації постачальників функції виразів для виразів компонента Routing. Використовуючи ці постачальники, ви можете додавати користувацькі функції у мову виразів маршрутизації.

security.expression_language_provider

Ціль: Зареєструвати постачальник для функцій мови виразів у безпеці

Цей тег використовується для автоматичної реєстрації постачальників функції виразів для виразів компонента Security. Використовуючи ці постачальники, ви можете додавати користувацькі функції у мову виразів безпеки.

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 та ін.).

Тепер, зареєструйте ваш завантажувач як сервіс та тегуйте його 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. Ви можете виконати будь-яку необхідну вам логіку у цьому файлі, щоб завантажити ваші переклади.

Якщо ви завантажуєте переклади з БД, то вам все одно потрібний файл-джерело, але він може бути або порожнім, або містити трохи інформації про завантаження цих джерел з БД. Ціль файлу - запустити метод 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 вже має декілька дамперів:

Ви можете створити користувацький дампер, розширивши FileDumper або реалізувавши DumperInterface та тегувавши сервіс за допомогою translation.dumper. Тег має одну опцію: alias. Це імʼя, яке використовувалося для визначення того, який дампер застосувати.

1
2
3
4
services:
    App\Translation\JsonFileDumper:
        tags:
            - { name: translation.dumper, alias: json }

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.