Symfony 7.4: Что нового
Представляем Symfony 7.4: отказ от XML-конфигурации, улучшенные voters, UUID v7 по умолчанию, кеширование HTTP-клиента, валидация видео и многое другое для эффективной разработки.
В ноябре 2025 года вышел долгожданный релиз Symfony 7.4, продолжающий традицию эволюционного развития фреймворка с сохранением обратной совместимости. Это обновление приносит десятки улучшений, направленных на повышение производительности, безопасности и удобства разработчиков.
В этой статье мы перечислим и разберем ключевые нововведения: отказ от устаревшего XML в конфигурации, новые возможности для безопасности (Voter), переход на современные UUID v7, встроенное кеширование HTTP-клиента по стандарту RFC 9111, мощное ограничение для валидации видеофайлов и многое другое.
Готовьтесь к плавному обновлению и новым инструментам для ваших проектов
Статьи про Symfony
Список нововведений
Устаревание XML-конфигурации: Чтобы упростить настройку приложений, Symfony 7.4 объявляет XML устаревшим форматом конфигурации.
Улучшения Security Voter: Добавлены новые функции Twig и возможность настраивать метаданные для механизма голосования безопасности.
Улучшения Uid: По умолчанию теперь генерируются UUID v7, добавлена микросекундная точность и упрощено использование в тестах.
Кеширование HTTP-клиента: Представлено клиентское кеширование HTTP, соответствующее стандарту RFC 9111, на базе компонента Cache.
Валидация видеофайлов: Добавлено новое ограничение для проверки видео с возможностью контроля размеров, кодеков и форматов.
Взвешенные переходы Workflow: Введена поддержка переходов с весами, что позволяет обрабатывать несколько экземпляров и моделировать процессы с количественными требованиями (например, согласования).
Улучшенные исключения в терминале: Теперь в терминале отображаются чистые и читаемые трассировки исключений вместо подробных HTML-дампов.
Общая директория share/: Появилась новая директория для хранения данных, общих для нескольких серверов (например, кешей приложения).
Улучшенная фильтрация валют: Обработка валют стала умнее: автоматически исключаются устаревшие валюты, добавлены новые опции для валидации и отображения только актуальных.
Многошаговые формы: Введена концепция "потоков форм" (form flows) для создания многоэтапных форм с использованием привычных подходов Symfony.
Улучшенные вызываемые команды: Добавлена поддержка enum, ввода на основе DTO, интерактивных подсказок и полная совместимость с тестированием.
Вынос вспомогательных методов контроллера: Представлен новый способ использования помощников контроллера без наследования от базового класса, что упрощает создание и тестирование независимых от фреймворка контроллеров.
Улучшения атрибутов: Расширены возможности атрибутов для маршрутизации, безопасности и событий.
Улучшения класса Request: Внесены ключевые изменения, включая устаревание некоторых методов, расширенный парсинг тела запроса для большего числа HTTP-методов и более строгий контроль переопределения методов.
Улучшения для разработчиков (Часть 1): Множественные улучшения, начиная от умных помощников для форм и консоли, заканчивая лучшей отладкой, локализацией и конфигурацией сервисов.
Улучшения для разработчиков (Часть 2): Упрощена работа с сессиями в тестах, улучшена отладка маршрутов, повышена доступность форм и добавлена нативная интеграция с FrankenPHP.
Подпись сообщений Messenger: В компонент Messenger добавлена возможность подписи сообщений, что гарантирует их целостность до обработки.
Улучшенная PHP-конфигурация: Устаревший "текучий" (fluent) PHP-конфиг заменен на новый массивный формат с полной поддержкой автодополнения, статического анализа и динамической генерацией структур.
Расширение валидации и сериализации через PHP-атрибуты: Добавлены новые PHP-атрибуты для расширения метаданных валидации и сериализации классов, которыми вы не управляете.
Прочие улучшения (Часть 1): Более быстрый нативный HTML5-парсинг, гибкая валидация URL, улучшенная обработка заголовка Link, поддержка HTTP-метода QUERY и упрощенная конфигурация тегов ресурсов.
Прочие улучшения (Часть 2): Добавлена поддержка enum в Workflow, новые возможности контроля XML CDATA, хранилище блокировок DynamoDB, новые Doctrine-типы на основе DatePoint и явные query-параметры при генерации URL.
Прочие улучшения (Часть 3): Структурированная обработка MIME-суффиксов, поддержка Microsoft Graph для почты, обработка непереведенных сообщений, новое утверждение для email и улучшения профилировщика для запросов EventSource.
Устаревание XML-конфигурации
С момента своего появления Symfony поддерживала три формата конфигурации: PHP, YAML и XML. Все они обладали практически идентичными возможностями и производительностью, поскольку компилировались в PHP код перед запуском.
В последних версиях Symfony поддержка XML по умолчанию была отключена для пакетов и маршрутов. Для её повторной активации требовалось вручную обновить методы configureContainer() и/или configureRoutes() в файле src/Kernel.php.
В Symfony 7.4 XML-конфигурация официально объявлена устаревшей. Начиная с версии Symfony 8.0, этот формат больше не будет поддерживаться. YAML останется форматом по умолчанию, используемым Symfony и её рецептами (recipes), однако вы также можете выбрать PHP, если предпочитаете полностью кодоориентированную конфигурацию.
Для повторно используемых бандлов (bundles) XML долгое время оставался популярным форматом, так как много лет был официально рекомендуемым вариантом. Вы можете воспользоваться специальным инструментом для автоматического преобразования XML-конфигурации вашего бандла в PHP.
Параллельно с этим упразднением, Symfony 7.4 улучшает оставшиеся форматы важными новыми функциями.
Улучшенное автодополнение для YAML
JSON-схемы описывают структуру, ограничения и типы данных JSON-документов и совместимых с ним форматов, таких как YAML. В связке с поддерживающим их редактором или валидатором (например, встроенными в современные IDE вроде PHPStorm) они обеспечивают проверку в реальном времени и автодополнение.
В Symfony 7.4 появились новые схемы для конфигурации сервисов и маршрутов, а также для метаданных валидации и сериализации. Поэтому обновленные рецепты Symfony теперь включают специальную директиву $schema: в начале YAML-файлов, которая указывает на соответствующую схему. Это позволяет среде разработки "понимать" структуру конфигурационного файла и помогать вам при его редактировании.
Расширенные массивы (Array Shapes) для PHP
Мы также исследуем новые способы сделать PHP-конфигурацию более выразительной. В Symfony 7.4 мы представляем расширенные структуры массивов (array shapes). Они позволяют конфигурировать приложение, используя структуры, похожие на YAML, но написанные на чистом PHP.
Это позволяет определять маршруты в PHP в виде ассоциативного массива, где ключ — это имя маршрута, а значение — его параметры. Аналогичным образом можно описывать и другую конфигурацию, например, для пакетов: в виде вложенного массива с названием бандла в качестве ключа и его настройками в качестве значения.
Эти структурированные массивы могут использоваться статическими анализаторами и IDE для предоставления более качественной информации и автодополнения, хотя конечный опыт будет зависеть от возможностей вашего редактора кода.
Улучшения механизма Security Voter
Symfony уже предоставляет функции Twig is_granted() и is_granted_for_user(), позволяющие проверять права доступа с помощью voters прямо в шаблонах. Эти функции возвращают логическое значение (true/false), указывающее, имеет ли текущий или указанный пользователь запрашиваемый атрибут безопасности.
В Symfony 7.4 добавляются две новые функции Twig: access_decision() и access_decision_for_user(). Вместо простого булева значения они возвращают объект AccessDecision. Этот объект (DTO) хранит в себе итоговое решение о доступе, коллекцию всех отдельных "голосов" (votes), результирующее сообщение (например, "Доступ разрешен" или пользовательское сообщение об отказе) и другую вспомогательную информацию.
На практике это позволяет в шаблоне не только узнать, разрешен ли доступ, но и получить детализированную причину решения. Например, можно проверить решение, а затем безопасно отобразить для конечного пользователя связанное с ним сообщение, если доступ запрещен.
Добавление метаданных к объектам Vote
В Symfony 7.3 был представлен объект Vote как часть функционала, объясняющего решения voters. В Symfony 7.4 его возможности расширены: теперь к каждому голосу можно прикрепить произвольные метаданные.
Внутри вашего security voter используйте свойство extraData объекта Vote, чтобы добавить любое пользовательское значение. Это значение может быть любого типа, а не только строковым.
Эта новая возможность особенно полезна при определении пользовательской стратегии принятия решений о доступе. По умолчанию голос в Symfony может только разрешить, запретить или воздержаться, и все голоса имеют равный вес. В пользовательской стратегии вы можете, например, присвоить каждому голосу оценку или вес (например, $vote->extraData['score'] = 10;) и использовать это значение при агрегации итоговых результатов.
Таким образом, вы получаете гибкий инструмент для реализации сложной логики принятия решений, где разные voters могут вносить различный вклад в окончательный вердикт на основе переданных метаданных.
Улучшения компонента Uid
Компонент Uid предоставляет утилиты для работы с уникальными идентификаторами, такими как UUID и ULID. В Symfony 7.4 было добавлено несколько новых функций, связанных с UUID.
UUID v7 по умолчанию
UUID v7 — это недавнее дополнение к спецификации UUID, которое генерирует идентификаторы, упорядоченные по времени, на основе высокоточного таймстампа Unix. Это улучшенная версия по сравнению с UUID v1 и v6, и теперь она является рекомендуемым вариантом вместо этих устаревших версий.
Начиная с Symfony 7.4, UUID v7 используется по умолчанию при создании значений через фабрику (UuidFactory). Это означает, что при вызове методов для создания нового UUID или timestamp-based UUID будет генерироваться именно седьмая версия.
Если вам необходима генерация другой версии UUID, вы можете настроить значения по умолчанию в конфигурации фреймворка, указав нужные номера версий для обычных и временных UUID.
Добавление микросекундной точности для UUID v7
Временная составляющая значений UUID v7 обеспечивает точность до миллисекунды. Однако спецификация UUID упоминает, что возможно использование дополнительной точности часов для обеспечения порядка значений с точностью выше миллисекунды.
В Symfony 7.4 мы обновили генерацию UUID v7, включив в неё микросекундную точность. Вам не нужно ничего делать, чтобы воспользоваться этим нововведением. Просто обновитесь до Symfony 7.4, и любые новые создаваемые UUID будут иметь эту повышенную точность. Это также принесло приятный бонус в виде повышения производительности — время генерации сократилось на 10%.
Тестовая фабрика для UUID
Многие версии UUID включают случайные или зависящие от времени части, что затрудняет их использование в тестах. В Symfony 7.4 мы представляем MockUuidFactory, чтобы сделать ваши UUID предсказуемыми и воспроизводимыми в тестовой среде.
Во-первых, сервисы, использующие UUID, должны зависеть от фабрики UuidFactory для их создания. Это означает, что вместо прямого вызова конструктора UUID, сервис получает фабрику через внедрение зависимости и использует её.
Затем, при тестировании таких сервисов, вы можете использовать MockUuidFactory. Вы передаёте ей заранее определённый список UUID, которые будут последовательно возвращаться при каждом вызове метода создания нового идентификатора. Это позволяет вам точно знать, какое значение будет сгенерировано, и делать детерминированные проверки (assertions) в тестах.
Кроме метода create(), мок-фабрика также поддерживает методы randomBased(), timeBased() и nameBased(). Вы также можете смешивать разные версии UUID в списке возвращаемых значений для более сложных сценариев тестирования.
Кеширование HTTP-клиента
Компонент HttpClient предоставляет функцию кеширования для предотвращения повторных HTTP-запросов к одному и тому же контенту. Ранее внутри использовался класс HttpCache из компонента HttpKernel.
В Symfony 7.4 мы переработали эту функцию, чтобы отказаться от HttpCache, основать кеширование на компоненте Cache и сделать реализацию полностью соответствующей стандарту RFC 9111.
Настройка кеширования
Процесс настройки стал проще и интегрированным. Вот как это работает:
1. Определите пул кеша (cache pool) с адаптером, поддерживающим теги (tag-aware). Это делается в конфигурации фреймворка. Например, можно использовать Redis.
2. Добавьте новую опцию caching в конфигурацию своего HTTP-клиента. В этой опции укажите, какой пул кеша следует использовать.
После этой настройки все запросы, отправленные с помощью данного клиента, будут автоматически кешироваться в соответствии со стандартом RFC 9111. Это означает, что клиент будет интеллектуально учитывать заголовки кеширования от сервера (как, например, Cache-Control), обеспечивая корректное поведение.
Дополнительные параметры
Опция caching принимает два дополнительных ключа для тонкой настройки:
shared: Если установлено значение true (по умолчанию), клиент использует общий кеш. Это позволяет повторно использовать закешированные ответы между разными пользователями, что повышает эффективность.
max_ttl: По умолчанию ответы хранятся в кеше столько времени, сколько указано сервером в заголовке TTL (Time to Live). Эта опция позволяет установить верхний предел для этого времени, ограничивая срок жизни записей в кеше заданным значением.
Таким образом, нововведение предлагает более современный, стандартизированный и удобный способ организации HTTP-кеширования на стороне клиента, встроенный прямо в конфигурацию Symfony.
Ограничение Video для валидации
Компонент Symfony Validator предоставляет десятки встроенных ограничений (constraints) для проверки данных любого типа. В Symfony 7.4 добавлено новое ограничение Video, предназначенное для валидации видеофайлов.
Ограничение Video работает аналогично существующему ограничению Image, но специально разработано для видеофайлов и включает соответствующие опции проверки. Перед его использованием необходимо установить FFmpeg, который предоставляет инструмент ffprobe, используемый для извлечения и анализа метаданных видео.
Это ограничение позволяет накладывать требования к следующим параметрам:
Размеры и пропорции: ширина, высота, количество пикселей, соотношение сторон.
Технические характеристики: видеокодек, контейнер (формат файла).
Ориентация: можно разрешить или запретить альбомные (landscape), портретные (portrait) или квадратные (square) видео.
Прочие параметры: максимальный размер файла, допустимые MIME-типы.
Например, с его помощью можно гарантировать, что загружаемое видео соответствует стандарту Full HD (1080p), не превышает размер в 100 мегабайт и имеет формат MP4 или WebM.
По умолчанию ограничение принимает распространенные видеокодеки (H.264, HEVC, VP9, AV1) и форматы контейнеров (MP4, WebM, MKV). Однако вы можете гибко настроить эти списки, указав только те кодеки и контейнеры, которые соответствуют вашим конкретным требованиям.
Таким образом, новое ограничение предоставляет мощный и детализированный инструмент для контроля качества и соответствия видеофайлов, загружаемых в ваше приложение.
Взвешенные переходы в Workflow
Компонент Workflow в Symfony моделирует бизнес-процессы как последовательность мест (местоположений или шагов), соединенных переходами (действиями, перемещающими объект между местами). Прогресс объекта отслеживается через "отметку" (marking), которая фиксирует, в каких местах он находится.
Ключевое отличие Workflow от State Machine в том, что объект может находиться в нескольких местах одновременно. Это полезно для моделирования параллельных процессов. Однако до сих пор каждое место могло лишь фиксировать факт присутствия объекта, как бинарный флаг.
Symfony 7.4 вводит концепцию кратности (multiplicity) с помощью взвешенных переходов. Теперь место может отслеживать, сколько раз объект в нем находится. Это незаменимо, когда для продолжения процесса требуется несколько экземпляров чего-либо: например, «собрать 4 ножки перед сборкой стола» или «дождаться 3 согласований перед публикацией».
Как работают взвешенные переходы
Переходу можно назначить "вес", определяющий количество требуемых или производимых экземпляров:
- Вес на выходе (to): переход помещает объект в целевое место N раз.
- Вес на входе (from): переход требует, чтобы объект находился в исходном месте N раз, прежде чем его можно будет выполнить.
Без указания веса каждый переход по умолчанию потребляет или создает ровно один экземпляр на место.
Пример: Сборка стола
Рассмотрим workflow для сборки стола. Нужно 4 ножки, 1 столешница, а также нужно отслеживать время.
Логика процесса:
- Начальный переход
startпомещает объект в состояниеprepare_leg4 раза (для ножек), вprepare_top1 раз (для столешницы) и вstopwatch_running1 раз (для таймера). - Каждый переход
build_legзабирает один экземпляр изprepare_legи добавляет один вleg_created. Его нужно выполнить ровно 4 раза. - Переход
build_topсоздает одну столешницу. - Финальный переход
joinтребует, чтобы объект находился вleg_createdровно 4 раза, и по одному разу в остальных необходимых местах (top_created,stopwatch_running). Только тогда сборка будет завершена.
Что это дает: Система создает точку синхронизации. Вы не сможете перейти к сборке, пока все необходимые компоненты не достигнут заданного количества. Workflow автоматически обеспечивает эти структурные ограничения на уровне модели, делая процесс надежным и предсказуемым.
Улучшенный вывод исключений в терминале
При запуске Symfony-приложений в режиме отладки исключения отображаются в браузере на удобной странице с подробной трассировкой стека и инструментами для мгновенной диагностики проблем.
Однако при возникновении исключения в консоли (например, во время запуска тестов) эта же HTML-страница всегда выводилась прямо в терминал. Вместо чистого, читаемого сообщения об ошибке разработчики видели сотни строк сырого HTML, CSS и JavaScript, что захламляло вывод и сильно затрудняло анализ.
Долгое время это было одной из самых неприятных особенностей процесса тестирования в Symfony. Предыдущие версии пытались смягчить проблему, добавляя основное сообщение об исключении в виде HTML-комментариев в начало и конец вывода, но это не решало её кардинально.
В Symfony 7.4 эта проблема наконец исправлена. Теперь исключения в терминале отображаются в виде чистых, читаемых текстовых трассировок стека — именно так, как этого и следовало ожидать.
Symfony 7.4 автоматически выбирает подходящий механизм рендеринга ошибок в зависимости от среды выполнения. Технически, для принятия решения о том, когда рендерить ошибку как HTML, а когда как обычный текст, используется параметр kernel.runtime_mode.
Это значение устанавливается автоматически на основе контекста выполнения (браузер или консоль), но вы также можете контролировать его явно, задав переменную окружения APP_RUNTIME_MODE. Это нововведение значительно улучшает опыт разработки и отладки при работе через командную строку.
Общая директория Share Directory
Symfony хранит кеши двух типов в директории var/cache/: системный и прикладной. Однако в архитектурах с несколькими серверами у этих типов кеша возникают противоречивые требования:
- Системный кеш (скомпилированный контейнер, маршруты, оптимизированные классы и т.д.) должен быть локальным для каждого сервера для максимальной производительности. Его не нужно синхронизировать между серверами, так как он идентичен на всех экземплярах.
- Прикладной кеш (например, пулы
cache.app) должен быть общим для всех серверов в кластере, чтобы поддерживать консистентность данных.
Текущее распространенное решение — монтировать всю директорию var/cache/ на общее сетевое хранилище (NFS, EFS и т.п.). Это работает, но снижает производительность, поскольку заставляет быстрый системный кеш использовать медленное сетевое хранилище вместо быстрых локальных дисков.
В Symfony 7.4 мы представляем новую концепцию, решающую эту проблему: директорию share/. Это специальная директория для данных, которые должны быть общими между серверами.
Доступ к этой новой директории можно получить через:
- Новый метод
KernelInterface::getShareDir(). - Новую переменную окружения
APP_SHARE_DIR. - Новый параметр контейнера
%kernel.share_dir%.
Для обеспечения обратной совместимости метод getShareDir() по умолчанию возвращает то же значение, что и getCacheDir(). Однако в новых приложениях Symfony 7.4 в файле .env будет определена отдельная переменная, например: APP_SHARE_DIR=$APP_PROJECT_DIR/var/share.
Что изменится: Все пулы кеша, производные от адаптера app (cache.app), теперь по умолчанию будут хранить свои данные в %kernel.share_dir%/pools/app, а не в %kernel.cache_dir%/pools/app.
Назначение директории: Директория share/ не ограничивается только пулами кеша. Она предназначена для любых данных, общих для всех фронтенд-серверов в кластере. Например:
var/share/pools/— прикладные пулы кеширования.var/share/http_cache/— хранилище HTTP-кеша.var/share/storage/— локальное хранилище Flysystem.var/share/db/— SQLite базы данных.
Это разделение позволяет оптимизировать производительность, храня системный кеш локально, а общие данные — в доступном всем серверам месте.
Улучшенная фильтрация валют
По умолчанию класс Currencies из компонента Intl и поле формы CurrencyType отображают все валюты, определённые стандартом ISO 4217.
Этот список включает устаревшие валюты, такие как немецкая марка или ирландский фунт, которые были заменены евро десятилетия назад. Для электронной коммерции или платежных приложений показ вышедших из обращения валют не имеет смысла и создает плохой пользовательский опыт.
Symfony 7.4 решает эту проблему, скрывая устаревшие валюты по умолчанию и вводя новые методы для проверки и фильтрации валют на основе их статуса законного платежного средства и временных периодов действия.
Новые помощники в Intl
Класс Currencies теперь включает методы для фильтрации валют по стране и дате, используя метаданные ICU для определения их статуса и периода обращения:
Currencies::forCountry()— позволяет получить все активные и законные валюты для заданной страны на сегодняшний день или на конкретную историческую дату.Currencies::isValidInCountry()— проверяет, действительна ли конкретная валюта для указанной страны.
Например, можно легко получить список всех валют, которые были в обращении в Испании 1 января 1982 года, или проверить, является ли швейцарский франк (CHF) действительной валютой для Швейцарии.
Новые опции для типа формы CurrencyType
Поле формы выбора валюты теперь включает три новые опции для фильтрации отображаемого списка:
legal_tender(по умолчаниюtrueв 7.4): Определяет, показывать ли только законные платежные средства (true), только незаконные (false) или все валюты (null).active_at: Показывает только валюты, находившиеся в обращении на конкретную дату.not_active_at: Показывает только валюты, вышедшие из обращения на конкретную дату.
Эти опции позволяют легко создавать селекторы валют, которые показывают пользователям только релевантные и актуальные варианты, адаптированные под конкретную страну или исторический период, значительно улучшая UX форм.
Многошаговые формы (Form Flows)
Формы Symfony — это проверенная временем функция для создания даже самых сложных форм. Они предоставляют десятки встроенных типов полей, расширенную валидацию, события для динамического поведения, поддержку вложенных коллекций полей и многое другое.
В Symfony 7.4 мы улучшаем формы, представляя концепцию многошаговых форм (Form Flows). Это позволяет разбивать большие формы на меньшие, связанные между собой этапы, по которым пользователь может перемещаться, пока процесс не будет завершен.
Основные принципы Form Flows
Эти новые многошаговые формы называются "потоками форм" (form flows) и следуют тем же основным концепциям, что и обычные формы. Рассмотрим приложение, которое определяет класс UserSignUp для данных нового пользователя. Трехэтапная форма регистрации создается следующим образом:
- Вместо расширения базового класса
AbstractTypeтеперь используетсяAbstractFlowType. - Вместо метода
buildForm()используетсяbuildFormFlow(). - Каждый шаг формы определяется как независимая, обычная форма Symfony. Затем он добавляется в поток с помощью метода
addStep()с указанием уникального имени. - В конфигурации можно указать свойство объекта данных (например,
currentStep), в котором будет автоматически храниться имя текущего активного шага.
Обработка в контроллере
Создание и обработка такой многошаговой формы в контроллере практически не отличается от работы с обычной формой. Ключевых отличий всего два:
- Необходима дополнительная проверка
$flow->isFinished(), чтобы узнать, когда форма завершена (например, пользователь нажал финальную кнопку отправки). - При рендеринге необходимо вызвать
$flow->getStepForm(), чтобы получить объект формы для текущего шага.
Валидация по шагам
Form Flows вводят полезное соглашение для валидации: они автоматически устанавливают имя текущего шага в качестве активной группы валидации. Это позволяет применять ограничения валидации только к данным текущего этапа, используя атрибут Valid с параметром groups.
Навигация между шагами
Навигацией управляют специальные типы кнопок, которые расширяют ButtonFlowType:
ResetFlowType— сбрасывает форму в начальное состояние.PreviousFlowType— возвращает на предыдущий шаг.NextFlowType— переходит к следующему шагу.FinishFlowType— завершает процесс и помечает форму как завершенную.
Эти кнопки поддерживают опции вроде skip, back_to, include_if и clear_submission, что позволяет реализовывать условные шаги, сложную навигацию и нелинейные сценарии.
Таким образом, Form Flows предоставляют мощный, но знакомый инструмент для создания сложных многоэтапных процессов, таких как регистрация, оформление заказа или многошаговые опросы, с сохранением всех преимуществ экосистемы форм Symfony.
Улучшенные вызываемые команды (Invokable Commands)
Вызываемые команды (invokable commands) и input-атрибуты были одними из самых популярных и важных функций, представленных в Symfony 7.3. В Symfony 7.4 мы улучшили их в нескольких аспектах.
Поддержка Enum в вызываемых командах
Типы атрибутов #[Argument] и #[Option] теперь могут быть типизированными перечислениями (backed enums). Строковый ввод, предоставленный пользователем, автоматически преобразуется в соответствующий вариант enum. Если ввод не соответствует ни одному допустимому значению, Symfony отображает понятное сообщение об ошибке со списком возможных вариантов.
Например, можно определить enum для региона облака и размера сервера, а затем использовать их в качестве типов аргументов и опций команды. Это обеспечивает строгую типизацию и автоматическую валидацию на уровне консоли.
Новый атрибут MapInput
Когда команда определяет множество аргументов и/или опций, её метод __invoke() может выглядеть перегруженным. В Symfony 7.4 мы представляем новый атрибут #[MapInput].
Его можно применить к DTO-классу, в котором вы определяете все аргументы и опции команды (с помощью уже знакомых #[Argument] и #[Option]). Затем в метод __invoke() команды передается только один параметр, аннотированный #[MapInput], содержащий этот DTO. Это делает сигнатуру метода чище и улучшает организацию кода. DTO можно даже вкладывать друг в друга.
Поддержка вызываемых команд в тестах
Класс CommandTester упрощает тестирование команд, используя специальные классы ввода и вывода. В Symfony 7.4 мы обновили его, чтобы обеспечить полную совместимость со всеми новыми функциями вызываемых команд, включая работу с enum и DTO.
Интерактивные вызываемые команды
Symfony команды предоставляют интерактивные функции, такие как запрос недостающих аргументов, повторный ввод при ошибках и т.д. В Symfony 7.4 мы расширили вызываемые команды, включив в них интерактивные возможности через два новых атрибута: #[Interact] и #[Ask].
#[Interact] можно применить к любому нестатическому публичному методу команды. Этот метод будет вызываться в интерактивном режиме, избавляя от необходимости создавать метод с фиксированным именем interact(). Сигнатура метода стала более гибкой.
#[Ask] делает интерактивность ещё лаконичнее. Этот атрибут можно добавить прямо к аргументу или опции (или к свойству DTO). Если значение не было предоставлено, Symfony автоматически задаст пользователю указанный в атрибуте вопрос. Это позволяет реализовать простые запросы данных буквально в одну строку, без написания отдельного метода.
Эти улучшения делают создание консольных команд в Symfony ещё более выразительным, типобезопасным и удобным для разработки и тестирования.
Отделимые помощники контроллера (Controller Helpers)
Контроллеры в Symfony-приложениях часто наследуются от базового класса AbstractController, чтобы использовать удобные сокращения, такие как render(), redirectToRoute(), addFlash() и другие. Это популярный подход, так как он прост и продуктивен. Однако если вы предпочитаете писать контроллеры, не зависящие от фреймворка, Symfony 7.4 представляет новую функцию, которая делает это проще, чем когда-либо.
Введение ControllerHelper
Symfony 7.4 вводит новый класс ControllerHelper. Он предоставляет все вспомогательные методы из AbstractController в виде отдельных публичных методов. Это позволяет использовать эти помощники без наследования от базового контроллера.
Вместо этого вы можете внедрить только те конкретные методы-помощники, которые нужны вашему контроллеру, используя новый атрибут #[AutowireMethodOf]. Например, можно внедрить замыкания (closures) для рендеринга шаблонов и перенаправления.
Этот подход дает вам:
- Точный контроль над зависимостями (внедряются только нужные методы).
- Лучшую тестируемость (легко подменить конкретный помощник в тестах).
- Меньший граф зависимостей.
Работа с интерфейсами
Замыкания — это хорошо, но Symfony 7.4 идет дальше. Вы можете использовать интерфейсы для описания сигнатур методов-помощников и внедрять их напрямую. Это обеспечит статический анализ и автодополнение в вашей IDE без написания лишнего кода.
Например, можно создать интерфейс RenderInterface с методом __invoke(), сигнатура которого повторяет сигнатуру помощника render(). Затем, используя тот же атрибут #[AutowireMethodOf], внедрить реализацию этого интерфейса в контроллер. Symfony автоматически создаст нужный объект.
Для кого это предназначено?
Большинству приложений следует продолжать использовать AbstractController как обычно — это простой и выразительный подход. Новый ControllerHelper предназначен для продвинутой архитектуры, которая ценит слабую связанность (decoupling) и чистоту кода.
Примечательно, что эта стратегия не ограничивается контроллерами. Например, её можно применить к репозиториям Doctrine: вместо внедрения полного сервиса репозитория можно внедрить отдельные функции запросов, используя тот же атрибут #[AutowireMethodOf].
Улучшения атрибутов
PHP-атрибуты позволяют определять структурированные метаданные прямо в коде, рядом с классами, методами или свойствами, которые они настраивают. Хотя их использование в Symfony опционально, они значительно улучшают опыт разработки. Поэтому каждая новая версия Symfony добавляет новые атрибуты и улучшает существующие.
Объединенные типы в #[CurrentUser]
Атрибут #[CurrentUser] используется в аргументах контроллера для получения текущего аутентифицированного пользователя. В Symfony 7.4 его улучшили, добавив поддержку объединенных типов (union types). Это позволяет вашему контроллеру работать с несколькими возможными типами пользователей (например, AdminUser|Customer), что удобно в системах с разными ролями.
Несколько сред в #[Route]
Атрибут #[Route] позволяет определять маршруты прямо в методах контроллера. Опция env ограничивает действие маршрута определёнными средами конфигурации (например, dev, test, prod). В Symfony 7.4 эта опция теперь поддерживает список сред, что полезно для создания маршрутов, доступных, например, только в средах разработки и тестирования или только на staging и production.
Повторяемый #[AsDecorator]
Атрибут #[AsDecorator] помогает настроить, как один сервис декорирует другой, используя паттерн "Декоратор". В Symfony 7.4 этот атрибут стал повторяемым (repeatable). Теперь один класс может декорировать несколько других сервисов, просто добавив несколько атрибутов #[AsDecorator] с разными именами сервисов. Это упрощает создание универсальных декораторов (например, логирующих клиентов для разных API).
Объединенные типы в #[AsEventListener]
Атрибут #[AsEventListener] настраивает слушателей событий прямо на их классах. Когда метод слушателя указывает ожидаемый тип события, можно опустить аргумент события в атрибуте. В Symfony 7.4 в этих сигнатурах методов теперь поддерживаются объединенные типы. Это позволяет одному методу обрабатывать события нескольких типов, что делает код гибче.
Опция methods в #[IsGranted]
Атрибут #[IsGranted] выполняет проверки прав доступа перед выполнением кода. В Symfony 7.4 он получил новую опцию methods, которая позволяет ограничить проверку определёнными HTTP-методами. Если метод текущего запроса совпадает с одним из настроенных, проверка выполняется; в противном случае атрибут игнорируется. Это удобно для тонкой настройки доступа к одним и тем же endpoint'ам для разных методов.
Авторегистрация атрибутов Route
Symfony по умолчанию загружает все атрибуты #[Route] из директории контроллеров. В Symfony 7.4 мы улучшили эту функцию: теперь можно использовать #[Route] в любой директории приложения. Механизм работает так: Symfony автоматически присваивает классам с этим атрибутом специальный тег, а затем компилятор собирает все такие сервисы и регистрирует их маршруты. Это упрощает конфигурацию и делает структуру проекта свободнее.
Новый атрибут #[IsSignatureValid]
Symfony предоставляет утилиты для подписи и проверки URI. В Symfony 7.4 новый атрибут #[IsSignatureValid] упрощает эту функцию, автоматически выполняя проверку подписи перед вызовом метода контроллера. Его также можно применять на уровне класса для проверки всех методов или ограничивать определёнными HTTP-методами с помощью опции methods. Это повышает безопасность с минимальными усилиями.
Улучшения класса Request
Компонент HttpFoundation предоставляет объектно-ориентированную абстракцию спецификации HTTP. Это одна из самых важных концепций при изучении Symfony, поскольку фреймворк построен вокруг модели "запрос-ответ", определяемой классами Request и Response.
В Symfony 7.4 мы внесли несколько важных изменений, связанных с классом Request.
Устаревание метода get()
Класс Request включает метод get(), который извлекает параметр, проверяя по порядку: атрибуты маршрута, GET-параметры и POST-параметры. Как только находится совпадение, метод возвращает значение и прекращает поиск.
Однако Symfony уже давно рекомендует получать эти значения напрямую через свойства attributes, query или request. В Symfony 7.4 метод Request::get() объявлен устаревшим. Начиная с Symfony 8.0, он больше не будет доступен.
Вместо него следует использовать:
$request->attributes->get('key')— если значение приходит из параметров маршрута или пользовательских атрибутов.$request->query->get('key')— для GET-параметров строки запроса.$request->request->get('key')— для данных, отправленных через POST.
Это изменение делает код более явным и понятным, устраняя неочевидное поведение приоритетов поиска.
Парсинг тела запроса для других HTTP-методов
В RESTful API часто используются HTTP-методы, такие как PUT или PATCH, с содержимым типа multipart/form-data или application/x-www-form-urlencoded. До сих пор Symfony парсил тело запроса только для POST-запросов из-за ограничений PHP.
В PHP 8.4 появилась новая функция request_parse_body(), позволяющая парсить тело для любых HTTP-методов с указанными типами контента. Поэтому Symfony 7.4 теперь также парсит тело для не-POST запросов.
На практике такие методы, как Request::createFromGlobals() (который создает объект Request из PHP-суперглобальных переменных), теперь корректно работают для POST, PUT, DELETE, PATCH и QUERY запросов. Это улучшение делает работу с API более предсказуемой и удобной.
Устаревание переопределения некоторых HTTP-методов
Поскольку браузеры поддерживают только методы GET и POST в HTML-формах, Symfony предоставляет функцию переопределения HTTP-метода (HTTP method override), позволяющую имитировать другие методы, такие как PUT или DELETE.
В Symfony 7.4, чтобы сделать приложения безопаснее по умолчанию, переопределение методов GET, HEAD, CONNECT и TRACE теперь считается устаревшим. Мы также ввели новые методы для настройки того, какие HTTP-методы можно переопределять. Например, можно явно разрешить только ['PUT', 'PATCH', 'DELETE'] или полностью запретить переопределение, установив пустой массив.
В Symfony-приложении эту настройку можно задать глобально с помощью новой опции конфигурации allowed_http_method_override в файле конфигурации фреймворка. Это повышает безопасность, предотвращая нежелательное изменение критичных методов запроса.
Улучшения для разработчиков (Developer Experience - DX)
Developer Experience (DX) описывает, насколько гладко и эффективно работать с фреймворком или инструментом. В Symfony 7.4 мы добавили множество небольших улучшений DX, и этот пост освещает некоторые из них.
Таймаут для Question Helper
Помощник Question из компонента Console предоставляет утилиты для запроса ввода от пользователя. В Symfony 7.4 теперь можно установить таймаут для вопросов. Если пользователь не ответит в течение заданного времени, будет выброшено исключение MissingInputException. Это полезно для интерактивных скриптов, требующих реакции.
Угадыватель типа Enum для форм
Компонент Form использует "угадыватели типов" для автоматического выбора типа поля, если он не указан явно. В Symfony 7.4 добавлен новый угадыватель для PHP-перечислений (enum). Symfony будет автоматически использовать тип EnumType с правильной настройкой класса при обнаружении поля-перечисления.
Новая команда для генерации OIDC токенов
В Symfony 6.3 был представлен обработчик токенов OpenID Connect. В Symfony 7.4 добавлена команда для генерации JWT токенов, что полезно для тестирования и разработки. Она позволяет быстро создать токен с заданными параметрами.
Локаль по умолчанию вне HTTP-контекста
При генерации URL вне контекста HTTP (например, в командах) возникают сложности с определением локали. В Symfony 7.4 параметр kernel.default_locale теперь также используется как локаль по умолчанию при генерации URL вне HTTP-запросов.
Новые помощники для BrowserKit
Компонент BrowserKit симулирует поведение веб-браузера. В Symfony 7.4 добавлены два новых метода:
isFirstPage() — возвращает true, если текущая позиция в начале истории.
isLastPage() — возвращает true, если текущая позиция в конце истории.
- Для удобства тестирования добавлены соответствующие PHPUnit-утверждения, такие как
assertBrowserHistoryIsOnFirstPage().
Улучшенные дампы в не-HTML контекстах
Подобно улучшенным исключениям в терминале, функции dd() и dump() теперь рендерят HTML только тогда, когда запрос содержит HTTP-заголовок Accept со значением html. Во всех остальных случаях (отладка API, вывод в терминал) дампы выводятся как обычный текст.
Упрощение Target-атрибутов
Атрибут #[Target] помогает выбрать конкретную реализацию одного типа для внедрения. В Symfony 7.4 упростили задание его значений: теперь можно использовать те же имена, что и в конфигурационных файлах, без добавления лишних суффиксов, основанных на типе сервиса.
Подготовка сессии в функциональных тестах
Клиент, используемый в функциональных тестах, теперь включает метод getSession(), который возвращает объект сессии. Это позволяет заранее устанавливать в ней данные, необходимые для тестов: CSRF-токены, настройки пользователя, данные A/B-тестирования и т.д., делая тесты более гибкими.
Улучшенная отладка маршрутов
Команда debug:router улучшена:
Колонки Scheme и Host отображаются только тогда, когда их значения отличаются от ANY, что делает вывод чище.
Колонка Method теперь отображает HTTP-методы в цвете, следуя общепринятым соглашениям (например, синий для GET, желтый для POST).
Лучшая доступность форм
В Symfony 7.4 поля форм с ошибками валидации теперь автоматически включают корректные атрибуты aria-invalid и aria-describedby в соответствии с требованиями доступности WCAG 2.1. Это повышает удобство использования для людей с ограниченными возможностями без изменений в вашем коде.
Мокирование функции strtotime()
PHPUnit Bridge предоставляет класс ClockMock для мокирования встроенных PHP-функций времени. В Symfony 7.4 в этот список добавлена функция strtotime(), что позволяет мокировать её в тестах.
Больше точности при обработке сообщений Messenger
У команды messenger:consume появилась новая опция --exclude-receivers. Она используется вместе с --all, чтобы исключить определенные получатели (например, очереди с ошибками) при потреблении сообщений со всех остальных.
Автоматическая интеграция с режимом Worker FrankenPHP
FrankenPHP — это современный высокопроизводительный PHP-сервер приложений. Symfony 7.4 улучшает интеграцию с его режимом Worker, при котором приложение загружается один раз и хранится в памяти для огромного прироста производительности. Больше не нужно устанавливать отдельный пакет runtime/frankenphp-symfony — Symfony 7.4 имеет нативную поддержку этого режима.
Подпись сообщений
Компонент Symfony Messenger определяет транспорты для отправки и получения сообщений, часто через системы очередей, такие как Doctrine, Redis, Amazon SQS, Beanstalkd или AMQP.
Если эти системы очередей недостаточно защищены, злоумышленник может внедрить поддельные сообщения в очередь. Это особенно опасно для сообщений, которые запускают выполнение команд или процессов.
Хотя защита инфраструктуры не является прямой обязанностью Symfony, в Symfony 7.4 добавлен новый уровень защиты. Теперь сообщения можно криптографически подписывать, чтобы обнаруживать и отклонять любые из них, которые были изменены.
Как включить подпись сообщений
Чтобы включить подпись, установите опцию sign в значение true в атрибуте #[AsMessageHandler] обработчика, который обрабатывает сообщение.
Как это работает
Когда подпись включена, каждое сообщение подписывается с использованием HMAC-подписи, вычисленной с помощью секретного ключа вашего приложения (параметр kernel.secret).
Подпись добавляется в заголовки сообщения (Body-Sign и Sign-Algo) при его отправке и автоматически проверяется при получении.
Что происходит при несовпадении подписи
Если подпись отсутствует или недействительна, выбрасывается исключение InvalidMessageSignatureException, и сообщение не будет обработано. Это предотвращает выполнение команд из поддельных или изменённых сообщений.
Таким образом, эта функция добавляет дополнительный уровень целостности и безопасности для вашей асинхронной обработки сообщений, не требуя сложной настройки.
Улучшенная PHP-конфигурация
Ещё в Symfony 5.3 (выпущенной в мае 2021 года) мы представили builder-классы конфигурации как "текучий" (fluent) PHP-интерфейс для настройки приложений. Эти классы генерировались динамически в зависимости от установленных бандлов.
В Symfony 7.4, в рамках более широкой работы по модернизации форматов конфигурации (и поскольку мы объявляем устаревшим XML), мы также объявляем устаревшими builder-классы и текучий PHP-интерфейс.
Основная причина — техническая: текучий интерфейс недостаточно гибок и должен соответствовать единственной канонической интерпретации дерева конфигурации. Это также значительно усложняет автоматическое обновление конфигурации через рецепты Symfony.
Что приходит на смену?
Мы представляем новый PHP-формат конфигурации на основе массивов. Если на первый взгляд это выглядит как "просто массивы", вы не ошибаетесь. Это просто, компактно и очень привычно: похоже на YAML, но прямо в PHP. Однако за этим стоит нечто большее.
Чтобы новый формат раскрылся в полной мере, Symfony теперь определяет структуры массивов (array shapes) для всей конфигурации. Это определения метаданных PHP, которые могут читать и обрабатывать такие инструменты, как PhpStorm, PHPStan, Psalm и другие. Это означает:
- Полное автодополнение
- Статический анализ
- Проверку типов
- Мгновенную возможность обнаружить любую опцию конфигурации
Эти структуры генерируются динамически на основе бандлов, установленных в вашем приложении. Сгенерированный файл называется reference.php и хранится в директории config/. Его следует добавить в ваш репозиторий и, опционально, добавить новую запись в секцию autoload файла composer.json.
Текущий статус
Мы ещё не готовы сделать этот новый формат рекомендуемым. YAML по-прежнему обладает многими преимуществами. Однако это обновление открывает путь к использованию PHP как конфигурационного формата первого класса в будущем.
Новый подход лаконичен, выразителен, его легко поддерживать, он хорошо поддерживается современными инструментами и использует всю мощь PHP. Что ещё не хватает? Не все статические анализаторы и IDE полностью поддерживают сложные структуры массивов, Symfony Flex пока понимает только YAML, и ещё несколько деталей нуждаются в доработке, прежде чем это видение станет реальностью. Тем не менее, это важный шаг к более унифицированному, мощному и удобному для разработчика опыту конфигурации в Symfony.
Расширение валидации и сериализации с помощью PHP-атрибутов
Многие приложения на Symfony используют внешние бандлы и пакеты, предоставляющие собственные классы. Когда требовалось настроить валидацию или сериализацию этих классов, приходилось переопределять их метаданные в XML или YAML-файлах, размещённых в жёстко заданных директориях конфигурации (например, config/validation/). Это работало, но ощущалось оторванным от основного кода приложения.
Symfony 7.4 представляет более элегантный подход. Теперь вы можете расширять метаданные валидации и сериализации, используя PHP-атрибуты.
Расширение метаданных валидации
Чтобы расширить метаданные валидации внешнего класса, создайте новый класс в любом месте вашего приложения и примените к нему атрибут #[ExtendsValidationFor]. Этот атрибут объявляет полное имя класса (FQCN), который вы хотите расширить.
Внутри этого класса добавьте свойства и геттеры, которые вы хотите расширить от исходного класса, используя точно такие же имена. К ним можно добавить необходимые атрибуты-ограничения валидации (например, #[Assert\NotBlank], #[Assert\Email]).
Как это работает:
- Во время компиляции контейнера Symfony собирает классы, помеченные
#[ExtendsValidationFor(Target::class)], и проверяет, существуют ли объявленные свойства/геттеры в целевом классе. Если нет — выбрасывается исключение. - Валидатор настраивается так, что целевой класс сопоставляется с вашим классом-расширением.
- Во время выполнения, при загрузке метаданных валидации для целевого класса, Symfony считывает атрибуты (ограничения, обратные вызовы, провайдеры групп) как из исходного класса, так и из вашего класса-расширения, и объединяет их.
Эти классы-расширения не предназначены для создания экземпляров. При желании их можно объявить как abstract.
Расширение метаданных сериализации
Symfony 7.4 вводит ту же идею для метаданных сериализации. Применив атрибут #[ExtendsSerializationFor] к своим классам, вы можете объявлять новые атрибуты сериализации (например, #[Groups], #[SerializedName], #[MaxDepth]) для сторонних классов, не определяя XML или YAML в директории config/serialization/.
Как и в случае с валидацией, Symfony проверяет существование свойств, а затем объединяет метаданные из исходного класса и вашего расширения во время выполнения.
Преимущества подхода
- Локализация: Конфигурация валидации/сериализации находится рядом с остальным кодом приложения, а не в отдельной директории.
- Безопасность: Проверка существования свойств предотвращает ошибки.
- Гибкость: Можно добавлять собственные группы валидации, переименовывать поля для сериализации и применять любые другие атрибуты.
- Чистота: Не нужно модифицировать код сторонних пакетов или создавать сложные конфигурационные файлы.
Это нововведение делает работу с классами из внешних зависимостей значительно более удобной и интегрированной.
Прочие улучшения
Нативный HTML5-парсер (PHP 8.4)
PHP 8.4 включает в себя нативный и полнофункциональный парсер HTML5. В предыдущих версиях Symfony использовались сторонние библиотеки. Начиная с Symfony 7.4, если ваше приложение работает на PHP 8.4 или выше, Symfony автоматически использует гораздо более быстрый нативный парсер из PHP. Никаких изменений с вашей стороны не требуется.
Разрешение любых протоколов в ограничении Url
Ограничение Url использует опцию protocols для указания допустимых протоколов. В Symfony 7.4 её улучшили: теперь можно использовать *`''**, чтобы принимать любой протокол, соответствующий спецификации RFC 3986 (например,custom://,git+ssh://`).
Парсинг заголовков Link
Некоторые API используют HTTP-заголовок Link для пагинации. В Symfony 7.4 добавлен класс HttpHeaderParser в компонент WebLink, который упрощает разбор таких заголовков и извлечение ссылок с их атрибутами (такими как rel, href).
Поддержка HTTP-метода QUERY
HTTP-метод QUERY — это предлагаемое дополнение к стандарту HTTP. Он похож на POST, но является идемпотентным и безопасным для повторения. В Symfony 7.4 добавлена поддержка QUERY в классе Request, функции HTTP-кеширования, веб-профилировщике и компоненте HttpClient.
Упрощенная конфигурация тегов ресурсов (Resource Tags)
В Symfony 7.3 были представлены теги ресурсов. В Symfony 7.4 их настройку упростили: теперь теги можно задавать напрямую в конфигурации сервисов (YAML/PHP) или с помощью нового атрибута #[AutoconfigureResourceTag].
Поддержка Enum в компоненте Workflow
Symfony 7.4 добавляет поддержку типизированных перечислений (backed enums) в компоненте Workflow. Значения enum теперь можно использовать в качестве местоположений (places), начальных состояний (initial marking) и переходов (transitions) в конфигурации workflow. Symfony автоматически преобразует enum в строковое/числовое значение при сохранении и обратно при работе с объектами.
Обертка CDATA для конкретных полей
Компонент Serializer предоставляет опцию для оборачивания содержимого полей в CDATA. В Symfony 7.4 добавлена новая опция CDATA_WRAPPING_NAME_PATTERN, позволяющая задать регулярное выражение для имен полей, которые всегда должны быть обёрнуты в CDATA, независимо от их содержимого.
Хранилище блокировок DynamoDB
DynamoDB — это полностью управляемая бессерверная NoSQL база данных от AWS. В Symfony 7.4 добавлена поддержка DynamoDB в компоненте Lock через отдельный пакет. Теперь блокировки можно хранить в DynamoDB, указав соответствующий DSN.
Новые Doctrine-типы DayPointType и TimePointType
Представлены два новых типа Doctrine: day_point и time_point. Они позволяют использовать класс DatePoint из компонента Clock для полей, содержащих только дату или только время, вместо полных datetime.
Явные query-параметры при генерации URL
Раньше параметры маршрута автоматически использовались в поддоменах или пути, что мешало передать их в строке запроса. В Symfony 7.4 введён специальный ключ _query в параметрах генерации URL. Значения, переданные в нём, всегда попадают в query-строку, даже если имя параметра совпадает с частью маршрута.
Поддержка структурированных MIME-суффиксов
Улучшен метод getFormat() класса Request. Теперь он может более точно извлекать формат из сложных MIME-типов с суффиксами (например, application/device-config+tlv → tlv). Для этого нужно передать второй параметр true.
Интеграция с Microsoft Graph для почты
Symfony уже интегрирован с 18 почтовыми сервисами. В Symfony 7.4 добавлена новая интеграция с API электронной почты Microsoft Graph.
Класс StaticMessage для непереводимых сообщений
Иногда сообщения уже переведены или должны оставаться неизменными. Новый класс StaticMessage реализует TranslatableInterface, но не выполняет перевод, возвращая исходный текст. Это полезно для сообщений, которые уже локализованы вне Symfony.
Новое утверждение assertEmailAddressNotContains для тестов
В набор вспомогательных утверждений PHPUnit для Symfony добавлен новый метод assertEmailAddressNotContains(). Он проверяет, что указанный email-адрес не содержится в заданном заголовке письма, дополняя существующий assertEmailAddressContains().
Профилирование запросов EventSource
Улучшена панель Ajax в профилировщике Symfony. Теперь она захватывает и отображает не только Ajax-запросы, но и запросы, инициированные через EventSource (Server-Sent Events). Они появляются в панели отладки как записи типа event-stream.
Опубликовано:

