React Router 6 и Атрибуты PHP 8

Месяц назад вышел PHP 8.1 с новыми возможностями. Атрибуты теперь поддерживают вложенность, которой раньше не было. Это нам мешало перейти на них в 8.0. И не все библиотеки поддерживали атрибуты. Теперь же всё поддерживается и нас ничто не останавливает.

Пришла пора завершить переход на PHP 8.0 и перевести проект с классических аннотаций на новые нативные атрибуты для валидатора и Doctrine ORM. Поговорить, что делать с ними в legacy-проектах. И заодно обновиться на новые компоненты из версии Symfony 6 для бэкенда и подключить новый React Router 6 для фронтенда.

  • 00:00:33 Атрибуты в PHP 8
  • 00:07:03 Обновление фронтенда
  • 00:08:53 Переход на React Router 6
  • 00:13:25 Новые версии Cucumber
  • 00:15:02 Исправление закрытия браузера в E2E
  • 00:16:39 Увеличение таймаутов в E2E
  • 00:17:48 Регулировка числа потоков
  • 00:19:08 Версия Xdebug
  • 00:19:55 Обновление API
  • 00:24:58 Валидатор из Symfony 6
  • 00:26:38 Дополнительный тест на валидацию
  • 00:27:51 Восстановление валидации по аннотациям
  • 00:31:58 Перевод валидатора на атрибуты
  • 00:33:35 Перевод Doctrine ORM на атрибуты
  • 00:39:49 Драйвер для чтения атрибутов
  • 00:42:53 Донастройка CS Fixer
  • 00:43:14 Переход на атрибуты в legacy проекте
  • 00:49:20 Обзор результата
Скрытый контент (код, слайды, ...) для подписчиков. Открыть →
Дмитрий Елисеев
elisdn.ru
Комментарии (32)
Руслан

Спасибо!

Ответить
slo_nik

Добрый вечер, Дмитрий.

Как всегда на отлично)

Сразу же вопрос.

Есть всё-таки возможность поставить overtrue/phplint к symfony6.0? Если да, то как это можно делать?

Или забить на это и ждать пока обновится сам overtrue/phplint на использование symfony/console v6.0?

Вчера пытался найти посвежее пакет phplint, но пока ничего не попалось.

Ответить
Дмитрий Елисеев

Или забить на это и ждать

Или отправить Pull Request и не ждать.

Ответить
slo_nik

Понял.

И вот ещё такая проблема.

После обновлений появилась ошибка

Firefox не может установить соединение с сервером ws://localhost:3000/ws.

Пробовал в конфигурации nginx для frontend и gateway задать настройки

proxy_connect_timeout 43200000;
proxy_read_timeout 43200000;
proxy_send_timeout 43200000;

Но это не помогло.

Как ещё можно решить данную проблему?

Ответить
Дмитрий Елисеев

Для location /ws {...} в проксировании настроить заголовок Connection.

Ответить
slo_nik

То есть, нужно создать для ws отдельный блок в настройках nginx, так же как делали для sockjs-node?

    location /sockjs-node {
      proxy_set_header  Host $host;
      proxy_set_header  Upgrade $http_upgrade;
      proxy_set_header  Connection "Upgrade";
      proxy_pass        http://frontend-one-node:3000;
      proxy_redirect    off;
    }
Ответить
Дмитрий Елисеев

Да

Ответить
slo_nik

А где поискать, как понять, какое именно обновление вызвало этот сбой?

Ответить
Дмитрий Елисеев

В CHANGELOG пакетов, у которых были мажорные изменения.

Ответить
slo_nik

Ошибка возникла после обновления react-scripts 4.0.3 -> 5.0.0

На github есть issues

Ответить
slo_nik

К сожалению не помогает.

Добавил в frontend/docker/development/nginx/conf.d и в gateway/docker/development/nginx/conf.d, но ошибка всё-равно появляется.

Ответить
slo_nik

Ругается на файл

node_modules/webpack-dev-server/client/clients/WebSocketClient.js

строка 13

this.client = new WebSocket(url);

Ответить
Максим (@myks92)

11 дней назад уже сделал такой PR. 4 дня назад выпустили версию 4.1 где есть поддержка Symfony 6. Пользуйтесь)

Ответить
Arunas

Спасибо.

Ответить
Владимир Перепеченко

Благодарю Дмитрий, даже я понял про атрибуты.

Интересно, несовместимость каких текущих пакетов помешала Вам прыгнуть сразу на PHP 8.1 ?

Традиционные вопросы чайника:

Какие папки мы вправе указывать как metadata_dirs для доктрины?

  1. можем ли сразу указать для всего проекта /src ? Или рекурсивно она не ищет? Или ищет но медленно?
  2. должны ли в указанных папках находится только файлы entity или там имеет право быть ещё всякий мусор?
Ответить
Дмитрий Елисеев

несовместимость каких текущих пакетов помешала Вам прыгнуть сразу на PHP 8.1

Пару недель назад были мелкие проблемы у PHP-CS-Fixer, которые уже исправили. Сейчас есть deprecations у пакета willdurand/negotiation.

А так в любом проекте можно посмотреть явно мешающие пакеты командой:

docker-compose run --rm api-php-cli composer why-not php 8.1

Для проверки реальной совместимости можно попробовать в локальном Dockerfile и composer.json поменять версию и после пересборки запустить api-check.

Но помимо смены версии желательно и код перевести на новые возможности вроде readonly и Enums. Так что для перехода на PHP 8.1 нужен будет отдельный подробный эпизод.

Ответить
Дмитрий Елисеев

Именно. В своём коде это всё находит Psalm, но в коде чужих библиотек могут быть проблемы.

Ответить
Владимир Перепеченко

К сожалению, Psalm найдёт только если разработчик сам поставил deprecated в аннотации в докблоке своего кода.

А просто deprecated функции или куски кода в голом PHP он не находит.

Ранее у phpstan был плагин для поиска подобных вещей, но он давно не обновляется, так что сейчас в опенсорсе, наверное, и нет ничего, для поиска deprecated кода.

Ответить
Дмитрий Елисеев

Можем ли сразу указать для всего проекта /src? Или рекурсивно она не ищет?

Можем. Рекурсивно ищет.

Или там имеет право быть ещё всякий мусор?

Может быть мусор, как у нас там лежат классы типов и репозиториев.

Ответить
Владимир Перепеченко

Благодарю! Тогда в чем фишка это фишки? При каких обстоятельтвах мы вынуждены будем указывать в массиве конфига кучу отдельных папок для Entity вместо просто одной папки?

Ответить
Дмитрий Елисеев

У нас ни в чём, так как мэппинг везде одинаковый. Можно и так, и так.

Нам бы сейчас отдельные папки помогли постепенно модуль за модулем перевести с аннотаций на атрибуты большой проект.

Ответить
Владимир Перепеченко

Значит на производительность не повлияет указание одного src - Отлично!

Очень ценю Ваши ответы Дмитрий! 👊

Ответить
slo_nik

После обновления react-scripts 4.0.3 -> 5.0.0 возникла ошибка:

Firefox cannot connect to the server ws://localhost:3000/ws.

Решается заменой в конфигах nginx

location /sockjs-node{...}

на

location /ws{...}

И добавлением в environment для frontend-node переменной

  • WDS_SOCKET_PORT=0

Без этой переменной не работает.

Ошибка больше в консоли не появлялась, "горячая" перезагрузка страницы работает.

Возможно кому-то поможет.

Ответить
Руслан

Спасибо!

Ответить
Руслан

Дима, когда примерно будет продолжение серии по Slim/React?

Ответить
Алексей

Спасибо, и есть вопрос по атрибутам, в проекте по Symfony для swagger`а использовались аннотации, а как такие же анотации перевести в атрибуты? вот пример из вашего проекта используется php 8.1

   /**
     * @OA\Get(
     *     path="/work/tasks",
     *     tags={"Work Task"},
     *     @OA\Parameter(
     *         name="filter[author]",
     *         in="query",
     *         required=false,
     *         @OA\Schema(type="string"),
     *         style="form"
     *     ),
     *     @OA\Response(
     *         response=200,
     *         description="Success response",
     *         @OA\JsonContent(
     *             type="object",
     *             @OA\Property(property="items", type="array", @OA\Items(
     *                 @OA\Property(property="id", type="integer"),
     *                 @OA\Property(property="project", type="object",
     *                     @OA\Property(property="id", type="string"),
     *                     @OA\Property(property="name", type="string"),
     *                 ),
     *                 @OA\Property(property="date", type="string")
     *             )),
     *             @OA\Property(property="pagination", ref="#/components/schemas/Pagination"),
     *         )
     *     ),
     *     security={{"oauth2": {"common"}}}
     * )
     */
Ответить
Дмитрий Елисеев

Аналогично, но с ключами вроде parameters и responses:

    #[OA\Get(
        path: '/work/tasks',
        tags: ['Work Task'],
        parameters: [
            new OA\Parameter(
                name: 'filter[author]',
                in: 'query',
                required: false,
                schema: new OA\Schema(type: 'string'),
                style: 'form'
            ),
        ],
        responses: [
            new OA\Response(
                response: 200,
                content: new OA\JsonContent(...)
            )
        ]
    )]
Ответить
Алексей

понял, спасибо большое, к примеру выходит как то так

#[OAT\Get(
    path: '/profile',
    description: 'profile',
    tags: ['Profile'],
    responses: [
        new OAT\Response(
            response: 200,
            content: new OAT\JsonContent(
                properties: [
                    new OAT\Property(
                        property: 'time',
                        type: 'string'
                    ),
                    new OAT\Property(
                        property: 'result',
                        type: "object",
                        properties:[
                            new OAT\Property(property: 'title', type: 'string')
                        ]
                    )
                ]
            )
        )
    ]
)]

еще вопрос, phpStorm начиная с new OAT\Response подсвечивает все красным, однако код работает и документацию делает правильно и я не нашел плагинов которые бы ему объяснили что все норм

Ответить
Алексей

Вопрос отпал сам собой, оказывается phpstorm 2021.2 так не умел, обновился до .3 и все отлично!

Ответить
Стариков Андрей

Добрый день, заметил, что при переходе на атрибуты, правило final_class для php cs fixer перевело классы сущностей в final, так как в этой проверке настроено определение entity при помощи phpDoc. На dev окружение проблем с этим нет, но на prod сервере будет ошибка при создании прокси объектов. Чтобы не отключать это правило, у себя добавил к этим классам @final. Может стоит добавить какую-то проверку в make check, чтобы она проверяла такие возможны ошибки

Ответить
Дмитрий Елисеев

Да, есть у них пока такой баг. Может в скором времени исправят.

Прокси-объекты создаются если в проекте мы из одной сущности лениво подгружаем ManyToOne связь вроде $comment->author или если в зависимых фикстурах используется getReference. У нас таких внешних связей не будет, так что нам final не помешает.

Ответить
Зарегистрируйтесь или войдите чтобы оставить комментарий

Или войти через:

Yandex
MailRu
GitHub
Google