Обновление стороннего пакета до старшей версии Symfony

Дата обновления перевода 2023-06-30

Обновление стороннего пакета до старшей версии Symfony

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

Разрешение на установку компонентов Symfony 3

БОльшинство сторонних пакетов определяют свои зависимости Symfony, используя ограничения ~2.N или ^2.N в файле composer.json. Например:

1
2
3
4
5
6
7
{
    "require": {
        "symfony/framework-bundle": "~2.7",
        "symfony/finder": "~2.7",
        "symfony/validator": "~2.7"
    }
}

Эти ограничения предотвращают использование пакетом компонентов Symfony 3, так что становится невозможно установить его в приложение, основанное на Symfony 3. Эту проблему очень легко решить благодаря гибкости ограничений зависимости Композера (Composer). Просто замените ~2.N на ~2.N|~3.0 (или ^2.N на ^2.N|~3.0).

Вышеописанный пример можно обновить так, чтобы он работал с Symfony 3 следующим образом:

1
2
3
4
5
6
7
{
    "require": {
        "symfony/framework-bundle": "~2.7|~3.0",
        "symfony/finder": "~2.7|~3.0",
        "symfony/validator": "~2.7|~3.0"
    }
}

Tip

Еще одним общим ограничением версий, которое часто бывает в сторонних пакетах, является >=2.N. Вы должны избегать использования этого ограничения, потому что оно слишком общее (что означает, что ваш пакет совместим с любой последующей версией Symfony). Используйте вместо этого ~2.N|~3.0 или ^2.N|~3.0, чтобы укрепить ваш пакет для будущего.

Ищите устаревания и исправляйте их

Кроме того, чтоб позволить пользователям испгользовать ваш пакет в Symfony 3, ваш пакет должен перестать использовать любые функции, устаревшие в версии 2.8, потому что в версии 3.0 они были удалены (вы будете получать исключения или PHP-ошибки). Наиболее лёгким способом определить устаревания является установка symfony/phpunit-bridge package и последующий запуск набора тестов.

Для начала, установите компонент в качестве зависимости dev вашего пакета:

1
$ composer require --dev symfony/phpunit-bridge

Потом, запустите ваш набор тестов и ищите перечень устареваний, отображённый после отчета о тестировании PHPUnit:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# эта команда доступна после запуска "composer require --dev symfony/phpunit-bridge"
$ ./bin/phpunit

# ... вывод PHPUnit

Оставшиеся уведомления об устареваниях (3)

Опция "шаблон" (pattern) в файле ... устарела в версии 2.2 и будет удалена в версии
3.0. Используйте опцию "путь" (path) в определении маршрута вместо этого ...

Функция Twig "form_enctype" устарела. Вместо неё используйте "form_start" в ...

Класс Symfony\Component\Security\Core\SecurityContext устарел в версии 2.6 и будет
удалён в версии 3.0. Используйте ...

Исправьте найденные устаревания, запустите набор тестов снова и повторяйте процесс до тех пор, пока не получите отчёт без устареваний.

Полезные ресурсы

Существует несколько ресурсов, которые могут помочь вам найти, понять и исправить использование устаревших функций:

Официальное руководство Symfony по обновлению с версий 2.x до 3.0
Полный перечень изменений, необходимых для обновления до Symfony 3.0, сгрупированные по компонентам.
SensioLabs DeprecationDetector
Запускает анализ статического кода в сравнении с исходным кодом вашего проекта, чтобы найти использование устаревших методов, классов и интерфейсов. Работает для любого PHP-приложения, но включает специальные детекторы для приложений
Symfony, где он также может определять использование устаревших сервисов.
Наладчик обновления Symfony
Анализирует проекты Symfony, чтобы найти устаревания. В дополнение также автоматически решает некоторые из них благодаря растущему списку поддерживаемых "наладчиков".

Тестирование вашего пакета в Symfony 3

Теперь, когда ваш пакет был избавлен от всех устареваний, пора тестировать его по-настоящему в приложении Symfony 3. Если предположить, что у вас уже есть приложение Symfony 3, то вы можете протестировать обновлённый пакет, без необходимости его установки через Composer.

Если ваша операционная система поддерживает символические ссылки, просто направьте необходимый каталог-поставщик к вашему локальному корневому каталогу пакета:

1
$ ln -s /path/to/your/local/bundle/ vendor/you-vendor-name/your-bundle-name

Если ваша операционная система не поддерживает символьные ссылки, вам понадобится скопироваь ваш локальный каталог пакета в соответствующий каталог внутри vendor/.

Обновление конфигурации Travis CI

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
language: php
sudo: false
php:
    - 5.3
    - 5.6
    - 7.0

matrix:
    include:
        - php: 5.3.3
          env: COMPOSER_FLAGS='--prefer-lowest --prefer-stable' SYMFONY_DEPRECATIONS_HELPER=weak
        - php: 5.6
          env: SYMFONY_VERSION='2.7.*'
        - php: 5.6
          env: SYMFONY_VERSION='2.8.*'
        - php: 5.6
          env: SYMFONY_VERSION='3.0.*'
        - php: 5.6
          env: SYMFONY_VERSION='3.1.*'
        - php: 5.6
          env: DEPENDENCIES='dev' SYMFONY_VERSION='3.2.*@dev'

before_install:
    - composer self-update
    - if [ "$DEPENDENCIES" == "dev" ]; then perl -pi -e 's/^}$/,"minimum-stability":"dev"}/' composer.json; fi;
    - if [ "$SYMFONY_VERSION" != "" ]; then composer --no-update require symfony/symfony:${SYMFONY_VERSION}; fi;

install: composer update $COMPOSER_FLAGS

script: phpunit

Обновление вашего кода для поддержки Symfony 2.x и 3.x одновременно

Настоящей сложностью добавления поддержки Symfony 3 в ваши пакеты является ситуация, когда вы хотите, чтобы пакет поддерживал обе версии Symfony 2.x и 3.x одновременно, используя один код. Есть несколько острых углов, где вам понадобится расправиться с различиями API.

Перед тем, как углубляться в специфику наиболее распространённых крайних случаев, общей рекомендацией является не пологаться на версию Symfony Kernel, чтобы решить, какой код использовать:

1
2
3
4
5
if (Kernel::VERSION_ID < 20800) {
    // код для Symfony 2.x
} else {
    // код для Symfony 3.x
}

Вместо того, чтобы проверять версию Symfony Kernel, проверьте версию конкретного компонента. Например, OptionsResolver API изменился в версии 2.6, путём добавления метода setDefined(). Рекомендуемой проверкой в этом случае будет:

1
2
3
4
5
6
7
use Symfony\Component\OptionsResolver\OptionsResolver;

if (!method_exists(OptionsResolver::class, 'setDefined')) {
    // код для старого OptionsResolver API
} else {
    // код для нового OptionsResolver API
}

Tip

Существует один случай, когда вы действительно можете положиться на константу Symfony\Component\HttpKernel\Kernel::VERSION_ID: при попыке определить версию компонента symfony/http-kernel, так как это тот компонент, где определяется константа.