Repeater - список однотипних елементів з однаковим набором полів: учасники, позиції, контакти.
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
Repeater::make('members')
->schema([
TextInput::make('name')->required(),
Select::make('role')->options(['member' => 'Учасник', 'owner' => 'Власник'])->required(),
])
->columns(2)
->minItems(1)
->maxItems(10);
Builder - список різнотипних блоків у довільному порядку. Класичний приклад - вміст сторінки з блоків «заголовок», «абзац», «зображення», «цитата»:
use Filament\Forms\Components\Builder;
use Filament\Forms\Components\Builder\Block;
Builder::make('content')
->blocks([
Block::make('heading')->schema([TextInput::make('text')->required()]),
Block::make('image')->schema([FileUpload::make('url')->image()]),
]);
Два способи зберігання:
1. JSON-колонка (за замовчуванням). Увесь масив зберігається в одну колонку, модель потребує касту array. Просто, але шукати й фільтрувати по вмісту незручно.
2. Зв'язок HasMany для Repeater:
Repeater::make('items')
->relationship()
->schema([...])
->orderColumn('sort');
Кожен елемент - окремий запис у таблиці. Перетягування для зміни порядку в режимі зв'язку працює лише з orderColumn().
Корисні можливості:
distinct()на полі всередині - значення не повторюються між елементами (наприклад, «правильна відповідь» лише одна);table([...])- показати елементиRepeaterтаблицею замість карток;itemLabel()- підпис згорнутого елемента за його вмістом.
Пастка з $get(). Усередині елемента $get('field') шукає поле в цьому ж елементі. Щоб дістатися поля зовні - $get('../client_id') (на рівень вище) чи $get('../../client_id').
Коли не варто. Якщо елементів сотні або з ними працюють окремо від батька (свої статуси, пошук), краще relation manager: Repeater рендерить усі елементи в одній формі, і велика кількість робить її повільною.