tech-tips/Языки программирования/PHP/Laravel/Руководство по обновлению до Laravel 9 Уроки Laravel.md

286 lines
29 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[https://laravel.demiart.ru/upgrade-guide-to-laravel-9/](https://laravel.demiart.ru/upgrade-guide-to-laravel-9/)
![[laravel-9-upgrade.png]]
Мы постарались задокументировать все возможные критические изменения. Поскольку некоторые из них находятся в малоизвестных частях фреймворка, только часть этих изменений может повлиять на ваше приложение. Приблизительное время обновления: 30 минут.
### Требуется PHP 8.0.2
Минимальная поддерживаемая версия PHP Laravel теперь 8.0.2.
### PHP Типы возвращаемого значения
Язык начинает требовать определения типа возвращаемого значения для методов, таких как `offsetGet`, `offsetSet`, и т.п. По этой причине Laravel 9 реализовал эти типы в своей кодовой базе. Как правило, это не должно влиять на написанный пользователем код, однако, если вы переопределяете один из этих методов, расширяя базовые классы Laravel, то вам нужно будет добавить типы возвращаемых значений в код вашего приложения или пакета:
- `count(): int`
- `getIterator(): Traversable`
- `getSize(): int`
- `jsonSerialize(): array`
- `offsetExists($key): bool`
- `offsetGet($key): mixed`
- `offsetSet($key, $value): void`
- `offsetUnset($key): void`
Кроме того, типа возвращаемых значений были добавлены в методы, реализующие PHP `SessionHandlerInterface`. Опять же, маловероятно, что это изменение повлияет на ваше приложение или пакет:
- `open($savePath, $sessionName): bool`
- `close(): bool`
- `read($sessionId): string|false`
- `write($sessionId, $data): bool`
- `destroy($sessionId): bool`
- `gc($lifetime): int`
### Зависимости Composer
Вы должны обновить следующие зависимости в файле composer.json вашего приложения:
- `laravel/framework к ^9.0`
- `nunomaduro/collision к ^6.0`
Кроме того, замените `facade/ignition` на `"spatie/laravel-ignition": "^1.0"` в этом же файле.
Не забудьте также проверить все сторонние пакеты, используемые в вашем приложении, и убедитесь, что они поддерживают Laravel 9.
### Контракт Application
Метод `storagePath` интерфейса `Illuminate\Contracts\Foundation\Application` был обновлен для использования аргумента `$path`. Если вы реализуете этот интерфейс, вы должны соответствующим образом обновить свою реализацию:
### Метод `ignore` обработчика исключений
Метод `ignore` теперь `public` вместо `protected`. Этот метод не включен в дефолтный каркас приложения. Однако, если вы задавали этот метод вручную, то должны обновить его видимость до `public`:
### Blade — Ленивые коллекции и переменная `$loop`
При итерации экземпляра `LazyCollection` в Blade-шаблоне переменная `$loop` больше недоступна, так как доступ к этой переменной приводит к полной загрузке `LazyCollection` в память, что делает использование ленивых коллекций бессмысленным в данном сценарии.
### Collections — Контракт Enumerable
Контракт `Illuminate\Support\Enumerable` теперь определяет метод `sole`. Если вы реализуете этот интерфейс вручную, то обновите свою реализацию, добавив новый метод:
### Контракт Container
Контракт `Illuminate\Contracts\Container\Container` получил два новых метода: `scoped` и `scopedIf`. Если вы реализуете этот контракт вручную, то обновите свою реализацию, добавив их.
### Контракт ContextualBindingBuilder
Контракт `Illuminate\Contracts\Container\ContextualBindingBuilder` получил новый метод `giveConfig`. Если вы реализуете этот контракт вручную, то обновите свою реализацию, добавив его.
### Postgres конфигурация «Schema»
Параметр конфигурации `schema`, используемый для настройки путей поиска соединений Postgres в файле конфигурации `config/database.php` вашего приложения, должен быть переименован в `search_path`.
### Кастомные касты и `null`
В предыдущих версиях Laravel метод `set` кастомных кастов не вызывался, если для атрибута приведения было установлено значение `null`. Однако такое поведение не соответствовало документации Laravel. В Laravel 9.x метод `set` класса каста будет вызываться с `null` в аргументе `$value`. Поэтому вы должны убедиться, что ваши касты смогут правильно отработать этот сценарий:
public function set($model, $key, $value, $attributes)
### Методы Belongs To Many `firstOrNew`, `firstOrCreate` и `updateOrCreate`
Методы отношения belongsToMany: `firstOrNew`, `firstOrCreate` и `updateOrCreate` принимают массив атрибутов в качестве первого аргумента. В предыдущих версиях Laravel этот массив сравнивался со «сводной»/промежуточной таблицей для существующих записей.
Однако такое поведение было неожидаемым и, как правило, нежелательным. Вместо этого эти методы теперь сравнивают массив атрибутов с таблицей связанной модели:
Кроме того, метод `firstOrCreate` теперь принимает массив `$values` в качестве второго аргумента. Этот массив будет объединен с первым аргументом метода ( `$attributes`) при создании связанной модели, если она еще не существует. Это изменение делает этот метод совместимым с методом `firstOrCreate`, предлагаемыми другими типами отношений:
### Метод `touch`
Теперь метод `touch` принимает атрибут. Если вы ранее переопределяли этот метод, то вам следует обновить его, добавив новый аргумент:
### Контракт `Encrypter`
В контракт `Illuminate\Contracts\Encryption\Encrypter` добавлен метод `getKey`. Если вы реализуете этот интерфейс вручную, то обновить свою реализацию:
### Фасады — метод `getFacadeAccessor`
Метод `getFacadeAccessor` всегда должен возвращать ключ привязки контейнера. В предыдущих версиях Laravel этот метод мог возвращать экземпляр объекта, однако такое поведение больше не поддерживается. Если вы создавали свои собственные фасады, то убедитесь, что этот метод возвращает строку привязки контейнера:
### Переменная окружения `FILESYSTEM_DRIVER`
Переменная `FILESYSTEM_DRIVER` была переименована в `FILESYSTEM_DISK` для более точного отражения ее назначения. Это изменение затрагивает только каркас приложения, однако вы можете обновить переменные окружения своего приложения, если хотите.
### Flysystem 3.x
Laravel 9 переходит с Flysystem 1.x на 3.x. Под капотом Flysystem поддерживает все методы работы с файлами, предоставляемые фасадом `Storage`. В связи с этим в вашем приложении могут потребоваться некоторые изменения; однако мы постарались сделать этот переход максимально плавным.
### Требования
Перед использованием драйверов S3 или SFTP необходимо установить соответствующий пакет через Composer:
Amazon S3`composer require --with-all-dependencies league/flysystem-aws-s3-v3 "^3.0"`
SFTP
`composer require league/flysystem-sftp-v3 "^3.0"`
### Перезапись существующих файлов
Операции записи `put`, `write`, `writeStream` теперь перезаписывают существующие файлы по умолчанию. Если вы не хотите перезаписывать существующие файлы, то вам следует вручную проверить существование файла перед выполнением операции записи.
### Чтение несуществующих файлов
Попытка чтения из несуществующего файла теперь возвращает `null`. В предыдущих версиях Laravel выбрасывалось исключение `Illuminate\Contracts\Filesystem\FileNotFoundException`.
### Удаление несуществующих файлов
Попытка применения метода `delete` к несуществующему файлу теперь возвращает `true`.
### Кэшированные адаптеры
Flysystem больше не поддерживает «`cached adapters`». Поэтому они были удалены из Laravel, и любая соответствующая конфигурация (например, ключ `cache` в конфигурации диска) может быть удалена.
### Кастомные файловые системы
Небольшие изменения были внесены в шаги, необходимые для регистрации кастомных драйверов файловой системы. Если вы создавали свои собственные драйверы или использовали пакеты, создающие таковые, то необходимо обновить свой код и зависимости. Например, в Laravel 8.x кастомный драйвер файловой системы может быть зарегистрирован следующим образом:
Storage::extend('dropbox', function ($app, $config) {
А в Laravel 9.x колбэк метода `Storage::extend` должен возвращать экземпляр `Illuminate\Filesystem\FilesystemAdapter` напрямую:
Storage::extend('dropbox', function ($app, $config) {
### Хелперы
### `data_get` & итерируемые объекты
Раньше хелпер `data_get` можно было использовать для извлечения вложенных данных только из массивов и экземпляров `Collection`. А теперь этот хелпер может извлекать вложенные данные из всех итерируемых объектов.
### str
Laravel 9 теперь включает глобальныйх хелпер [`str`](https://laravel.com/docs/master/helpers#method-str). Если вы задаете глобальный хелпер `str` в своем приложении, то вы должны переименовать или удалить его, чтобы он не конфликтовал с основным Laravel-хелпером.
### Методы `when/unless`
Как вы, возможно, знаете, методы `when` и `unless` предлагаются различными классами по всему фреймворку. Эти методы можно использовать для условного выполнения действия, если логическое значение первого аргумента метода оценивается как `true` или `false`:
Таким образом, в предыдущих версиях Laravel передача замыкания методам `when` или `unless` означала, что условная операция всегда будет выполняться, поскольку нечеткое сравнение с объектом замыкания (или любым другим объектом) всегда оценивается как `true`. Это часто приводило к неожиданным результатам, поскольку разработчики ожидали, что результат замыкания будет использоваться в качестве логического значения, определяющего, выполняется ли условное действие.
В Laravel 9 любые замыкания, переданные методам `when` или `unless`, будут выполнены, а значение, возвращаемое замыканием, будет считаться логическим значением, используемым методами `when` и `unless`:
$collection->when(function ($collection) {
$collection->merge([1, 2, 3]);
### HTTP Client
### Дефолтный таймаут
HTTP-клиент теперь имеет дефолтный тайм-аут в 30 секунд. Другими словами, если сервер не отвечает в течение 30 секунд, то будет выброшено исключение. Раньше дефолтного таймаута не было, из-за чего запросы иногда подвисали на неопределенное время.
Если вы хотите указать более длительный тайм-аут для запроса, то можете сделать это с помощью метода `timeout`:
### Symfony Mailer
Одно из самых больших изменений в Laravel 9 это переход от SwiftMailer, который не поддерживается с декабря 2021 года, к Symfony Mailer. Однако мы постарались сделать этот переход как можно более плавным для ваших приложений. Внимательно ознакомьтесь со списком изменений ниже, чтобы убедиться, что ваше приложение полностью совместимо.
### Требования
Пакет `aws/aws-sdk-php` больше не потребуется при использовании Amazon SES, и его можно удалить, если он не требуется для других частей вашего приложения. Вместо этого вашему приложению нужен пакет `symfony/amazon-mailer`:
Чтобы продолжить использование Mailgun, вашему приложению потребуется пакет `symfony/mailgun-mailer`:
Пакет `wildbit/swiftmailer-postmark` должен быть удален из вашего приложения. Вместо этого вашему приложению нужен пакет `symfony/postmark-mailer`:
### Обновленные типы возвращаемых значений
Методы `send`, `html`, `text` и `plain` больше не возвращают количество получателей. Вместо этого возвращается экземпляр `Illuminate\Mail\SentMessage`. Этот объект содержит экземпляр `Symfony\Component\Mailer\SentMessage`, доступный через метод `getSymfonySentMessage`.
### Переименованные «Swift» методы
Различные методы, связанные со SwiftMailer, некоторые из которых не были задокументированы, сейчас переименованы в их аналоги Symfony Mailer. Например, метод `withSwiftMessage` переименован в `withSymfonyMessage`:
Пожалуйста, внимательно изучите документацию [Symfony Mailer](https://symfony.com/doc/6.0/mailer.html#creating-sending-messages) для всех возможных взаимодействий с объектом `Symfony\Component\Mime\Email`.
Нижерасположенный список содержит более подробный обзор переименованных методов. Многие из них являются низкоуровневыми, используемыми для прямого взаимодействия со SwiftMailer/Symfony Mailer, поэтому могут не использоваться в большинстве приложений Laravel:
### Прокси-методы `Illuminate\Mail\Message`
Обычно отсутствующие методы в `Illuminate\Mail\Message` проксировались базовому `Swift_Message`. Но теперь, вместо этого, они будут проксироваться в `Symfony\Component\Mime\Email`. Таким образом, любой код, который ранее полагался на SwiftMailer, должен быть обновлен до соответствующих аналогов Symfony Mailer.
Опять же, многие приложения могут и не взаимодействовать с этими методами, поскольку они не описаны в документации Laravel:
### Генерируемые идентификаторы сообщений
SwiftMailer предлагал возможность задать собственный домен для включения в сгенерированные идентификаторы сообщений с помощью параметра конфигурации `mime.idgenerator.idright`. Но это не поддерживается Symfony Mailer. Вместо этого он автоматически генерирует идентификатор сообщения на основе отправителя.
### Принудительные переподключения
Теперь больше невозможно принудительно переподключиться к транспорту (например, когда мейлер работает через демона). Вместо этого Symfony Mailer попытается автоматически переподключиться к транспорту и выбросит исключение, если это не удастся.
### Параметры SMTP-stream
Определение параметров потока для SMTP больше не поддерживается. Вместо этого вы должны задать соответствующие параметры непосредственно в конфигурации, если они поддерживаются. Например, чтобы отключить проверку пира TLS:
Чтобы узнать больше о доступных параметрах конфигурации, ознакомьтесь с [документацией Symfony Mailer](https://symfony.com/doc/6.0/mailer.html#transport-setup).
Несмотря на вышеприведенный пример, не рекомендуется отключать проверку SSL, поскольку это создает возможность атак типа «man-in-the-middle».
### SMTP auth_mode
Определение SMTP `auth_mode` в файле конфигурации `mail` больше не требуется. Режим аутентификации будет автоматически согласован между Symfony Mailer и SMTP-сервером.
### Неудавшиеся отправления
Теперь невозможно получить список получателей, которым не получилось отправить письмо. Вместо этого, , если сообщение не будет отправлено, то выбросится исключение `Symfony\Component\Mailer\Exception\TransportExceptionInterface`. Вместо того, чтобы полагаться на получение невалидных адресов электронной почты после отправки сообщения, мы рекомендуем вам проверять их перед отправкой сообщения.
### Пакеты
### Каталог `lang`
В новых приложениях Laravel папка `resources/lang` теперь находится в корневой папке проекта (`lang`). Если ваш пакет публикует языковые файлы в этот каталог, то вы должны убедиться, что ваш пакет использует `app()->langPath()`, а не захардкоженный старый путь.
### Очереди
### Библиотека `opis/closure`
Зависимость Laravel от `opis/closure` была заменена на `laravel/serializable-closure`. Это не должно привести к каким-либо критическим изменениям в вашем приложении, если только вы не взаимодействуете с библиотекой `opis/closure` напрямую. Кроме того, были удалены классы `Illuminate\Queue\SerializableClosureFactory` и `Illuminate\Queue\SerializableClosure`, ранее объявленные устаревшими. Если вы взаимодействуете с библиотекой `opis/closure` напрямую или используете любой из удаленных классов, то вместо этого используйте [Laravel Serializable Closure](https://github.com/laravel/serializable-closure).
### Метод `failed` провайдера `Failed Job`
Метод `flush`, заданный интерфейсом `Illuminate\Queue\Failed\FailedJobProviderInterface`, теперь принимает аргумент `$age`, определяющий, сколько в днях должно просуществовать невыполненное задание, прежде чем оно будет сброшено командой `queue:flush`. Если вы реализуете вручную интерфейс `FailedJobProviderInterface`, то убедитесь, что ваша реализация обновлена для использования нового аргумента:
### Сессия
### Метод `getSession`
Класс `Symfony\Component\HttpFoundaton\Request`, расширяемым Laravel-классом `Illuminate\Http\Request`, предлагает метод `getSession` для получения текущего обработчика хранилища сессии. Этот метод не задокументирован, так как большинство приложений Laravel взаимодействуют с сессией через метод `session`.
Ранее метод `getSession` возвращал экземпляр `Illuminate\Session\Store` или `null`. Однако из-за того, что в релизе Symfony 6.x используется тип возвращаемого значения `Symfony\Component\HttpFoundation\Session\SessionInterface`, теперь метод `getSession` корректно возвращает `SessionInterface` или выбрасывает исключение \`Symfony\Component\HttpFoundation\Exception\SessionNotFoundException`, если сессия недоступна.
### Тестирование
### Метод `assertDeleted`
Все вызовы метода `assertDeleted` должны быть заменены на `assertModelMissing`.
### Доверенные прокси
Если вы обновляете свой проект c Laravel 8 до Laravel 9, импортируя имеющийся код в совершенно новый каркас приложения на Laravel 9, то вам может потребоваться обновить мидлвар «`trusted proxy`».
В файле `app/Http/Middleware/TrustProxies.php` обновите `use Fideloper\Proxy\TrustProxies as Middleware` до `use Illuminate\Http\Middleware\TrustProxies as Middleware`.
### Валидация
### Метод `validated` из FormRequest
Метод `validated` теперь принимает аргументы `$key` и `$default`. Если вы вручную переопределяли этот метод, то вам следует обновить его:
### Правило `password`
Правило `password`, проверяющее соответствие введенного пароля текущему, было переименовано в `current_password`.
### Непроверенные ключи массива
В предыдущих версиях Laravel приходилось вручную указывать валидатору исключать непроверенные ключи массива из проверенных данных, особенно в сочетании с правилом `array`, в котором не указан список разрешенных ключей.
В Laravel 9 непроверенные ключи теперь всегда исключаются из проверенных данных, даже если в правиле `array` не указаны разрешенные ключи. Как правило, такое поведение и является наиболее ожидаемым. Предыдущий метод `excludeUnvalidatedArrayKeys` был добавлен в Laravel 8 только как временная мера для сохранения обратной совместимости.
Хотя это и не рекомендуется, но вы можете вернуться к предыдущего поведению, как в Laravel 8.x, вызвав новый метод `includeUnvalidatedArrayKeys` в методе `boot` одного из провайдеров вашего приложения:
### Разное
Мы также рекомендуем вам просмотреть все изменения в [репозитории laravel/laravel на GitHub](https://github.com/laravel/laravel). Некоторые из этих изменений описаны в данном руководстве по обновлению, некоторые, такие как изменения в файлах конфигурации или комментарии, не включены. Вы можете легко просмотреть их с помощью [инструмента сравнения GitHub](https://github.com/laravel/laravel/compare/8.x...9.x) и выбрать, какие обновления важны именно для вас.
Задать вопросы по урокам можно на [нашем форуме](https://demiart.ru/forum/index.php?showtopic=268805).
[Статьи](https://laravel.demiart.ru/category/articles/)[blade](https://laravel.demiart.ru/tag/blade/)[composer](https://laravel.demiart.ru/tag/composer/)[laravel](https://laravel.demiart.ru/tag/laravel/)[php](https://laravel.demiart.ru/tag/php/)[валидация](https://laravel.demiart.ru/tag/validation/)[исключения](https://laravel.demiart.ru/tag/exceptions/)[локализация](https://laravel.demiart.ru/tag/localization/)[мидлвары](https://laravel.demiart.ru/tag/middleware/)[очереди](https://laravel.demiart.ru/tag/queues/)[пакеты](https://laravel.demiart.ru/tag/packages/)[письма](https://laravel.demiart.ru/tag/emails/)[рефакторинг](https://laravel.demiart.ru/tag/refactoring/)