3 листопада команда Filament випустила v5.11.1 і разом з нею v4.16.1. Номер патч-версії тут вводить в оману: окрім звичних виправлень, Ден Гаррін провів ревізію назв API, і понад сорок методів отримали нові канонічні імена. Старі назви оголошено застарілими, але вони лишаються робочими аліасами, тож оновлення нічого не ламає. Це продовження v5.11.0 з її JavaScript-компонентами і жорсткішим захистом Livewire - там про нові можливості, тут про порядок у тому, що вже є.
Що саме змінилося
Усі зміни зроблено за одним шаблоном: з'являється метод із новою назвою, старий лишається з тими самими аргументами і просто передає виклик далі, а над ним стоїть PHPDoc-позначка:
/**
* @deprecated Use `live()` instead.
*/
public function reactive(): static
Важлива деталь: це лише метадані. Ні trigger_error(), ні E_USER_DEPRECATED у цих методах немає, тож після composer update у логах і тестах нічого не з'явиться. Застарілі виклики побачить IDE (PhpStorm закреслює їх) і PHPStan із пакетом phpstan/phpstan-deprecation-rules. Коли саме аліаси приберуть, у нотатках до випуску не сказано, але застарілі методи у Filament зазвичай зникають з наступною мажорною версією.
Ще одна деталь, яка рятує від зайвої роботи: у pull request #20862 і #20900 була хвиля перейменувань «Form → Schema» - fillForm() на fillSchema(), beforeFormFilled() на beforeSchemaFilled(), createOptionForm() на createOptionSchema() тощо. Ще до випуску окремий коміт «Restore form-specific API names» її відкотив. У тегах v5.11.1 і v4.16.1 цих методів-замінників немає, тож fillForm(), хуки beforeFormFilled() / afterFormValidated(), createOptionForm(), editOptionForm() у Select, getOptionsFormComponents() в імпортерах та експортерах і preserveFormDataWhenCreatingAnother() лишаються як є. Якщо читали дифи в GitHub - не переносьте їх у код.
Найпомітніші заміни
Більшість перейменувань стосується методів, які викликає сам фреймворк. Але кілька трапляються майже в кожному проєкті:
// було
TextInput::make('price')->reactive()->postfix('грн');
$table->deferLoading();
// стало
TextInput::make('price')->live()->suffix('грн');
$table->lazyLoaded();
reactive() давно був просто обгорткою над live(), а postfix() - над suffix(), тепер це зафіксовано офіційно (#20857). У таблицях deferLoading() став lazyLoaded(), а isLoadingDeferred() - isLazyLoaded(). Якщо ви перевизначали isTableLoadingDeferred() у Livewire-компоненті, налаштовуйте відкладене завантаження в методі table(). Хук updatedTableSortDirection() у компонентах з таблицями поступився місцем updatedTableSort().
Шпаргалка за областями
Форми та схеми (#20862, #20869):
Section::formBefore() → contentBefore(), isFormBefore() → isContentBefore();
Get / Set: skipComponentsChildContainersWhileSearching() → skipComponentsChildSchemasWhileSearching();
Builder, Repeater: getRawItemState() → getItemStateSnapshot();
RepeatableEntry::getItemState() → getItemStateWithExistence();
getExtraFieldWrapperAttributesBag() → getExtraFieldWrapperAttributeBag(), так само для Entry;
MentionProvider::hasSearchResultsUsing() → hasSearchResultsUsingCallback();
RichContentAttribute::getCustomBlocksConfig() → getCustomBlocksConfiguration();
SpatieMediaLibraryFileUpload::getConversionsDisk() → getConversionsDiskName().
Таблиці:
deferLoading() → lazyLoaded(), isLoadingDeferred() → isLazyLoaded();
updatedTableSortDirection() → updatedTableSort();
getInverseRelationship() → getInverseRelationshipName();
- у підсумках
hasQueryModification() → hasQueryModificationCallback();
getGetStateUsingCallback() → getStateUsingCallback().
Панелі (#20861, #20868):
NavigationItem::isActiveWhen() → activeWhen(), isChildItemsActive() → hasActiveChildItems();
Cluster::unshiftClusterBreadcrumbs() → prependClusterBreadcrumbs();
passwordResetRequestRouteSlug() → requestPasswordResetRouteSlug(), passwordResetRouteSlug() → resetPasswordRouteSlug();
databaseNotificationsPolling() → databaseNotificationsPollingInterval();
Filament::currentDomain() → setCurrentDomain(), hasDarkModeForced() → isDarkModeForced().
Сам префікс маршруту скидання пароля не змінився - лише назви методів, які його налаштовують.
Нотифікації та віджети (#20867):
pullNotificationsFromSession() → pullNotifications();
- у графіках з фільтрами
resetFiltersForm() → resetFilters();
- на дашборді
normalizeTableFilterValuesFromQueryString() → normalizeFilterValuesFromQueryString().
Імпорт і експорт:
getFileDisk() → getFileDiskName() в експортері та дії експорту;
isEnablingVisibleTableColumnsByDefault() → shouldEnableVisibleTableColumnsByDefault();
ImportColumn::guess() → guesses();
- в події
ImportChunkProcessed: getProcessedRows() → getProcessedRowsCount(), getSuccessfulRows() → getSuccessfulRowsCount().
Генератори (#20860) - для тих, хто розширює make:filament-*: getTableActions() → getTableRecordActions(), outputTableActions() → outputTableRecordActions(), outputTableMethodBulkActions() → outputTableBulkActions(), а в генераторі блоків rich editor configureToPreviewMethod() → configureToPreviewHtmlMethod().
Класи й трейти. Застарілими стали й кілька типів: трейти CanDeferLoading (тепер CanBeLazyLoaded), CanLimitItemsLength (CanLimitItemsCount), HasRowLoopObject (HasRowLoop), клас SchemaIconAlias (SchemasIconAlias), job ExportCompletion (CompleteExport). Трейт сторінки HasMaxWidth із властивістю $maxWidth поступився місцем $maxContentWidth і getMaxContentWidth() у BasePage.
Чи є Rector-правило
Ні. Пакет filament/upgrade у v5 містить лише правила для переходу між мажорними версіями. Згадане в нотатках виправлення Rector (#20882) стосується старого сценарію оновлення з v3 на v4: правила для маршрутів сторінок і ресурсів більше не переписують однойменні методи сторонніх класів. До нових назв воно стосунку не має.
Найчастіші заміни можна зробити стандартним RenameMethodRector - він враховує тип об'єкта, тому не зачепить чужі методи з такою ж назвою:
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Components\Component;
use Filament\Tables\Table;
use Rector\Config\RectorConfig;
use Rector\Renaming\Rector\MethodCall\RenameMethodRector;
use Rector\Renaming\ValueObject\MethodCallRename;
return RectorConfig::configure()
->withPaths([__DIR__ . '/app'])
->withConfiguredRule(RenameMethodRector::class, [
new MethodCallRename(Component::class, 'reactive', 'live'),
new MethodCallRename(TextInput::class, 'postfix', 'suffix'),
new MethodCallRename(Table::class, 'deferLoading', 'lazyLoaded'),
]);
Rector працює лише там, де виводить тип. Ланцюжки на кшталт TextInput::make()->... він розпізнає, а виклики в замиканнях без тайпхінтів - не завжди. Для контролю підійде звичайний пошук:
grep -rnE -- "->(reactive|postfix|deferLoading)\(" app/
Два виправлення поза перейменуваннями
authorizeAny() (#20884). Коли всі перелічені дозволи (abilities) відмовляли, isAuthorized() повертав false, а getAuthorizationResponse() - дозвіл. Виконати дію все одно не вдавалося, але губилася підказка з причиною відмови, не з'являлося сповіщення, а монтування дії не скасовувалося заздалегідь. Тепер повертається перша відмова з її статусом і повідомленням. Порожній authorizeAny([]) відмовляє, порожній authorize([]), як і раніше, дозволяє.
csvDelimiter() у дії експорту (#20902) позначено застарілим, бо він ні на що не впливав. Роздільник CSV задається перевизначенням getCsvDelimiter() у класі експортера. Якщо ви покладалися на метод дії й дивувалися, чому в файлі все одно коми, - ось причина.
Що робити зараз
Оновлюйтеся спокійно: поведінка не змінилася, аліаси передають ті самі аргументи. Перейменовувати варто поступово, поки зміни дрібні. Почніть із reactive(), postfix() і deferLoading() - вони живуть у ресурсах майже кожного проєкту. Якщо в CI вже є PHPStan, додайте phpstan-deprecation-rules, і решту знайде аналізатор. А для 4.x усе те саме вийшло у v4.16.1, тож проєкти, що ще не перейшли на v5, можуть перейменувати методи заздалегідь.