Оновлення старшої версії (наприклад, з 5.4.0 до 6.0.0)

Дата оновлення перекладу 2022-12-23

Оновлення старшої версії (наприклад, з 5.4.0 до 6.0.0)

Кожні два роки Symfony випускає нову старшу версію (змінюється перша цифра). Ці релізи найскладніші в оновленні, так як їм дозволено порушувати зворотну сумісність. Однак, Symfony робить так, щоб процес оновлення пройшов якнайприємніше.

Це означає, що ви можете оновити більшу частину вашого коду до того, як старші версія насправді буде випущена. Це називається - робити ваш код сумісним з майбутнім.

В оновленні до старшої версії існує декілька кроків:

  1. Позбавити ваш код старінь ;
  2. Оновити до нової старшої версії через Composer ;
  3. Оновити ваш код, щоб він працював з новою версією .

1) Позбавити ваш код старінь

Під час життєвого циклу релізу старшої версії додаються нові функції, а підписи методів та використання публічних API змінюються. Однак, молодші версії не повинні містити ніяких змін зворотної сумісності. Щоб досягти цього, "старий" код (наприклад, функції, класи і т.д.) все ще працюватиме, але буде відмічений як застарілий, що означає, що його буде видалено або змінено у майбутньому, і що вам варто перестати його використовувати.

Коли випускається старша версія (наприклад, 6.0.0), всі застарілі функції та особливості видаляються. Так що, якщо ви оновили ваш код так, щоб він перестав використовувати такі застарілі функції у останній версії перед старшою (наприклад, в 5.4.*), у вас не повинно виникнути проблем з оновленням. Це означає, що ви спочатку повинні оновитися до останньої молодшої версії (наприклад, 5.4), щоб ви могли побачити всі старіння.

Щоб допомогти вам знайти старіння, сповіщення викликаються кожний раз, коли ви використовуєте застарілу функцію. Коли ви відвідуєте ваш додаток у середовищі розробки вашого браузера, ці сповіщення відображаються в панелі інструментів веб-розробки:

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

Але в інших ситуаціях, попередження може бути розмитим: установка десь може змусити глибший клас викликати попередження. У цьому випадку Symfony намагається як можна чіткіше сформулювати повідомлення, але можливо ви захочете глибше дослідити таке попередження.

А іноді попередження може поступати від сторонньої бібліотеки або пакету, які ви використовуєте. Якщо це так, то існує висока вірогідність, що такі старіння вже були оновлені. У такому випадку, оновіть бібліотеку, щоб виправити їх.

Як тільки зникнуть всі попередження про старіння, ви можете оновлюватися з найбільшою впевненістю.

Старіння в PHPUnit

Коли ви виконуєте ваші тести, використовуючи PHPUnit, повідомлення про старіння не відображаються. Щоб допомогти вам в цьому, Symfony надає міст PHPUnit. Цей міст покаже вам зручне резюме усіх повідомлень про старіння наприкінці тестового звіту.

Все, що вам потрібно - це встановити міст PHPUnit:

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

Тепер ви можете почати виправляти сповіщення:

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

OK (10 тестів, 20 тверджень)

Повідомлення про старіння, що залишилися (6)

Сервіс "request" викликає старіння і буде видалено у версії 3.0.
Додайте підказку для Symfony\Component\HttpFoundation\Request в параметри
вашого контролера, щоб замість цього повернути запит: 6x
    3x in PageAdminTest::testPageShow from Symfony\Cmf\SimpleCmsBundle\Tests\WebTest\Admin
    2x in PageAdminTest::testPageList from Symfony\Cmf\SimpleCmsBundle\Tests\WebTest\Admin
    1x in PageAdminTest::testPageEdit from Symfony\Cmf\SimpleCmsBundle\Tests\WebTest\Admin

Як тільки ви виправите все, команда завершиться 0 (успіх) і ви закінчили!

Caution

Ви скоріш за все побачите багато старінь стосовно несумісності нативних типів повернення. Див. Додавання нативних типів повернених значень , щоб отримати посібник з виправлення таких старінь.

Іноді вам не вдасться виправити всі старіння (наприклад, щось застаріло у версії 5.4, а вам все ще потрібна підтримка версії 5.3). У таких випадках ви все одно можете використати міст для виправлення якомога більшої кількості старінь, а потім дозволити одному або більше з них провести тестування. Ви можете зробити це, використовуючи змінну середовища SYMFONY_DEPRECATIONS_HELPER:

1
2
3
4
5
6
7
8
<!-- phpunit.xml.dist -->
<phpunit>
    <!-- ... -->

    <php>
        <env name="SYMFONY_DEPRECATIONS_HELPER" value="max[total]=999999"/>
    </php>
</phpunit>

Ви також можете виконати таку команду:

1
$ SYMFONY_DEPRECATIONS_HELPER=max[total]=999999 php ./bin/phpunit

2) Оновити до нової старшої версії через Composer

Коли ваш код буде позбавлено від старінь, ви можете оновити бібліотеку Symfony через Composer, модифікувавши ваш файл composer.json, та змінивши всі бібліотеки, які починаються з symfony/ на нову старшу версію:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
      "...": "...",

      "require": {
-         "symfony/cache": "5.4.*",
+         "symfony/cache": "6.0.*",
-         "symfony/config": "5.4.*",
+         "symfony/config": "6.0.*",
-         "symfony/console": "5.4.*",
+         "symfony/console": "6.0.*",
          "...": "...",

          "...": "Декілька бібліотек, що починаються з symfony/,
                  дотримуються власної схеми версіонування. Вам
                  не потрібно оновлювати ці версії: ви можете оновити
                  їх незалежно, коли захочете",
          "symfony/monolog-bundle": "^3.5",
      },
      "...": "...",
  }

Знизу вашого файлу composer.json, у блоці extra, ви можете знайти налаштування даних длля версії Symfony. Переконайтеся в тому, що оновили і її. Наприклад, змініть її на 6.0.*, щоб оновитися до версії Symfony 6.0:

1
2
3
4
5
6
7
"extra": {
      "symfony": {
          "allow-contrib": false,
-       "require": "5.4.*"
+       "require": "6.0.*"
      }
  }

Далі, використайте Composer, щоб завантажити нові версії бібліотек:

1
$ composer update "symfony/*"

Ошибки зависимостей

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

1
$ composer update symfony/symfony --with-dependencies

Это обновляет symfony/symfony и все пакеты, от которых он завсит, которые будут включать всебя несколько других пакетов. Используя облегчённую версию ограничений в composer.json, вы можете контролировать, до каких версий будет обновлена каждая из ваших библиотек.

Если и это не сработает, ваш файл composer.json может указывать версию для билиотеки, котора не совместима с более новыми версиями Symfony. В таком случае, обновление библиотеки до более новой версии в composer.json может решить проблему.

Или, у вас могут быть более глубокие проблемы, когда разные библиотеки зависят от конфликтующих версий других библиотек. Проверьте ваши сообщения ошибок для отладки.

Обновление других пакетов

Вы можете также захотеть обновить и остальные ваши библиотеки. Если вы хорошо справились с вашими version constraints в composer.json, вы можете без опаски сделать это, выполнив:

1
$ composer update

Caution

Будьте осторожны, если у вас есь какие-то общие ограничения версий в вашем composer.json (например, dev-master), это может обновить некоторые библиотеки не из Symfony до более новых версий, которые содержат существенные изменения обратной совместимости.

3) Updating Recipes

Over time - and especially when you upgrade to a new version of a library - an updated version of the recipe may be available. These updates are usually minor - e.g. new comments in a configuration file - but it's a good idea to keep your files in sync with the recipes.

Symfony Flex provides several commands to help upgrade your recipes. Be sure to commit any unrelated changes you're working on before starting:

1.18

The recipes:update command was introduced in Symfony Flex 1.18.

1
2
3
4
5
6
7
8
9
10
11
# choose an outdated recipe to update
$ composer recipes:update

# update a specific recipe
$ composer recipes:update symfony/framework-bundle

# see a list of all installed recipes and which have updates available
$ composer recipes

# see detailed information about a specific recipes
$ composer recipes symfony/framework-bundle

The recipes:update command is smart: it looks at the difference between the recipe when you installed it and the latest version. It then creates a patch and applies it to your app. If there are any conflicts, you can resolve them like a normal git conflict and commit like normal.

3) Оновити ваш код, щоб він працював з новою версією

У деяких рідкісних ситуаціях, наступна старша версія може містити порушення зворотної сумісності. Не забудьте прочитати UPGRADE-X.0.md (де X - це нова старша версія), включений до сховища Symfony, щоб дізнатися про будь-які порушення зворотної сумісності, на які вам варто звернути увагу.

Оновлення до Symfony 6: Додавання нативних типів значень, що повертаються

Symfony 6 буде постачатися з нативними типами значень PHP, що повертаються, (майже) до всіх методів.

В PHP, якщо батько має декларацію типу значення, що повертається, будь-який клас, шо реалізує або перевизначає метод, повинен також мати тип значення, що повертається. Однак, ви можете додати тип значення, що повертається, до того, як його додасть батько. Це означає, що важливо додавати нативні типи значень PHP, що повертаються, до ваших класів до оновлення на Symfony 6.0. Інакше, ви отримаєте помилки несумісних декларацій.

Коли увімкнено режим налагодження (зазвичай у середовищах розробки та тестування), Symfony видаватиме старіння для кожної несуммісної декларації методів. Наприклад, метод UserInterface::getRoles() в Symfony 6 матиме тип значення, що повертається, array. В Symfony 5.4, ви отримаєте повідомлення про старіння, і повинні будете додати декларацію типу значення, що повертається, до вашого методу getRoles().

Щоб допомогти з цим, Symfony надає скрипт, який може додавати ці типи значень, що повертаються, за вас автоматично. Переконайтеся в тому, що ви встановили компонент symfony/error-handler. Після цього, згенеруйте повне відображення класів, викоритовуючи Composer, і виконайте скрипт, щоб виконати перебір та виправити всі несумісні методи:

1
2
3
4
5
6
7
# Переконайтеся, що "exclude-from-classmap" не заповнений у вашому "composer.json". Потім скиньте автозавантажувач:

# "-o" - це важливо! Це змушує Composer знайти всі класи
$ composer dump-autoload -o

# виправте всі старіння несумісних методів
$ ./vendor/bin/patch-type-declarations

Tip

Ця функція не обмежується пакетами Symfony. Вона також допоможе вам додавати типи та готуватися до інших залежностей у вашому проекті.

Поведінку цього скрипта можна змінити, використовуючи змінну середовища SYMFONY_PATCH_TYPE_DECLARATIONS. Значення цієї змінної середовища url-зашифроване (наприклад, param1=value2&param2=value2), і доступні наступні параметри:

force

Включає виправлення типів значень, що повертаються, значення повинно бути:

  • 2, щоб додати всі можливі типи значень, що повертаються (за замовчуванням рекомендовано для додатків);
  • 1, щоб додати типи значень, що повертаються, лише до тестів, фінальних, внутрішніх та приватних методів;
  • phpdoc, щоб додати лише анотації docblock @return до несумісних методів, або #[\ReturnTypeWillChange], якщо воно викликано PHP-двигуном.
php
Цільова версія PHP - наприклад, 7.1 не генерує типи "object" (які були представлені в 7.2). За замовчуванням це прирівнюється до PHP-версії, що використовується при виконанні скрипту.
deprecations
Встановіть 0, щоб відключити старіння. Інакше, виникне сповіщення про старіння, коли дочірньому класу не вистачатиме типу значення, що повертається, в той час як батьківський клас буде оголошувати анотацію @return (за замовчуванням - 1).

Якщо є якісь конкретні файли, які треба ігнорувати, ви можете встановити змінну середовища SYMFONY_PATCH_TYPE_EXCLUDE як регулярний вираз. Цей регулярний вираз буде співставлений з повним шляхом до класу, і кожний шлях, що співпадає, буде проігноровано (наприклад, SYMFONY_PATCH_TYPE_EXCLUDE="/tests\/Fixtures\//"). Класи у каталозі vendor/ ігноруватимуться завжди.

Tip

Скрипту не важливий стиль коду. Запустіть свій виправник стилю коду, або PHP CS Fixer з правилами phpdoc_trim_consecutive_blank_line_separation, no_superfluous_phpdoc_tags і ordered_imports, після виправлення типів.

Пакети з відкритим кодом повинні бути обережнішими при додаванні типів значень, що повертаються, так як додавання типу значення, що повертається, змушує всіх користувачів, які розширюють клас, також додавати тип значення, що повертається. Рекомендований підхід полягає у двокроковому процесі:

  1. По-перше, створіть молодший реліз (тобто, без порушень зворотної сумісності), де ви додасте типи, які можуть бути представлені безпечно, і додайте PHPDoc @return до всіх інших методів:

    1
    2
    3
    4
    5
    6
    # Додати декларації типів до всіх внутрішніх, фінальних, тестових та приватних методів.
    # Оновити параметр "php", щоб він відповідав вашій мінімально потрібній версії PHP
    $ SYMFONY_DEPRECATIONS_HELPER="force=1&php=7.4" ./vendor/bin/patch-type-declarations
    
    # Додати PHPDoc до публічних та захищених методів, що залишилися
    $ SYMFONY_DEPRECATIONS_HELPER="force=phpdoc&php=7.4" ./vendor/bin/patch-type-declarations

    Після виконання скриптів, перевірте свої класи та додайте PHPDoc @return там, де його не вистачає. Старіння та скрипт виправлень працюють виключно засновуючись на інформації PHPDoc. Користувачі цього релізу отримають сповіщення про старіння, які повідомлять їм про те, що варто додати типи значень, що повертаються, яких не вистачає, з вашого пакету в їх код.

    Якщо вам не був потрібен PHPDoc, і всі ваші делкарації методів вже сумісні з Symfony, ви можете спокійно дозволити ^6.0 для залежностей Symfony. В інших випадках, вам буде потрібно перейти до наступного кроку (2).

  2. Створіть новий старший реліз (тобто, з порушенням зворотної сумісності), де ви додасте типи до всіх методів:

    1
    2
    # Оновити параметр "php", щоб він відповідав вашій мінімально потрібній версії PHP
    $ SYMFONY_DEPRECATIONS_HELPER="force=2&php=7.4" ./vendor/bin/patch-type-declarations

    Тепер ви можете безпечно дозволити ^6.0 для залежностей Symfony.