- Изменения с высоким влиянием
- Изменения со средним влиянием
- Изменения с низким влиянием
- Обновление до 5.0 с 4.x
Обновление до 5.0 с 4.x
Примерное время обновления: 30 минут
Мы стараемся описать все возможные изменения, нарушающие обратную совместимость. Часть из них затрагивает редко используемые возможности MoonShine, поэтому на ваше приложение может повлиять лишь некоторая их доля.
Руководство дополняется и будет расширено до выхода версии 5.0. Для обновления с 3.x сначала выполните руководство по обновлению 4.x.
Обновление зависимостей
Вероятность влияния: высокая
Для MoonShine 5.0 требуются PHP 8.4 или новее и Laravel 11, 12 или 13. Laravel 10 больше не поддерживается.
Обновите следующие зависимости в composer.json вашего приложения:
moonshine/moonshineдо^5.0,moonshine/import-exportдо^3.0, если вы используете импорт и экспорт.
composer updatecomposer update
Для MoonShine 5.0 требуются symfony/http-foundation и symfony/psr-http-message-bridge версии 7.4 или 8.1.
Если Composer не может их установить из-за зафиксированных старых версий, обновите пакет вместе с зависимостями:
composer update moonshine/moonshine -Wcomposer update moonshine/moonshine -W
Ресурсы
Фильтры, теги запросов и обработчики
Вероятность влияния: высокая
Трейты HasFilters, HasQueryTags и HasHandlers удалены из ModelResource.
Фильтры, теги запросов и обработчики настраиваются только в IndexPage.
Перенесите следующие методы из ресурса на его индексную страницу:
filters(),queryTags(),handlers(),getIgnoredFields().
namespace App\MoonShine\Resources\Post\Pages;use MoonShine\Laravel\Pages\Crud\IndexPage;use MoonShine\Laravel\QueryTags\QueryTag;use MoonShine\UI\Fields\Text;class PostIndexPage extends IndexPage{protected function filters(): iterable{return [Text::make('Title', 'title'),];}protected function queryTags(): array{return [QueryTag::make('Published',static fn ($query) => $query->where('is_published', true)),];}}
namespace App\MoonShine\Resources\Post\Pages;use MoonShine\Laravel\Pages\Crud\IndexPage;use MoonShine\Laravel\QueryTags\QueryTag;use MoonShine\UI\Fields\Text;class PostIndexPage extends IndexPage{protected function filters(): iterable{return [Text::make('Title', 'title'),];}protected function queryTags(): array{return [QueryTag::make('Published',static fn ($query) => $query->where('is_published', true)),];}}
Методы ресурса hasFilters(), getFilters(), hasQueryTags(), getQueryTags(), hasHandlers() и getHandlers() также удалены.
Вызывайте их у индексной страницы.
-$resource->getFilters();+$resource->getIndexPage()?->getFilters();-$resource->getFilters();+$resource->getIndexPage()?->getFilters();
Значения фильтров и сохраненное состояние запроса по-прежнему читаются из ресурса, например через getFilterParams().
Подробнее в разделах Фильтры, Теги запросов и Обработчики.
Импорт и экспорт
Вероятность влияния: средняя
MoonShine 5.0 работает с moonshine/import-export 3.x.
Трейт ImportExportConcern и интерфейс HasImportExportContract остаются в ресурсе вместе с полями импорта и экспорта.
Кнопки теперь являются обработчиками индексной страницы, поэтому добавьте в нее трейт ImportExportHandlersConcern.
namespace App\MoonShine\Resources\Category\Pages;use MoonShine\ImportExport\Traits\ImportExportHandlersConcern;use MoonShine\Laravel\Pages\Crud\IndexPage;class CategoryIndexPage extends IndexPage{use ImportExportHandlersConcern;}
namespace App\MoonShine\Resources\Category\Pages;use MoonShine\ImportExport\Traits\ImportExportHandlersConcern;use MoonShine\Laravel\Pages\Crud\IndexPage;class CategoryIndexPage extends IndexPage{use ImportExportHandlersConcern;}
Перенесите переопределения методов import(), export(), isExportToCsv() и handlers() из ресурса на индексную страницу.
Внутри страницы ресурс доступен через getResource().
Экранирование
Экранирование отображаемого текста
Вероятность влияния: высокая
Метки, подсказки, префиксы, суффиксы и строки, возвращаемые callback-функциями полей beforeRender() и afterRender(), теперь экранируются по умолчанию.
Метка вида <strong>Name</strong> отображается как текст.
Добавьте соответствующий метод unescape…() там, где нужен HTML.
use MoonShine\UI\Fields\Text;Text::make('<strong>Name</strong>', 'name')+ ->unescapeLabel()->hint('<a href="/help">Help</a>')+ ->unescapeHint();
use MoonShine\UI\Fields\Text;Text::make('<strong>Name</strong>', 'name')+ ->unescapeLabel()->hint('<a href="/help">Help</a>')+ ->unescapeHint();
Значения по умолчанию можно изменить в секции escapes конфигурации.
'escapes' => ['label' => true,'hint' => true,'prefix' => true,'suffix' => true,'before_render' => true,'after_render' => true,],'escapes' => ['label' => true,'hint' => true,'prefix' => true,'suffix' => true,'before_render' => true,'after_render' => true,],
Названия ссылок полей, метки связанных записей и заголовки модальных окон экранируются независимо от этих настроек.
Чтобы разрешить в них HTML, используйте unescapeLinkName(), unescapeOptionLabels() и unescapeTitle().
Значения, реализующие Illuminate\Contracts\Support\Htmlable, например HtmlString, выводятся как подготовленный HTML.
Разрешайте HTML только для доверенного содержимого. Отключение экранирования не очищает строку.
Все настройки описаны в разделе Экранирование отображаемого текста.
Экранирование значений полей
Вероятность влияния: низкая
Значения полей Text, Textarea и BelongsTo по-прежнему экранируются по умолчанию.
Новые настройки escapes.value и escapes.value_on_apply меняют это поведение глобально, поэтому, если оставить их включенными, ничего менять не нужно.
'escapes' => [// ...'value' => true,'value_on_apply' => true,],'escapes' => [// ...'value' => true,'value_on_apply' => true,],
Если ваше поле использует трейт WithEscapedValue и переобъявляет свойство $unescape, измените его тип на ?bool.
null означает, что поле следует глобальной настройке.
-protected bool $unescape = false;+protected ?bool $unescape = null;-protected bool $unescape = false;+protected ?bool $unescape = null;
Вызов escapeOnApply() без аргумента теперь всегда включает экранирование при применении, даже если escapes.value_on_apply выключен.
Настройки отдельного поля описаны в разделе Text.
Редактирование в popover
Вероятность влияния: очень низкая
Редактирование в popover через updateOnPreview() теперь экранирует значение, если поле не реализует MoonShine\UI\Contracts\HasEscapedValueContract или не вызывает unescape().
Встроенные поля Text, Textarea и BelongsTo реализуют этот контракт.
Собственное поле с трейтом WithEscapedValue должно реализовать этот контракт, чтобы в popover сохранялись неэкранированные значения.
Поля и компоненты
Переопределенные представления
Вероятность влияния: средняя
В версии 5.0 изменились многие представления компонентов. Если в приложении опубликованы и изменены какие-либо из представлений ниже, сравните их с новыми версиями и обновите.
Представления, выводящие метки, подсказки и заголовки, теперь выводят подготовленные в PHP значения, например $labelHtml, $hintHtml, $titleHtml и $valueHtml, которые уже учитывают настройки экранирования отображаемого текста.
Опубликованная копия с {!! $label !!} обходит экранирование, а копия с {{ $label }} игнорирует unescapeLabel().
moonshine::components.card,collapse,field-container,heading,modal,off-canvas,tabs,moonshine::components.form.fieldset,form.hint,form.wrapper,form.input-extensions.ext,form.input-extensions.prefix,moonshine::components.layout.box,layout.divider,layout.footer,moonshine::components.link-button,link-native,moonshine::components.menu.divider,menu.group,menu.item-link,moonshine::components.metrics.value,metrics.wrapped.value,moonshine::components.table.index,moonshine::fields.fieldset,fields.relationships.belongs-to-many.
Несколько часто используемых представлений теперь выводят элементы напрямую, без вложенных Blade-компонентов.
Их данные тоже подготавливаются в PHP, например $tagAttributes и $labelHtml в представлении кнопки.
moonshine::components.action-button,moonshine::components.form.builder,moonshine::components.icon,moonshine::components.rating,moonshine::fields.hidden.
Строки вертикальных таблиц по умолчанию, например на DetailPage, выводятся новым представлением moonshine::components.table.vertical-field.
Представления layout.grid, layout.column и layout.div для них больше не используются, поэтому их переопределения на эти строки не влияют.
Переопределяйте moonshine::components.table.vertical-field.
Строки, настроенные через замыкания title или value метода vertical(), по-прежнему используют компоненты.
Расширения файлов
Вероятность влияния: низкая
Поля File и Image наследуют новый глобальный список allowed_extensions, если у поля не вызван allowedExtensions().
Значение по умолчанию [] разрешает все расширения, поэтому в существующих приложениях ничего менять не нужно.
Если ваш класс поля наследует File или Image и переобъявляет свойство $allowedExtensions, измените его тип на ?array.
null означает, что поле следует глобальному списку.
-protected array $allowedExtensions = ['pdf'];+protected ?array $allowedExtensions = ['pdf'];-protected array $allowedExtensions = ['pdf'];+protected ?array $allowedExtensions = ['pdf'];
Метод allowedExtensions() контракта MoonShine\UI\Contracts\FileableContract теперь принимает array|string.
Обновите его сигнатуру в собственных реализациях и переопределениях.
-public function allowedExtensions(array $allowedExtensions): static+public function allowedExtensions(array|string $allowedExtensions): static-public function allowedExtensions(array $allowedExtensions): static+public function allowedExtensions(array|string $allowedExtensions): static
Атрибут accept по умолчанию теперь добавляется при рендере поля, поэтому до рендера getAttribute('accept') возвращает null, если у поля не вызывались accept() или allowedExtensions().
Подробнее в разделе File.
URL ссылок
Вероятность влияния: низкая
Компонент Link и ссылки поля Url теперь допускают только схемы http, https, mailto и tel, а также относительные URL и якоря.
Ссылки с другими схемами, например javascript: или ftp:, выводятся с href="#".
Текст ссылки не меняется.
Скелетон и спиннер таблиц
Вероятность влияния: низкая
Скелетон и спиннер выводятся только для асинхронных таблиц.
Методы skeleton() и loader() не влияют на синхронные таблицы.
Выпадающие меню
Вероятность влияния: очень низкая
Экземпляр Popper у выпадающего меню создается при первом открытии.
До этого свойство popperInstance Alpine-компонента dropdown равно null.
Проверяйте его перед вызовом методов из собственного JavaScript.
Устаревшие API
Удаленные классы
Вероятность влияния: средняя
Классы, помеченные устаревшими в 4.x, удалены.
| Класс | Замена |
|---|---|
MoonShine\Laravel\Handlers\Handler |
MoonShine\Crud\Handlers\Handler |
MoonShine\Laravel\Handlers\Handlers |
MoonShine\Crud\Handlers\Handlers |
MoonShine\Laravel\Notifications\NotificationButton |
MoonShine\Crud\Notifications\NotificationButton |
MoonShine\Laravel\Http\Responses\MoonShineJsonResponse |
MoonShine\Crud\JsonResponse |
MoonShine\Laravel\Http\Requests\Relations\AsyncSearchRequest |
MoonShine\Laravel\Http\Requests\Relations\RelationModelFieldRequest |
MoonShine\Laravel\MoonShineUI |
Хелпер toast() вместо MoonShineUI::toast() |
-use MoonShine\Laravel\Handlers\Handler;+use MoonShine\Crud\Handlers\Handler;-use MoonShine\Laravel\Http\Responses\MoonShineJsonResponse;+use MoonShine\Crud\JsonResponse;-MoonShineUI::toast('Saved');+toast('Saved');-use MoonShine\Laravel\Handlers\Handler;+use MoonShine\Crud\Handlers\Handler;-use MoonShine\Laravel\Http\Responses\MoonShineJsonResponse;+use MoonShine\Crud\JsonResponse;-MoonShineUI::toast('Saved');+toast('Saved');
Конфигурация
Значения конфигурации
Вероятность влияния: низкая
Значения конфигурации теперь проверяются при чтении, а некорректное значение вызывает TypeError.
middleware,auth.pipelinesиpagesдолжны быть массивами строк, например имен классов. Замыкания и объекты вauth.pipelinesбольше не поддерживаются, поэтому регистрируйте каждый pipeline как класс.pagesдолжен содержать классы страниц,layoutдолжен наследоватьMoonShine\Crud\Layouts\AbstractLayout, аpaletteдолжен реализовыватьMoonShine\Contracts\ColorManager\PaletteContract.
'auth' => ['pipelines' => [- static fn ($request, $next) => $next($request),+ \App\MoonShine\AuthPipelines\TwoFactorAuthentication::class,],],'auth' => ['pipelines' => [- static fn ($request, $next) => $next($request),+ \App\MoonShine\AuthPipelines\TwoFactorAuthentication::class,],],
Расширение MoonShine
Обертка запроса
Вероятность влияния: очень низкая
Свойство $request класса MoonShine\Core\AbstractRequest теперь имеет тип ServerRequestInterface|Closure.
PSR-запрос создается лениво, при чтении данных запроса.
Если ваш класс наследует AbstractRequest и читает $this->request напрямую, используйте метод getRequest().
-$this->request->getQueryParams();+$this->getRequest()->getQueryParams();-$this->request->getQueryParams();+$this->getRequest()->getQueryParams();
Контракты
Вероятность влияния: очень низкая
Если ваши классы реализуют контракты MoonShine напрямую, а не наследуют базовые классы, добавьте новые методы:
MoonShine\Contracts\UI\ComponentContract:when()иunless(), например через трейтIlluminate\Support\Traits\Conditionable,MoonShine\Contracts\Core\DependencyInjection\TranslatorContract:getString(),MoonShine\Contracts\Core\HasResourceContract:getResourceOrFail(), его реализует трейтMoonShine\Core\Traits\HasResource,MoonShine\Crud\Contracts\Notifications\NotificationButtonContract:toArray().
RequestContract::getScalar() теперь возвращает string|int|float|bool|null вместо mixed. Обновите тип возврата в собственных реализациях.
Новые контракты экранирования, например HasLabelEscapingContract или HasEscapedValueContract, необязательны.