Модернизация конфигурации Symfony

Источник: «Modernize Symfony Configs»
Конфигурация Symfony — одно из тех изменений, которые трудно заметить, пока они не будут удалены в следующей мажорной версии. Тогда приходится гуглить "сообщение об ошибке invalid option id" и надеяться на решение. Не самый лучший способ провести выходные, не так ли?

Оглавление

  1. Переход с YAML на PHP
  2. Переход от массива строк к типизированным PHP объектам
  3. Используйте всю мощь статического анализа

Symfony добавляет сообщения об устаревании этих опций, но заметить их не так-то просто.

Сегодня мы покажем, как обнаружить их с помощью Rector, PHPStan и ещё одного фантастического инструмента.

Symfony Security известна тем, что почти в каждой версии Symfony происходят значительные изменения. То, что работало в прошлом…

# config/security.yml
security:
enable_authenticator_manager: true

…может быть изменено или удалено.

Это не работает в Symfony 7. Мы хотим получать предупреждение заранее, как только произошло изменение, и без запуска нашего кода. Другие PHP-проекты используют @deprecation аннотации, отмечающие устаревшие методы, свойства, константы и классы прямо в коде в вашей любимой IDE.

Как насчёт YAML? В нём этого нет, поэтому сначала придётся перейти на PHP.

1. Переход с YAML на PHP

Нет необходимости возиться с ручным переходом. Используйте symplify/config-transformer, для автоматизации процесса:

composer require simplify/config-transformer --dev
vendor/bin/config-transformer switch-format config/security.yml

Он анализирует YAML, преобразует его в PHP формат и распечатывает:

# config/security.php
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;

return static function (ContainerConfigurator $containerConfigurator): void {
$containerConfigurator->extension('security', [
'enable_authenticator_manager' => true,
]);
};

Задание выполнено!

Если это ваша первая конфигурация с поддержкой PHP, не забудьте обновить Kernel для загрузки PHP-файлов.

Теперь у нас есть PHP конфиги, но на самом деле — это просто ещё одна форма массива, заполненного строками.

Symfony может работать лучше, по крайней мере, начиная с Symfony 5.3.

2. Переход от массива строк к типизированным PHP объектам

Вместо массивов мы хотим получить нечто, что можно использовать в IDE — полностью типизированные объекты с автозаполнением методов.

Вы используете Symfony 5.3+? Если нет, то сначала обновитесь с помощью Rector. После этого вы сможете использовать Config Builder Classes.

Но есть одна загвоздка — сложно рассказать о них вашей IDE и PHPStan, потому что они не являются частью кода Symfony. Они генерируются на лету, основываясь на текущей версии Symfony.

Чтобы упростить процесс генерации, воспользуйтесь инструментом tomasvotruba/symfony-config-generator, определяющим доступные классы расширений и генерирующим классы для построения конфигурации:

composer require tomasvotruba/symfony-config-generator --dev
vendor/bin/symfony-config-generator

Проверьте генерируемые классы в каталоге кэша Symfony:

/var/cache/Symfony

У нас есть классы для построения конфигураций и PHP с массивами строк.

Как перевести массивы в классы сборщика конфигурации

Rector поможет! Правила Symfony для Rector содержат одну маленькую жемчужину, помогающую на 99% автоматизировать работу — правило StringExtensionToConfigBuilderRector. Добавьте его в ваш конфиг rector.php:

# rector.php
use Rector\Config\RectorConfig;
use Rector\Symfony\CodeQuality\Rector\Closure\StringExtensionToConfigBuilderRector;

return static function (RectorConfig $rectorConfig): void {
$rectorConfig->rules([
StringExtensionToConfigBuilderRector::class,
]);
};

Затем запустите Rector с файлом конфигурации:

vendor/bin/rector p config/security.php

И вуаля — вот ваша современная конфигурация Symfony security:

# config/security.php
use Symfony\Config\SecurityConfig;

return static function (SecurityConfig $securityConfig): void {
$securityConfig->enableAuthenticatorManager(true);
};

Примечание: для некоторых элементов, таких как firewall, roles и т.д., потребуется отдельный вызов переменной — PHPStan сориентирует вас.

Вы только что увеличили ценность своих конфигов на порядок:

Чтобы PHPStan работал и не жаловался на отсутствие классов, расположенных в /var/cache, мы должны загрузить классы в конфигурацию PHPStan:

# phpstan.neon
parameters:
bootstrapFiles:
- var/cache/Symfony/Config/SecurityConfig.php
- var/cache/Symfony/Config/Security/ProviderConfig.php
- var/cache/Symfony/Config/Security/AccessControlConfig.php
- var/cache/Symfony/Config/Security/AccessDecisionManagerConfig.php
- var/cache/Symfony/Config/Security/FirewallConfig.php
- var/cache/Symfony/Config/Security/PasswordHasherConfig.php
- var/cache/Symfony/Config/Security/ProviderConfig.php

3. Используйте всю мощь статического анализа

Мы бы с удовольствием работали с проектом Symfony в такой форме, но подождите — это ещё не всё.

Что нам действительно нужно, так это получать ранние предупреждения об устаревании прямо в нашем CI до того, как мы решим обновляться. Конфиги недоступны в репозитории Symfony Github, так как они генерируются на лету.

Но когда мы посмотрим на файл в нашем проекте:

var/cache/Symfony/Config/SecurityConfig.php

Мы увидим, что метод enableAuthenticatorManager() фактически устарел в Symfony 6.4:

    /**
* @default true
* @param ParamConfigurator|bool $value
* @deprecated The "enable_authenticator_manager" option at "security" is deprecated.
* @return $this
*/

public function enableAuthenticatorManager($value): static
{
// ...
}

Теперь у нас есть:

Но этого недостаточно, чтобы позволить CI помочь нам. Одной детали не хватает… хотите угадать?

PHPStan предоставляет расширение, сообщающее о @deprecated элементах прямо в CI:

composer require phpstan/phpstan-deprecation-rules --dev

Примечание: установите phpstan/extension-installer, если у вас его ещё нет:

composer require phpstan/extension-installer --dev

Давайте запустим PHPStan с нашим конфигом и посмотрим результат:

vendor/bin/phpstan a config/security.php

PHPStan завершится неудачей и сообщит нам об этом:

1/1 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%

------ -------------------------------------------------------------------------
Line config.php
------ -------------------------------------------------------------------------
8 Call to deprecated method enableAuthenticatorManager()
of class Symfony\Config\SecurityConfig:
The "enable_authenticator_manager" option at "security" is deprecated.
------ -------------------------------------------------------------------------

Теперь вы защищены и можете приступать к исправлению устареваний, пока они не исчезли совсем.

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

Счастливого кодинга!

Дополнительные материалы

Предыдущая Статья

Инъекция зависимостей в командах Laravel Artisan

Следующая Статья

Функциональное программирование в JavaScript