ImportAction дає користувачу завантажити CSV, зіставити його колонки з полями моделі й імпортувати рядки у фоні. Рядки, що не пройшли валідацію, збираються в окремий CSV «невдалих рядків» для завантаження.
Підготовка:
php artisan make:queue-batches-table
php artisan make:notifications-table
php artisan vendor:publish --tag=filament-actions-migrations
php artisan migrate
php artisan make:filament-importer Product --generate
Імпорт використовує пакети джоб (job batches) і сповіщення в базі даних - без воркера черги нічого не відбудеться.
Імпортер:
use Filament\Actions\Imports\ImportColumn;
use Filament\Actions\Imports\Importer;
class ProductImporter extends Importer
{
protected static ?string $model = Product::class;
public static function getColumns(): array
{
return [
ImportColumn::make('sku')->requiredMapping()->rules(['required', 'max:32']),
ImportColumn::make('name')->requiredMapping()->rules(['required', 'max:255']),
ImportColumn::make('price')->numeric()->rules(['numeric', 'min:0']),
ImportColumn::make('category')->relationship(resolveUsing: 'slug'),
];
}
public function resolveRecord(): ?Product
{
// оновлювати наявні товари за SKU, нові - створювати
return Product::firstOrNew(['sku' => $this->data['sku']]);
}
}
ImportAction::make()
->importer(ProductImporter::class)
->chunkSize(250)
->maxRows(50_000);
CSV ділиться на частини (за замовчуванням по 100 рядків), кожна обробляється окремою джобою.
Ризики й як їх закрити:
- немає авторизації кожного запису. Імпорт не викликає політики: хто може запустити імпорт, той створить чи оновить будь-який запис, який поверне
resolveRecord(). Для недовірених користувачів перевірки треба додати в хукиbeforeCreate()/beforeUpdate()імпортера; resolveRecord()за слабким ключем (назва, email без нормалізації) - дублікати чи перезапис чужих даних;- CSV-формули. У файлі невдалих рядків значення лишаються як були. Комірка
=HYPERLINK(...)чи=cmd|..., відкрита в Excel, може виконатися як формула. Варто попереджати користувачів або очищати значення, що починаються з=,+,-,@; - файл невдалих рядків за замовчуванням може завантажити лише користувач, що запустив імпорт. Власна політика
ImportPolicyзамінює цю логіку повністю - перевірку автора треба повторити в ній; - розмір.
maxRows()і розумнийchunkSize()захищають від файлу на мільйони рядків, що «покладе» чергу; - кастинг перед валідацією - ціни з комою (
12,50) чи дати вдд.мм.рррртреба привести вcastStateUsing(), інакше всі рядки впадуть на валідації.