K

Tabulka

Importy tabulky

CSV načtené zpět do modelu: hlavičky namapované, buňky přetypované a zvalidované po sloupcích a chyby posbírané místo fatálních.

Na této stránce

Wire Table umí importovat řádky z nahraného CSV souboru do modelu tabulky — zrcadlo Exportů. Sloupce mapují hlavičky souboru na atributy modelu, každá buňka se přetypuje a zvaliduje podle svého sloupce a selhání validace po řádcích se sbírají místo přerušení běhu.

Deklarace importéru

Připojte ImportAction s konfigurací TableImport do hlavičkových akcí tabulky:

use NyonCode\WireTable\Import\ImportAction;
use NyonCode\WireTable\Import\ImportColumn;
use NyonCode\WireTable\Import\TableImport;
 
public function table(Table $table): Table
{
return $table
->model(Contact::class)
->columns([...])
->headerActions([
ImportAction::makeImport()
->importConfig(
TableImport::make()
->model(Contact::class)
->columns([
ImportColumn::make('name')
->requiredMapping()
->rules(['required']),
ImportColumn::make('email')
->rules(['nullable', 'email'])
->guess(['e-mail', 'mail']),
ImportColumn::make('age')
->castStateUsing(fn ($value) => (int) $value),
])
),
]);
}

Spuštění importu

Hostitelský seam je WithTable::importTable(string $filePath): ImportResult. Aplikace k němu zapojí UI nahrání souboru — typicky Livewire upload, jehož reálná cesta dočasného souboru se předá dovnitř:

use Livewire\WithFileUploads;
 
class Contacts extends Component
{
use WithTable;
use WithFileUploads;
 
public $importFile = null;
 
public function runImport(): void
{
$this->validate(['importFile' => 'required|file|mimes:csv,txt']);
 
$result = $this->importTable($this->importFile->getRealPath());
 
// např. notifikace: "{$result->getImported()} imported, {$result->getFailedCount()} skipped"
}
}

importTable() vyresolvuje konfiguraci ImportAction z hlavičkových akcí tabulky (zrcadlí exportTable()) a invaliduje cachované záznamy, takže další render ukáže nové řádky.

Mapování hlaviček

Sloupec se spáruje s hlavičkou souboru podle svého popisku, názvu atributu nebo libovolného aliasu z guess() — case-insensitive a otrimované. Mapování se vyresolvuje jednou z řádku hlaviček.

  • requiredMapping() označí hlavičku, kterou soubor musí obsahovat; chybějící vyhodí RuntimeException před zpracováním jakéhokoli řádku.
  • Nenamapované volitelné sloupce se pro každý řádek jednoduše přeskočí.

Validace po řádcích

rules() validují každou namapovanou buňku. Selhávající řádek se přeskočí a zaznamená — běh pokračuje:

$result = $this->importTable($path);
 
$result->getImported(); // uložené řádky
$result->getFailedCount(); // řádky přeskočené validací
$result->hasFailures();
$result->getFailures(); // [['row' => 3, 'errors' => ['The Email field must be…']], …]

Aktualizovat nebo vytvořit

Párovat existující záznamy místo vždy vytvářet:

TableImport::make()
->model(Contact::class)
->columns([...])
->updateExisting(['email']) // updateOrCreate klíčované emailem

Každý atribut updateExisting() musí být krmen namapovaným sloupcem souboru — nenamapovaný párovací atribut nechá celý běh selhat předem (jinak by prázdná množina párovacích klíčů tiše přepsala nesouvisející záznamy).

Vlastní perzistence

Převezměte perzistenci úplně pomocí createUsing() (model() není potřeba):

TableImport::make()
->columns([...])
->createUsing(function (array $data) {
Contact::firstOrNew(['email' => $data['email']])->fill($data)->save();
})

Volby CSV

TableImport::make()
->delimiter(';')
->enclosure('"')

Importér zvládá UTF-8 BOM, prázdné řádky a řádky s méně/více buňkami, než má hlavička (chybějící buňky se stanou prázdnými řetězci, přebytečné se zahodí). CSV je jediný podporovaný formát (jako importér ve Filamentu).

Metody

Metoda Na Popis
model(string) TableImport Cílový Eloquent model
columns(array) TableImport Seznam ImportColumn
delimiter(string) / enclosure(string) TableImport Volby parsování CSV
updateExisting(array) TableImport Párovací atributy updateOrCreate
createUsing(Closure) TableImport Vlastní handler perzistence po řádcích
label(string|Closure) ImportColumn Popisek hlavičky (výchozí je headline z názvu)
requiredMapping() ImportColumn Soubor musí obsahovat tento sloupec
rules(array) ImportColumn Validační pravidla pro buňku
castStateUsing(Closure) ImportColumn Transformovat surovou hodnotu buňky
guess(array) ImportColumn Alternativní názvy hlaviček
importTable(string) hostitel Spustí import hned, z reálné cesty
queueTableImport(string, ?string) hostitel Spustí ho na workeru, z cesty na disku

Import na frontě

Import byl už předtím cesta dovnitř, výsledek ven — přesun na frontu proto v jeho pipeline nemění nic. Job přidává ty tři věci, které si od requestu vypůjčit nemůže: soubor, který ho přežije, výsledek, který má kam jít, a selhání, které je vidět.

public function importInBackground(): void
{
$path = $this->file->store('imports', 's3');
 
$this->queueTableImport($path, 's3');
}

Nahraný soubor nejdřív uložte a předejte to, co uložení vrátí. queueTableImport() bere cestu na disku, ne reálnou cestu dočasného uploadu: worker může být klidně jiný stroj a dočasný soubor Livewire tam v tu chvíli nebude.

Výsledek přijde jako notifikace — počet naimportovaných a odmítnutých řádků — protože import na frontě nemá návratovou hodnotu. Běh, který nějaké řádky odmítl, hlásí varování, ne úspěch: import, který potichu zahodil řádek, je přesně ten druh úspěchu, o kterém je lepší vědět.

Chybějící soubor job položí. Čtečka CSV bere nečitelnou cestu jako „žádné řádky“, což je správně, když se uživatel dívá, a lež, když běží fronta: „naimportováno 0 řádků, 0 chyb“ se nedá odlišit od prázdného souboru. Worker, který upload nenajde, vyhodí ImportException a zkusí to znovu.

Úprava importu, který nevlastníte

Tabulka z nainstalovaného modulu deklaruje svoje vlastní mapování a aplikace do něj přidá přes hook import.configuring, místo aby tu třídu nahradila:

$manager->hook(Hook::ImportConfiguring, function (ImportConfiguringPayload $payload) {
$payload->columns = [...$payload->columns, ImportColumn::make('imported_by')];
$payload->import->updateExisting(['email']);
 
return $payload;
}, for: 'users');

Běží jednou na import, ať se doručí jakkoli — zařazený import se vrací do stejného importTable() — a až po autorizační kontrole ImportAction, takže $payload->path je soubor, který akce už otevřít povolila. Proto je jen ke čtení.

Související dokumentace