Вышла новая версия Symfony 7.2
Вышла очередная минорная версия Symfony 7.2
Как и все минорные обновления Symfony поддерживает обратную совместимость.
А это означает, что вы сможете легко обновиться, ничего не меняя в своем коде.
Ниже перечислены некоторые изменения для этой версии:
Week, WordCount and Yaml Constraints
Symfony включает десятки ограничений для проверки данных в приложениях. В Symfony 7.2 добавляны три новых ограничения.
Week Constraint
Это ограничение проверяет, что заданная строка (или объект, реализующий Stringable
интерфейс PHP) представляет собой допустимый номер недели в соответствии со стандартом ISO-8601
// src/Entity/Rental.php
namespace App\Entity;
use Symfony\Component\Validator\Constraints as Assert;
class Rental
{
#[Assert\Week]
protected string $bookingWeek;
}
Это ограничение включает в себя параметры max
и min
для дальнейшего ограничения того, какие недели может выбрать пользователь:
// src/Entity/OnlineCourse.php
namespace App\Entity;
use Symfony\Component\Validator\Constraints as Assert;
class OnlineCourse
{
#[Assert\Week(min: '2022-W01', max: '2022-W20')]
protected string $startWeek;
}
Проверка того, является ли неделя действительной или нет, не так тривиальна, как кажется, поскольку в некоторых годах 53 недели вместо обычных 52. Благодаря этому новому ограничению вы теперь можете забыть об этих деталях и позволить Symfony обрабатывать логику проверки.
WordCount Constraint
Это ограничение проверяет, что строка (или объект, реализующий Stringable
интерфейс PHP) содержит количество слов, попадающее в заданный диапазон от минимума до максимума:
// src/Entity/BlogPostDTO.php
namespace App\Entity;
use Symfony\Component\Validator\Constraints as Assert;
class BlogPostDTO
{
#[Assert\WordCount(min: 100, max: 200)]
protected string $content;
}
Подсчет слов — сложная для решения проблема. Вот почему это ограничение опирается на класс IntlBreakIterator
из PHP. Это также сильно зависит от языка контента, поэтому вы можете использовать locale
опцию для определения локали контента (по умолчанию она использует ту же, что и текущая локаль приложения).
Yaml Constraint
Несмотря на свои странности, YAML остается чрезвычайно популярным языком конфигурации. Вот почему было добавлено ограничение, которое проверяет, Stringable
содержит ли данная строка (или объект) допустимый синтаксис YAML:
// src/Entity/Report.php
namespace App\Entity;
use Symfony\Component\Validator\Constraints as Assert;
class Report
{
#[Assert\Yaml(message: "Your configuration doesn't have valid YAML syntax.")]
private string $customConfiguration;
}
Вы также можете использовать любой из флагов конфигурации , определенных в компоненте Symfony Yaml
:
#[Assert\Yaml(
message: "Your configuration doesn't have valid YAML syntax.",
flags: Yaml::PARSE_CONSTANT | Yaml::PARSE_CUSTOM_TAGS | Yaml::PARSE_DATETIME,
)]
private string $customConfiguration;
Expression Language Improvements
Компонент ExpressionLanguage
предоставляет движок, который может компилировать и оценивать выражения. Основная цель компонента — позволить пользователям использовать выражения внутри конфигурации для более сложной логики. В Symfony 7.2 улучшили его новыми функциями.
Новые операторы языка выражений
Компонент ExpressionLanguage
уже поддерживает некоторые бинарные операторы: &(and)
, |(or)
и ^(xor)
. В Symfony 7.2 добавили поддержку остальных побитовых операторов: <<(сдвиг влево)
, >>(сдвиг вправо)
и ~(not)
.
Эти операторы не самые популярные, но они полезны в таких сценариях, как работа с битовыми полями внутри выражений, например, флагами компонентов Yaml
:
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
$el = new ExpressionLanguage();
$el->evaluate('1 << 4'); // result: 16
$el->evaluate('32 >> 4'); // result: 2
$el->evaluate('~5'); // result: -6
Кроме того, добавлена xor
поддержка логического оператора (этот оператор уже был доступен как бинарный оператор):
$el->evaluate('$a xor $b'); // true if either $a or $b is true, but not both
WhenNot Attribute
В Symfony 5.3 ввели атрибут #[When]
как способ ограничить службы определенными средами конфигурации:
use Symfony\Component\DependencyInjection\Attribute\When;
// this class is only registered in the "dev" environment
#[When(env: 'dev')]
class SomeClass
{
// ...
}
Это работает хорошо, но при работе с многочисленными реализациями сервисов (например, для тестов) может быть обременительно определять #[When]
атрибут для каждого сервиса. Вот почему в Symfony 7.2 был введен противоположный атрибут: #[WhenNot]
.
Этот новый атрибут позволяет исключить службу из определенных сред:
use Symfony\Component\DependencyInjection\Attribute\WhenNot;
#[WhenNot(env: 'dev')]
class SomeClass
{
// ...
}
// add the attribute multiple times to exclude it from several environments
#[WhenNot(env: 'dev')]
#[WhenNot(env: 'test')]
class AnotherClass
{
// ...
}
Lazy Choice Loader
Поле EntityType
, определенное Symfony Forms
, позволяет вам представлять все значения, хранящиеся для некоторой Doctrine Entity
, через <select>
элемент HTML или коллекцию радиокнопок или флажков. Оно расширяет поле ChoiceType
, один из самых универсальных (и сложных) типов в Symfony Forms
.
Самый большой недостаток EntityType
заключается в том, что он может вызвать проблемы с производительностью при рендеринге сущности со многими значениями. Распространенным решением является создание поля автозаполнения с использованием комбинации кода PHP и JavaScript.
В Symfony 7.2 это упрощено, LazyChoiceLoader
который реализует стратегию загрузки выбора по требованию. Вы можете использовать его в типах форм с помощью choice_lazy
опции:
$formBuilder->add('user', EntityType::class, [
'class' => User::class,
'choice_lazy' => true,
]);
Внутри этот загрузчик сохраняет список выбора пустым, пока не понадобятся значения (избегая ненужных запросов к базе данных). Когда значения формы предоставляются или отправляются, он извлекает и кэширует только необходимые варианты.
Часть frontend
, необходимая для динамического отображения вариантов выбора пользователю, по-прежнему не предоставлена. Для этого можно использовать поле автозаполнения из Symfony UX
.
String Component Improvements
Компонент String
предоставляет объектно-ориентированный API для строк и работает с байтами, кодовыми точками UTF-8 и кластерами унифицированным образом. В Symfony 7.2 компонент был улучшен новыми функциями.
Added a kebab() Method
Компонент String
уже определяет некоторые методы для изменения регистра заданных строк. Например, camel()
для использования camelCase(Foo bar->fooBar)
и snake()
для использования snake_case(Foo Bar->foo_bar)
. В Symfony 7.2 добавили kebab()
использование kebab-case
:
use function Symfony\Component\String\u;
$string = u('symfonyIsGreat')->kebab(); // $string = 'symfony-is-great'
$string = u('Symfony is great')->kebab(); // $string = 'symfony-is-great'
$string = u('Symfony_is_Great')->kebab(); // $string = 'symfony-is-great'
New Truncation Modes
Компонент String
определяет truncate()
метод с двумя режимами работы:
// by default, contents are cut to strictly meet the desired length
u('Lorem Ipsum')->truncate(8); // 'Lorem Ip'
// but you can also keep the last word entirely, even if that generates a longer string
u('Lorem Ipsum')->truncate(8, cut: false); // 'Lorem Ipsum'
В Symfony 7.2 добавлены новые режимы через TruncateMode::*
:
// the default value is TruncateMode::Char which cuts the string at the exact given length
// (this is the same as the previous default behavior)
u('Lorem ipsum dolor')->truncate(8, cut: TruncateMode::Char); // 'Lorem ip'
// returns up to the last complete word that fits in the given length without surpassing it
u('Lorem ipsum dolor')->truncate(8, cut: TruncateMode::WordBefore); // 'Lorem'
// returns up to the last complete word that fits in the given length, surpassing it if needed
// (this is the same as setting `cut: false` in the previous example)
u('Lorem ipsum dolor')->truncate(8, cut: TruncateMode::WordAfter); // 'Lorem ipsum'
Simpler Single-File Symfony Applications
Symfony позволяет создавать однофайловые приложения, которые полезны для простых воркеров, микросервисов, инструментов CLI, минимальных API и т.д. Вот пример однофайлового приложения, как оно выглядело раньше:
// index.php
use App\Generator\NumberGenerator;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
use Symfony\Component\Routing\Attribute\Route;
require __DIR__.'/vendor/autoload.php';
class Kernel extends BaseKernel
{
use MicroKernelTrait;
public function registerBundles(): array
{
return [
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
];
}
protected function configureContainer(ContainerConfigurator $container): void
{
$container->extension('framework', [
'secret' => 'S0ME_SECRET'
]);
// alternatively, define this in a configuration file and load it as:
// $container->import(__DIR__.'/../config/framework.yaml');
}
#[Route('/random/{limit}', name: 'random_number')]
public function randomNumber(int $limit, NumberGenerator $numberGenerator): JsonResponse
{
return new JsonResponse([
'number' => $numberGenerator->generate($limit),
]);
}
}
return static function (array $context) {
return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
}
В Symfony 7.2 был упрощен MicroKernelTrait
. Теперь то же самое приложение выглядит так:
// index.php
use App\Generator\NumberGenerator;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
use Symfony\Component\Routing\Attribute\Route;
require __DIR__.'/vendor/autoload.php';
class Kernel extends BaseKernel
{
use MicroKernelTrait;
#[Route('/random/{limit}', name: 'random_number')]
public function __invoke(int $limit, NumberGenerator $numberGenerator): JsonResponse
{
return new JsonResponse([
'number' => $numberGenerator->generate($limit),
]);
}
}
return static function (array $context) {
return new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
}
Изменения, внесенные в Symfony 7.2:
- Каталог
config/
теперь необязателен, поэтому вы можете полностью его опустить, если определяете конфигурацию вconfigureContainer()
методе; - Файл
bundles.php
также является необязательным, иregisterBundles()
метод теперь по умолчанию равенyield new FrameworkBundle();
. Это устраняет необходимость определять этот метод, когда не загружены другие пакеты; - Поддержка внедрения сервисов в вызываемые действия с использованием
__invoke()
метода; - Параметр
framework.secret
теперь необязателен.
Об этих и других улучшениях вы можете почитать по ссылке ниже.
Ссылка на источник: https://symfony.com/blog/symfony-7-2-0-released