<? phpukraine ДОКУМЕНТАЦІЯ
⌕Пошук по платформі
Документація українською

Переклад офіційної документації українською. Кожен розділ показує стан готовності: недоперекладене позначене відкрито, а не приховане.

ВЕРСІЯ
АКТУАЛЬНА Актуальний реліз. Переклад наздоганяє оригінал, розділи з низьким відсотком позначені у змісті.
РЕСУРСИ · ПЕРЕКЛАДЕНО оновлено 23 вересня 2026

Звʼязки · Filament

Filament дає кілька способів керувати звʼязками в застосунку. Який саме інструмент брати, залежить від типу звʼязку та бажаного інтерфейсу.

Вибір правильного інструмента

Filament дає багато способів керувати звʼязками в застосунку. Яку функцію використати, залежить від типу звʼязку, яким ви керуєте, і від того, який інтерфейс вам потрібен.

Менеджери звʼязків - інтерактивні таблиці під формами ресурсу

Сумісні зі звʼязками HasMany, HasManyThrough, BelongsToMany, MorphMany і MorphToMany.

Менеджери звʼязків - це інтерактивні таблиці, які дозволяють адміністраторам переглядати, створювати, прикріплювати, асоціювати, редагувати, відкріплювати, розʼєднувати та видаляти повʼязані записи, не залишаючи сторінки Edit або View ресурсу.

Select і список чекбоксів - вибір з наявних записів або створення нового

Сумісні зі звʼязками BelongsTo, MorphTo і BelongsToMany.

За допомогою select користувачі зможуть обирати зі списку наявних записів. Ви також можете додати кнопку, яка дозволяє створити новий запис у модальному вікні, не залишаючи сторінки.

Коли ви використовуєте звʼязок BelongsToMany разом із select, можна буде вибрати кілька варіантів, а не один. Записи автоматично додадуться до проміжної таблиці після надсилання форми. За бажання випадний список із множинним вибором можна замінити простим списком чекбоксів. Обидва компоненти працюють однаково.

Repeater - CRUD для кількох повʼязаних записів усередині форми власника

Сумісні зі звʼязками HasMany і MorphMany.

Repeater - це звичайні компоненти форми, які можуть нескінченно рендерити повторюваний набір полів. Їх можна підключити до звʼязку, щоб записи автоматично читалися, створювалися, оновлювалися та видалялися з повʼязаної таблиці. Вони живуть усередині основної схеми форми й доступні як на сторінках ресурсу, так і вкладеними всередині модальних вікон дій.

З погляду UX таке рішення підходить лише тоді, коли повʼязана модель має небагато полів. Інакше форма стане дуже довгою.

Компоненти розмітки форми - збереження полів форми в один звʼязок

Сумісні зі звʼязками BelongsTo, HasOne і MorphOne.

Усі компоненти розмітки форми (Grid, Section, Fieldset тощо) мають метод relationship(). Коли ви його використовуєте, усі поля всередині цієї розмітки зберігаються в повʼязану модель замість моделі власника:

use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
use Filament\Schemas\Components\Fieldset;

Fieldset::make('Metadata')
    ->relationship('metadata')
    ->schema([
        TextInput::make('title'),
        Textarea::make('description'),
        FileUpload::make('image'),
    ])

У цьому прикладі title, description та image автоматично завантажуються зі звʼязку metadata і зберігаються назад після надсилання форми. Якщо запису metadata не існує, його буде створено автоматично.

Детальніше ця можливість описана в документації форм. Зазирніть на ту сторінку по докладнішу інформацію про використання.

Створення менеджера звʼязків

Щоб створити менеджер звʼязків, скористайтеся командою make:filament-relation-manager:

php artisan make:filament-relation-manager CategoryResource posts title
  • CategoryResource - імʼя класу ресурсу для моделі-власника (батьківської).
  • posts - імʼя звʼязку, яким ви хочете керувати.
  • title - імʼя атрибута, за яким ідентифікуватимуться пости.

Це створить файл CategoryResource/RelationManagers/PostsRelationManager.php. У ньому буде клас, де можна визначити форму і таблицю для менеджера звʼязків:

use Filament\Forms;
use Filament\Schemas\Schema;
use Filament\Tables;
use Filament\Tables\Table;

public function form(Schema $schema): Schema
{
    return $schema
        ->components([
            Forms\Components\TextInput::make('title')->required(),
            // ...
        ]);
}

public function table(Table $table): Table
{
    return $table
        ->columns([
            Tables\Columns\TextColumn::make('title'),
            // ...
        ]);
}

Новий менеджер звʼязків потрібно зареєструвати в методі getRelations() вашого ресурсу:

public static function getRelations(): array
{
    return [
        RelationManagers\PostsRelationManager::class,
    ];
}

Коли таблицю й форму для менеджера звʼязків визначено, відкрийте сторінку Edit або View вашого ресурсу, щоб побачити його в дії.

Налаштування URL-параметра менеджера звʼязків

Якщо передати ключ у масиві, який повертає getRelations(), він використовуватиметься в URL для цього менеджера звʼязків під час перемикання між кількома менеджерами. Наприклад, можна передати posts, щоб в URL було ?relation=posts замість числового індексу масиву:

public static function getRelations(): array
{
    return [
        'posts' => RelationManagers\PostsRelationManager::class,
    ];
}

Режим «лише для читання»

Менеджери звʼязків зазвичай відображаються на сторінці Edit або View ресурсу. На сторінці View Filament автоматично ховає всі дії, які змінюють звʼязок: створення, редагування й видалення. Ми називаємо це «режимом лише для читання», і він увімкнений за замовчуванням, щоб зберегти поведінку сторінки View. Втім, цю поведінку можна вимкнути, перевизначивши метод isReadOnly() у класі менеджера звʼязків так, щоб він завжди повертав false:

public function isReadOnly(): bool
{
    return false;
}

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

use Filament\Panel;

public function panel(Panel $panel): Panel
{
    return $panel
        // ...
        ->readOnlyRelationManagersOnResourceViewPagesByDefault(false);
}

Нетипові імена зворотних звʼязків

Для зворотних звʼязків, які не відповідають правилам іменування Laravel, може знадобитися метод inverseRelationship() у таблиці:

use Filament\Tables;
use Filament\Tables\Table;

public function table(Table $table): Table
{
    return $table
        ->columns([
            Tables\Columns\TextColumn::make('title'),
            // ...
        ])
        ->inverseRelationship('section'); // Оскільки зворотна повʼязана модель - `Category`, зазвичай це `category`, а не `section`.
}

Робота з мʼяким видаленням

За замовчуванням ви не зможете взаємодіяти з видаленими записами в менеджері звʼязків. Якщо хочете додати можливість відновлювати, примусово видаляти й фільтрувати видалені записи, використайте прапорець --soft-deletes під час генерації менеджера звʼязків:

php artisan make:filament-relation-manager CategoryResource posts title --soft-deletes

Докладніше про мʼяке видалення можна дізнатися тут.

Перелік повʼязаних записів

Повʼязані записи виводяться в таблиці. Увесь менеджер звʼязків побудований навколо цієї таблиці, яка містить дії для створення, редагування, прикріплення / відкріплення, асоціювання / розʼєднання і видалення записів.

Для налаштування менеджерів звʼязків можна використовувати будь-які можливості Table Builder.

Вивід атрибутів проміжної таблиці

Для звʼязків BelongsToMany і MorphToMany можна додати атрибути проміжної таблиці. Наприклад, якщо у вас є TeamsRelationManager для UserResource і ви хочете додати в таблицю атрибут role із проміжної таблиці, скористайтеся:

use Filament\Tables;

public function table(Table $table): Table
{
    return $table
        ->columns([
            Tables\Columns\TextColumn::make('name'),
            Tables\Columns\TextColumn::make('role'),
        ]);
}

Переконайтеся, що всі атрибути проміжної таблиці перелічені в методі withPivot() звʼязку і зворотного звʼязку.

Створення повʼязаних записів

Створення з атрибутами проміжної таблиці

Для звʼязків BelongsToMany і MorphToMany можна додати атрибути проміжної таблиці. Наприклад, якщо у вас є TeamsRelationManager для UserResource і ви хочете додати атрибут role із проміжної таблиці у форму створення, скористайтеся:

use Filament\Forms;
use Filament\Schemas\Schema;

public function form(Schema $schema): Schema
{
    return $schema
        ->components([
            Forms\Components\TextInput::make('name')->required(),
            Forms\Components\TextInput::make('role')->required(),
            // ...
        ]);
}

Переконайтеся, що всі атрибути проміжної таблиці перелічені в методі withPivot() звʼязку і зворотного звʼязку.

Налаштування CreateAction

Про те, як налаштувати CreateAction, зокрема змінювати дані форми, повідомлення та додавати хуки життєвого циклу, читайте в документації дій.

Редагування повʼязаних записів

Редагування з атрибутами проміжної таблиці

Для звʼязків BelongsToMany і MorphToMany можна редагувати й атрибути проміжної таблиці. Наприклад, якщо у вас є TeamsRelationManager для UserResource і ви хочете додати атрибут role із проміжної таблиці у форму редагування, скористайтеся:

use Filament\Forms;
use Filament\Schemas\Schema;

public function form(Schema $schema): Schema
{
    return $schema
        ->components([
            Forms\Components\TextInput::make('name')->required(),
            Forms\Components\TextInput::make('role')->required(),
            // ...
        ]);
}

Переконайтеся, що всі атрибути проміжної таблиці перелічені в методі withPivot() звʼязку і зворотного звʼязку.

Налаштування EditAction

Про те, як налаштувати EditAction, зокрема змінювати дані форми, повідомлення та додавати хуки життєвого циклу, читайте в документації дій.

Прикріплення й відкріплення записів

Filament уміє прикріплювати й відкріплювати записи для звʼязків BelongsToMany і MorphToMany.

Генеруючи менеджер звʼязків, можна передати прапорець --attach, щоб додати в таблицю ще й AttachAction, DetachAction і DetachBulkAction:

php artisan make:filament-relation-manager CategoryResource posts title --attach

Або, якщо ресурс уже згенеровано, просто додайте дії до масивів $table:

use Filament\Actions\AttachAction;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DetachAction;
use Filament\Actions\DetachBulkAction;
use Filament\Tables\Table;

public function table(Table $table): Table
{
    return $table
        ->columns([
            // ...
        ])
        ->headerActions([
            // ...
            AttachAction::make(),
        ])
        ->recordActions([
            // ...
            DetachAction::make(),
        ])
        ->toolbarActions([
            BulkActionGroup::make([
                // ...
                DetachBulkAction::make(),
            ]),
        ]);
}

AssociateAction, AttachAction, DetachAction і DissociateAction (а також їхні масові варіанти) перевіряють лише стан isReadOnly() менеджера звʼязків - за замовчуванням вони не звертаються до жодного методу політики моделі. Масові дії видалення, примусового видалення й відновлення використовують методи політики deleteAny(), forceDeleteAny() і restoreAny() (один виклик на всю партію) заради продуктивності. Якщо вам потрібна авторизація кожного запису окремо в масовій дії, викличте на ній authorizeIndividualRecords('ability'), погоджуючись на додаткову вартість запитів.

Попереднє завантаження варіантів у select модального вікна прикріплення

За замовчуванням, поки ви шукаєте запис для прикріплення, варіанти завантажуються з бази даних через AJAX. Якщо хочете натомість завантажити їх наперед, коли форму вперше відкрито, скористайтеся методом preloadRecordSelect() у AttachAction:

use Filament\Actions\AttachAction;

AttachAction::make()
    ->preloadRecordSelect()

Прикріплення з атрибутами проміжної таблиці

Коли ви прикріплюєте запис кнопкою Attach, може знадобитися власна форма для додавання атрибутів проміжної таблиці до звʼязку:

use Filament\Actions\AttachAction;
use Filament\Forms;

AttachAction::make()
    ->schema(fn (AttachAction $action): array => [
        $action->getRecordSelect(),
        Forms\Components\TextInput::make('role')->required(),
    ])

У цьому прикладі $action->getRecordSelect() повертає поле select для вибору запису, який потрібно прикріпити. Текстове поле role потім зберігається в колонку role проміжної таблиці.

Переконайтеся, що всі атрибути проміжної таблиці перелічені в методі withPivot() звʼязку і зворотного звʼязку.

Обмеження варіантів для прикріплення

Може знадобитися обмежити варіанти, доступні в AttachAction:

use Filament\Actions\AttachAction;
use Illuminate\Database\Eloquent\Builder;

AttachAction::make()
    ->recordSelectOptionsQuery(fn (Builder $query) => $query->whereBelongsTo(auth()->user()))

Пошук варіантів для прикріплення за кількома колонками

За замовчуванням варіанти, доступні в AttachAction, шукаються за recordTitleAttribute() таблиці. Якщо хочете шукати за кількома колонками, скористайтеся методом recordSelectSearchColumns():

use Filament\Actions\AttachAction;

AttachAction::make()
    ->recordSelectSearchColumns(['title', 'description'])

Прикріплення кількох записів

Метод multiple() у компоненті AttachAction дозволяє вибирати кілька значень:

use Filament\Actions\AttachAction;

AttachAction::make()
    ->multiple()

Налаштування поля select у модальному вікні прикріплення

Обʼєкт поля select, який використовується під час прикріплення, можна налаштувати, передавши функцію в метод recordSelect():

use Filament\Actions\AttachAction;
use Filament\Forms\Components\Select;

AttachAction::make()
    ->recordSelect(
        fn (Select $select) => $select->placeholder('Select a post'),
    )

Вибір записів для прикріплення через таблицю в модальному вікні

Методом tableSelect() можна вибирати записи в модальному вікні прикріплення за допомогою повноцінної таблиці Filament замість простого випадного списку:

use App\Filament\Resources\Products\Tables\ProductsTable;
use Filament\Actions\AttachAction;

AttachAction::make()
    ->tableSelect(ProductsTable::class)

У цьому прикладі клас ProductsTable - звичайний клас таблиці Filament із методом configure(), який визначає колонки таблиці:

use Filament\Tables\Columns\TextColumn;
use Filament\Tables\Table;

public static function configure(Table $table): Table
{
    return $table
        ->columns([
            TextColumn::make('name'),
            TextColumn::make('sku'),
            // ...
        ])
        ->filters([
            // ...
        ]);
}

Фільтрація запиту таблиці (через modifyQueryUsing(), фільтри або аргументи таблиці) є презентаційною: вона впливає лише на те, які записи показані для вибору. Це не межа безпеки: користувач, який підробить надісланий стан модального вікна, може прикріпити запис, виключений із видимої таблиці.

Щоб обмежити, які записи справді можна прикріпити, звузьте варіанти за допомогою методу recordSelectOptionsQuery(). Filament звіряє надісланий запис із цим запитом, тож записи поза ним відхиляються:

use App\Filament\Resources\Products\Tables\ProductsTable;
use Filament\Actions\AttachAction;
use Illuminate\Database\Eloquent\Builder;

AttachAction::make()
    ->tableSelect(ProductsTable::class)
    ->recordSelectOptionsQuery(fn (Builder $query) => $query->whereBelongsTo(auth()->user()))

Робота з дублікатами

За замовчуванням прикріпити той самий запис більше ніж раз не вийде. Причина в тому, що для цієї можливості потрібно ще й налаштувати первинну колонку id у проміжній таблиці.

Переконайтеся, що атрибут id перелічений у методі withPivot() звʼязку і зворотного звʼязку.

Нарешті, додайте до таблиці метод allowDuplicates():

public function table(Table $table): Table
{
    return $table
        ->allowDuplicates();
}

Пришвидшення масових дій відкріплення

За замовчуванням DetachBulkAction завантажує всі Eloquent-записи в памʼять, а потім проходить по них і відкріплює по одному.

Якщо ви відкріплюєте велику кількість записів, може знадобитися метод chunkSelectedRecords(), щоб брати меншу кількість записів за раз. Це зменшить споживання памʼяті вашим застосунком:

use Filament\Actions\DetachBulkAction;

DetachBulkAction::make()
    ->chunkSelectedRecords(250)

Filament завантажує Eloquent-записи в памʼять перед відкріпленням із двох причин:

  • Щоб дати змогу авторизувати окремі записи колекції політикою моделі перед відкріпленням (наприклад, через authorizeIndividualRecords('delete')).
  • Щоб гарантувати, що під час відкріплення запускаються події моделі, як-от deleting і deleted в обсервері моделі.

Якщо вам не потрібні ні авторизація окремих записів політикою, ні події моделі, скористайтеся методом fetchSelectedRecords(false): він не завантажуватиме записи в памʼять перед відкріпленням і натомість відкріпить їх одним запитом:

use Filament\Actions\DetachBulkAction;

DetachBulkAction::make()
    ->fetchSelectedRecords(false)

Асоціювання й розʼєднання записів

Filament уміє асоціювати й розʼєднувати записи для звʼязків HasMany і MorphMany.

Генеруючи менеджер звʼязків, можна передати прапорець --associate, щоб додати в таблицю ще й AssociateAction, DissociateAction і DissociateBulkAction:

php artisan make:filament-relation-manager CategoryResource posts title --associate

Або, якщо ресурс уже згенеровано, просто додайте дії до масивів $table:

use Filament\Actions\AssociateAction;
use Filament\Actions\BulkActionGroup;
use Filament\Actions\DissociateAction;
use Filament\Actions\DissociateBulkAction;
use Filament\Tables\Table;

public function table(Table $table): Table
{
    return $table
        ->columns([
            // ...
        ])
        ->headerActions([
            // ...
            AssociateAction::make(),
        ])
        ->recordActions([
            // ...
            DissociateAction::make(),
        ])
        ->toolbarActions([
            BulkActionGroup::make([
                // ...
                DissociateBulkAction::make(),
            ]),
        ]);
}

Попереднє завантаження варіантів у select модального вікна асоціювання

За замовчуванням, поки ви шукаєте запис для асоціювання, варіанти завантажуються з бази даних через AJAX. Якщо хочете натомість завантажити їх наперед, коли форму вперше відкрито, скористайтеся методом preloadRecordSelect() у AssociateAction:

use Filament\Actions\AssociateAction;

AssociateAction::make()
    ->preloadRecordSelect()

Обмеження варіантів для асоціювання

Може знадобитися обмежити варіанти, доступні в AssociateAction:

use Filament\Actions\AssociateAction;
use Illuminate\Database\Eloquent\Builder;

AssociateAction::make()
    ->recordSelectOptionsQuery(fn (Builder $query) => $query->whereBelongsTo(auth()->user()))

Пошук варіантів для асоціювання за кількома колонками

За замовчуванням варіанти, доступні в AssociateAction, шукаються за recordTitleAttribute() таблиці. Якщо хочете шукати за кількома колонками, скористайтеся методом recordSelectSearchColumns():

use Filament\Actions\AssociateAction;

AssociateAction::make()
    ->recordSelectSearchColumns(['title', 'description'])

Асоціювання кількох записів

Метод multiple() у компоненті AssociateAction дозволяє вибирати кілька значень:

use Filament\Actions\AssociateAction;

AssociateAction::make()
    ->multiple()

Налаштування поля select у модальному вікні асоціювання

Обʼєкт поля select, який використовується під час асоціювання, можна налаштувати, передавши функцію в метод recordSelect():

use Filament\Actions\AssociateAction;
use Filament\Forms\Components\Select;

AssociateAction::make()
    ->recordSelect(
        fn (Select $select) => $select->placeholder('Select a post'),
    )

Пришвидшення масових дій розʼєднання

За замовчуванням DissociateBulkAction завантажує всі Eloquent-записи в памʼять, а потім проходить по них і розʼєднує по одному.

Якщо ви розʼєднуєте велику кількість записів, може знадобитися метод chunkSelectedRecords(), щоб брати меншу кількість записів за раз. Це зменшить споживання памʼяті вашим застосунком:

use Filament\Actions\DissociateBulkAction;

DissociateBulkAction::make()
    ->chunkSelectedRecords(250)

Filament завантажує Eloquent-записи в памʼять перед розʼєднанням із двох причин:

  • Щоб дати змогу авторизувати окремі записи колекції політикою моделі перед розʼєднанням (наприклад, через authorizeIndividualRecords('update')).
  • Щоб гарантувати, що під час розʼєднання запускаються події моделі, як-от updating і updated в обсервері моделі.

Якщо вам не потрібні ні авторизація окремих записів політикою, ні події моделі, скористайтеся методом fetchSelectedRecords(false): він не завантажуватиме записи в памʼять перед розʼєднанням і натомість розʼєднає їх одним запитом:

use Filament\Actions\DissociateBulkAction;

DissociateBulkAction::make()
    ->fetchSelectedRecords(false)

Перегляд повʼязаних записів

Генеруючи менеджер звʼязків, можна передати прапорець --view, щоб додати в таблицю ще й ViewAction:

php artisan make:filament-relation-manager CategoryResource posts title --view

Або, якщо менеджер звʼязків уже згенеровано, просто додайте ViewAction до масиву $table->recordActions():

use Filament\Actions\ViewAction;
use Filament\Tables\Table;

public function table(Table $table): Table
{
    return $table
        ->columns([
            // ...
        ])
        ->recordActions([
            ViewAction::make(),
            // ...
        ]);
}

Видалення повʼязаних записів

За замовчуванням ви не зможете взаємодіяти з видаленими записами в менеджері звʼязків. Якщо хочете додати можливість відновлювати, примусово видаляти й фільтрувати видалені записи, використайте прапорець --soft-deletes під час генерації менеджера звʼязків:

php artisan make:filament-relation-manager CategoryResource posts title --soft-deletes

Або можна додати мʼяке видалення до наявного менеджера звʼязків:

use Filament\Actions\DeleteAction;
use Filament\Actions\DeleteBulkAction;
use Filament\Actions\ForceDeleteAction;
use Filament\Actions\ForceDeleteBulkAction;
use Filament\Actions\RestoreAction;
use Filament\Actions\RestoreBulkAction;
use Filament\Tables\Filters\TrashedFilter;
use Filament\Tables\Table;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\SoftDeletingScope;

public function table(Table $table): Table
{
    return $table
        ->modifyQueryUsing(fn (Builder $query) => $query->withoutGlobalScopes([
            SoftDeletingScope::class,
        ]))
        ->columns([
            // ...
        ])
        ->filters([
            TrashedFilter::make(),
            // ...
        ])
        ->recordActions([
            DeleteAction::make(),
            ForceDeleteAction::make(),
            RestoreAction::make(),
            // ...
        ])
        ->toolbarActions([
            BulkActionGroup::make([
                DeleteBulkAction::make(),
                ForceDeleteBulkAction::make(),
                RestoreBulkAction::make(),
                // ...
            ]),
        ]);
}

Налаштування DeleteAction

Про те, як налаштувати DeleteAction, зокрема змінити повідомлення й додати хуки життєвого циклу, читайте в документації дій.

Імпорт повʼязаних записів

ImportAction можна додати в шапку менеджера звʼязків, щоб імпортувати записи. У такому разі імпортеру, ймовірно, треба повідомити, якому власнику належать нові записи. Скористайтеся опціями імпорту, щоб передати ID запису-власника:

ImportAction::make()
    ->importer(ProductImporter::class)
    ->options(['categoryId' => $this->getOwnerRecord()->getKey()])

Тепер у класі імпортера можна асоціювати власника з імпортованим записом у звʼязку «один до багатьох»:

public function resolveRecord(): ?Product
{
    $product = Product::firstOrNew([
        'sku' => $this->data['sku'],
    ]);
    
    $product->category()->associate($this->options['categoryId']);
    
    return $product;
}

Або можна прикріпити запис у звʼязку «багато до багатьох», використавши хук afterSave() імпортера:

protected function afterSave(): void
{
    $this->record->categories()->syncWithoutDetaching([$this->options['categoryId']]);
}

Доступ до запису-власника звʼязку

Менеджери звʼязків - це Livewire-компоненти. Коли вони вперше завантажуються, запис-власник (Eloquent-запис, який виступає батьківським, тобто модель основного ресурсу) зберігається у властивість. Прочитати цю властивість можна так:

$this->getOwnerRecord()

Проте всередині static-методу на кшталт form() чи table() $this недоступний. Тож можна скористатися колбеком, щоб дістати екземпляр $livewire:

use Filament\Forms;
use Filament\Resources\RelationManagers\RelationManager;
use Filament\Schemas\Schema;

public function form(Schema $schema): Schema
{
    return $schema
        ->components([
            Forms\Components\Select::make('store_id')
                ->options(function (RelationManager $livewire): array {
                    return $livewire->getOwnerRecord()->stores()
                        ->pluck('name', 'id')
                        ->toArray();
                }),
            // ...
        ]);
}

Усі методи в Filament приймають колбек, усередині якого доступний $livewire->ownerRecord.

Групування менеджерів звʼязків

Менеджери звʼязків можна згрупувати в одну вкладку. Для цього оберніть кілька менеджерів в обʼєкт RelationGroup із підписом:

use Filament\Resources\RelationManagers\RelationGroup;

public static function getRelations(): array
{
    return [
        RelationGroup::make('Interactions', [
            RelationManagers\CommentsRelationManager::class,
            RelationManagers\TagsRelationManager::class,
        ]),
        RelationGroup::make('Links', [
            RelationManagers\LinksRelationManager::class,
        ]),
    ];
}

Умовне відображення менеджерів звʼязків

За замовчуванням менеджери звʼязків видимі, якщо метод viewAny() політики повʼязаної моделі повертає true.

Методом canViewForRecord() можна визначити, чи має менеджер звʼязків бути видимим для конкретного запису-власника й сторінки:

use Illuminate\Database\Eloquent\Model;

public static function canViewForRecord(Model $ownerRecord, string $pageClass): bool
{
    return $ownerRecord->status === Status::Draft;
}

Обʼєднання вкладок менеджерів звʼязків із формою

У класі сторінки Edit або View перевизначте метод hasCombinedRelationManagerTabsWithContent():

public function hasCombinedRelationManagerTabsWithContent(): bool
{
    return true;
}

Налаштування вкладки з вмістом

У класі сторінки Edit або View перевизначте метод getContentTabComponent() і скористайтеся будь-якими методами налаштування Tab:

use Filament\Schemas\Components\Tabs\Tab;

public function getContentTabComponent(): Tab
{
    return Tab::make('Settings')
        ->icon('heroicon-m-cog');
}

Позиція вкладки з формою

За замовчуванням вкладка з формою рендериться перед вкладками звʼязків. Щоб показати її після них, перевизначте метод getContentTabPosition() у класі сторінки Edit або View:

use Filament\Resources\Pages\Enums\ContentTabPosition;

public function getContentTabPosition(): ?ContentTabPosition
{
    return ContentTabPosition::After;
}

Налаштування вкладок менеджерів звʼязків

Щоб налаштувати вкладку менеджера звʼязків, перевизначте метод getTabComponent() і скористайтеся будь-якими методами налаштування Tab:

use Filament\Schemas\Components\Tabs\Tab;
use Illuminate\Database\Eloquent\Model;

public static function getTabComponent(Model $ownerRecord, string $pageClass): Tab
{
    return Tab::make('Blog posts')
        ->badge($ownerRecord->posts()->count())
        ->badgeColor('info')
        ->badgeTooltip('The number of posts in this category')
        ->icon('heroicon-m-document-text');
}

Окрім статичних значень, методи badgeColor() і badgeTooltip() приймають також функції для динамічного обчислення. У ці функції можна впроваджувати різні утиліти як параметри.

Якщо ви використовуєте групу звʼязків, скористайтеся методом tab():

use Filament\Resources\RelationManagers\RelationGroup;
use Filament\Schemas\Components\Tabs\Tab;
use Illuminate\Database\Eloquent\Model;

RelationGroup::make('Contacts', [
    // ...
])
    ->tab(fn (Model $ownerRecord): Tab => Tab::make('Blog posts')
        ->badge($ownerRecord->posts()->count())
        ->badgeColor('info')
        ->badgeTooltip('The number of posts in this category')
        ->icon('heroicon-m-document-text'));

Окрім статичних значень, методи badgeColor() і badgeTooltip() приймають також функції для динамічного обчислення. У ці функції можна впроваджувати різні утиліти як параметри.

Відкладене завантаження бейджів на вкладках менеджерів звʼязків

Якщо getBadge() виконує дорогий запит, бейдж можна відкласти, щоб він завантажувався асинхронно після рендеру сторінки. Для цього встановіть властивість $isBadgeDeferred у true:

use Illuminate\Database\Eloquent\Model;

protected static bool $isBadgeDeferred = true;

public static function getBadge(Model $ownerRecord, string $pageClass): ?string
{
    $count = $ownerRecord->tickets()->count();

    return $count > 0 ? (string) $count : null;
}

Або перевизначте метод isBadgeDeferred(), щоб задати динамічну поведінку:

use Illuminate\Database\Eloquent\Model;

public static function isBadgeDeferred(Model $ownerRecord, string $pageClass): bool
{
    return FeatureFlag::active();
}

Якщо ви використовуєте групу звʼязків, скористайтеся fluent-методом deferBadge():

use Filament\Resources\RelationManagers\RelationGroup;

RelationGroup::make('Contacts', [
    // ...
])
    ->badge(fn (Model $ownerRecord): string => (string) $ownerRecord->contacts()->count())
    ->deferBadge();

Спільні форма й таблиця ресурсу та менеджера звʼязків

Ви можете вирішити, що форма й таблиця ресурсу мають бути ідентичними до тих, що в менеджері звʼязків, і захотіти перевикористати вже написаний код. Це просто: викличте методи form() і table() ресурсу з менеджера звʼязків:

use App\Filament\Resources\Blog\Posts\PostResource;
use Filament\Schemas\Schema;
use Filament\Tables\Table;

public function form(Schema $schema): Schema
{
    return PostResource::form($schema);
}

public function table(Table $table): Table
{
    return PostResource::table($table);
}

Приховування спільного компонента форми в менеджері звʼязків

Якщо ви ділите компонент форми між ресурсом і менеджером звʼязків, у менеджері його може знадобитися приховати. Це особливо зручно, коли треба сховати поле Select для запису-власника в менеджері звʼязків, адже Filament усе одно подбає про це за вас. Для цього скористайтеся методом hiddenOn(), передавши імʼя менеджера звʼязків:

use App\Filament\Resources\Blog\Posts\PostResource\RelationManagers\CommentsRelationManager;
use Filament\Forms\Components\Select;

Select::make('post_id')
    ->relationship('post', 'title')
    ->hiddenOn(CommentsRelationManager::class)

Приховування спільної колонки таблиці в менеджері звʼязків

Якщо ви ділите колонку таблиці між ресурсом і менеджером звʼязків, у менеджері її може знадобитися приховати. Це особливо зручно, коли треба сховати колонку для запису-власника в менеджері звʼязків, бо вона недоречна, якщо запис-власник і так виведений вище. Для цього скористайтеся методом hiddenOn(), передавши імʼя менеджера звʼязків:

use App\Filament\Resources\Blog\Posts\PostResource\RelationManagers\CommentsRelationManager;
use Filament\Tables\Columns\TextColumn;

TextColumn::make('post.title')
    ->hiddenOn(CommentsRelationManager::class)

Приховування спільного фільтра таблиці в менеджері звʼязків

Якщо ви ділите фільтр таблиці між ресурсом і менеджером звʼязків, у менеджері його може знадобитися приховати. Це особливо зручно, коли треба сховати фільтр для запису-власника в менеджері звʼязків, бо таблиця вже відфільтрована за записом-власником. Для цього скористайтеся методом hiddenOn(), передавши імʼя менеджера звʼязків:

use App\Filament\Resources\Blog\Posts\PostResource\RelationManagers\CommentsRelationManager;
use Filament\Tables\Filters\SelectFilter;

SelectFilter::make('post')
    ->relationship('post', 'title')
    ->hiddenOn(CommentsRelationManager::class)

Перевизначення спільної конфігурації в менеджері звʼязків

Будь-яку конфігурацію, зроблену всередині ресурсу, можна перевизначити в менеджері звʼязків. Наприклад, якщо ви хочете вимкнути пагінацію в успадкованій таблиці менеджера звʼязків, але не в самому ресурсі:

use App\Filament\Resources\Blog\Posts\PostResource;
use Filament\Tables\Table;

public function table(Table $table): Table
{
    return PostResource::table($table)
        ->paginated(false);
}

Додаткова конфігурація в менеджері звʼязків стане в пригоді й тоді, коли ви захочете додати дію в шапку, щоб створювати, прикріплювати або асоціювати записи в менеджері звʼязків:

use App\Filament\Resources\Blog\Posts\PostResource;
use Filament\Actions\AttachAction;
use Filament\Actions\CreateAction;
use Filament\Tables\Table;

public function table(Table $table): Table
{
    return PostResource::table($table)
        ->headerActions([
            CreateAction::make(),
            AttachAction::make(),
        ]);
}

Налаштування Eloquent-запиту менеджера звʼязків

Ви можете застосувати власні обмеження запиту або скоупи моделі, які впливають на весь менеджер звʼязків. Для цього передайте функцію в метод modifyQueryUsing() таблиці й налаштуйте запит усередині неї:

use Filament\Tables;
use Illuminate\Database\Eloquent\Builder;

public function table(Table $table): Table
{
    return $table
        ->modifyQueryUsing(fn (Builder $query) => $query->where('is_active', true))
        ->columns([
            // ...
        ]);
}

modifyQueryUsing() обмежує запит для записів, які вже належать до звʼязку: це вивід таблиці та дії, що працюють із її рядками, як-от DetachAction, DissociateAction і масові дії. Він не застосовується до записів, доступних для AttachAction чи AssociateAction, бо ті записи за визначенням перебувають поза звʼязком.

Щоб обмежити, які записи можна прикріпити чи асоціювати, звузьте варіанти методом recordSelectOptionsQuery() на дії. Filament звіряє надісланий запис із цим запитом, тож записи поза ним відхиляються, навіть якщо користувач підробить надісланий стан модального вікна:

use Filament\Actions\AttachAction;
use Illuminate\Database\Eloquent\Builder;

AttachAction::make()
    ->recordSelectOptionsQuery(fn (Builder $query) => $query->where('is_active', true))

Докладніше про обмеження варіантів для прикріплення або асоціювання.

Налаштування заголовка менеджера звʼязків

Щоб задати заголовок менеджера звʼязків, скористайтеся властивістю $title у класі менеджера:

protected static ?string $title = 'Posts';

Щоб задати заголовок динамічно, перевизначте метод getTitle() у класі менеджера звʼязків:

use Illuminate\Database\Eloquent\Model;

public static function getTitle(Model $ownerRecord, string $pageClass): string
{
    return __('relation-managers.posts.title');
}

Заголовок відобразиться в заголовку таблиці, а також на вкладці менеджера звʼязків, якщо менеджерів більше одного. Якщо ви хочете налаштувати заголовок таблиці окремо, вам усе одно доступний метод $table->heading():

use Filament\Tables;

public function table(Table $table): Table
{
    return $table
        ->heading('Posts')
        ->columns([
            // ...
        ]);
}

Налаштування заголовка запису в менеджері звʼязків

Менеджер звʼязків спирається на поняття «атрибут заголовка запису», щоб визначити, який атрибут повʼязаної моделі використовувати для її ідентифікації. Під час створення менеджера звʼязків цей атрибут передається третім аргументом команди make:filament-relation-manager:

php artisan make:filament-relation-manager CategoryResource posts title

У цьому прикладі для ідентифікації поста в менеджері звʼязків використовуватиметься атрибут title моделі Post.

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

Іноді потрібно поєднати кілька атрибутів в один заголовок. Для цього замініть конфігураційний метод recordTitleAttribute() на recordTitle(), передавши функцію, яка перетворює модель на заголовок:

use App\Models\Post;
use Filament\Tables\Table;

public function table(Table $table): Table
{
    return $table
        ->recordTitle(fn (Post $record): string => "{$record->title} ({$record->id})")
        ->columns([
            // ...
        ]);
}

Якщо ви використовуєте recordTitle() і у вас є дія асоціювання або дія прикріплення, для цих дій варто також вказати колонки для пошуку:

use Filament\Actions\AssociateAction;
use Filament\Actions\AttachAction;

AssociateAction::make()
    ->recordSelectSearchColumns(['title', 'id']);

AttachAction::make()
    ->recordSelectSearchColumns(['title', 'id'])

Сторінки звʼязків

Сторінка ManageRelatedRecords - альтернатива менеджеру звʼязків, якщо ви хочете тримати керування звʼязком окремо від редагування чи перегляду запису-власника.

Такий підхід ідеальний, коли ви використовуєте підменю ресурсу, бо тоді легко перемикатися між сторінкою View чи Edit і сторінкою звʼязку.

Щоб створити сторінку звʼязку, скористайтеся командою make:filament-page:

php artisan make:filament-page ManageCustomerAddresses --resource=CustomerResource --type=ManageRelatedRecords

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

Цю нову сторінку потрібно зареєструвати в методі getPages() вашого ресурсу:

public static function getPages(): array
{
    return [
        'index' => Pages\ListCustomers::route('/'),
        'create' => Pages\CreateCustomer::route('/create'),
        'view' => Pages\ViewCustomer::route('/{record}'),
        'edit' => Pages\EditCustomer::route('/{record}/edit'),
        'addresses' => Pages\ManageCustomerAddresses::route('/{record}/addresses'),
    ];
}

Коли ви використовуєте сторінку звʼязку, генерувати менеджер звʼязків командою make:filament-relation-manager не потрібно, як і реєструвати його в методі getRelations() ресурсу.

Тепер сторінку можна налаштувати точно так само, як менеджер звʼязків, тими самими table() і form().

Додавання сторінок звʼязків у підменю ресурсу

Якщо ви використовуєте підменю ресурсу, зареєструйте цю сторінку як звичайно в getRecordSubNavigation() ресурсу:

use App\Filament\Resources\Customers\Pages;
use Filament\Resources\Pages\Page;

public static function getRecordSubNavigation(Page $page): array
{
    return $page->generateNavigationItems([
        // ...
        Pages\ManageCustomerAddresses::class,
    ]);
}

Передавання властивостей у менеджери звʼязків

Реєструючи менеджер звʼязків у ресурсі, можна методом make() передати йому масив властивостей Livewire:

use App\Filament\Resources\Blog\Posts\PostResource\RelationManagers\CommentsRelationManager;

public static function getRelations(): array
{
    return [
        CommentsRelationManager::make([
            'status' => 'approved',
        ]),
    ];
}

Цей масив властивостей мапиться на публічні властивості Livewire у класі менеджера звʼязків:

use Filament\Resources\RelationManagers\RelationManager;

class CommentsRelationManager extends RelationManager
{
    public string $status;

    // ...
}

Тепер до status у класі менеджера звʼязків можна звертатися через $this->status.

Вимкнення лінивого завантаження

За замовчуванням менеджери звʼязків завантажуються ліниво. Це означає, що вони завантажаться лише тоді, коли стануть видимими на сторінці.

Щоб вимкнути таку поведінку, перевизначте властивість $isLazy у класі менеджера звʼязків:

protected static bool $isLazy = false;
Стан перекладу

Перекладаємо з офіційної документації, розділ за розділом, і не ховаємо недоперекладене. Помітили неточність у терміні чи реченні: напишіть, виправимо.

47%
Готовності
0
У роботі
17
Ще не перекладено
Глосарій термінів