NovinkaZverejnili sme 50+ Laravel balíkov ako open source
Custom AI apps, agents and automation — Roundly ConsultingRoundly
Všetky balíky

Pridajte balík, publikujte jeho migrácie aj migrácie options-for-laravel (ukladajú sa v nich mapovania stĺpcov), ak ju ešte nemáte, pridajte tabuľku job_batches z Laravelu a spustite migráciu. Service provider aj alias fasády Imports sa načítajú automaticky spolu s providermi balíkov Roundly, na ktorých stojí — crypto, enums, options a package-toolkit:

composer require roundly-consulting/imports-for-laravel
php artisan vendor:publish --tag="options-migrations"   # saved column mappings live in options-for-laravel
php artisan vendor:publish --tag="imports-migrations"
php artisan make:queue-batches-table   # Laravel's job_batches table, if you do not have it yet
php artisan migrate

Migrácie sa len publikujú a idú len dopredu. Vzniknú štyri tabuľky: import_sessions, import_batches, import_row_results a imported_records. Každé nahratie číta uložené mapovania vlastníka, preto je tabuľka options povinná, kým je zapnuté imports.mappings.enabled (predvolene áno) — bez nej nahratie zlyhá s InvalidImportsConfigurationException, ktorá uvedie riešenie, nikdy nie so surovou chybou SQL.

Publikovanie môže urobiť aj inštalačný príkaz:

# Publishes the config, the imports migrations and options-for-laravel's migration
# (skipped when the options table exists), then prints the remaining steps.
# Refuses (exit 1) when an imports table already exists.
php artisan imports:install

1. Naplánujte sweep a prune

Balík sám nič neplánuje. imports:sweep expiruje zabudnuté relácie a uvoľní zaseknuté náhľady, importy a vrátenia; imports:prune zmaže súbory a výsledky riadkov po uplynutí doby uchovávania:

// routes/console.php
use Illuminate\Support\Facades\Schedule;

Schedule::command('imports:sweep')->everyFiveMinutes()->withoutOverlapping(10)->onOneServer();
Schedule::command('imports:prune')->daily()->onOneServer();

Spustite aj queue worker: náhľady nad imports.preview.sync_threshold (500 riadkov) a každý import bežia vo fronte, ak nie je vypnuté imports.queue.enabled. retry_after spojenia frontu držte nad imports.commit.timeout (600 sekúnd).

2. Typy kľúčov nastavte pred migráciou

Ak všade používate bigint id, predvolené hodnoty vyhovujú. Pri UUID alebo ULID kľúčoch ich nastavte pred php artisan migrate:

# Before php artisan migrate — bigint, uuid or ulid
IMPORTS_KEY_TYPE=uuid            # owner + actor morphs — must equal options.key_type
IMPORTS_RECORD_KEY_TYPE=         # the imported records' key type; blank = IMPORTS_KEY_TYPE
IMPORTS_PRIMARY_KEY_TYPE=bigint  # the package tables' own ids

Model, ktorého kľúč nesedí, sa odmietne ešte pred zápisom výnimkou InvalidImportsConfigurationException s kľúčom konfigurácie a názvom modelu.

3. Zvoľte súkromný disk

Nahraté súbory sa ukladajú na imports.storage.disk (predvolene local) do imports/<owner digest>/<session id>/. Funguje akýkoľvek disk Laravelu — nelokálny sa skopíruje do lokálneho dočasného súboru, keď je potrebný náhodný prístup — nikdy však nie verejný: nahraté súbory obsahujú osobné údaje a imports:doctor verejný disk nahlási ako chybu.

4. Napíšte importér a importujte súbor

Opíšte jeden typ záznamu a uveďte ho v config('imports.importers'):

use App\Models\Asset;
use App\Models\Vendor;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use RoundlyConsulting\Imports\Definition\{Field, NaturalKey, Ownership};
use RoundlyConsulting\Imports\Enums\ImportOperation;
use RoundlyConsulting\Imports\Importer;
use RoundlyConsulting\Imports\Rows\{ImportContext, ImportRow};

final class AssetsImporter extends Importer   // key `assets`, label `Assets`
{
    public function model(): string { return Asset::class; }
    public function ownership(): Ownership { return Ownership::column('team_id'); }
    public function naturalKey(): NaturalKey { return NaturalKey::by('asset_tag')->then('serial_number'); }

    public function fields(): array
    {
        return [
            Field::text('asset_tag')->aliases('tag', 'inventory no'),
            Field::text('serial_number'),
            Field::text('name')->required()->max(120),
            Field::date('purchased_on'),
            Field::reference('vendor')->to(Vendor::class)->by('vat_id', 'name')->storeAs('vendor_id'),
        ];
    }

    public function authorize(?Authenticatable $user, Model $owner, ImportOperation $operation): bool
    {
        return $user?->can('manage-assets', $owner) ?? false;
    }

    public function create(ImportRow $row, ImportContext $context): Model
    {
        return Asset::create([...$row->attributes(), ...$context->ownerAttributes()]);
    }

    public function update(Model $asset, ImportRow $row, ImportContext $context): Model
    {
        return tap($asset)->update($row->changes());   // blank cells keep the stored value
    }
}

Potom nahrajte súbor, pozrite si náhľad, potvrďte import — a v prípade potreby ho vráťte:

use RoundlyConsulting\Imports\Enums\DuplicateMode;
use RoundlyConsulting\Imports\Facades\Imports;

$import = Imports::for($team)->by($user)
    ->upload('assets', $request->file('file'))   // CSV or XLSX; columns map from the headers
    ->mode(DuplicateMode::Update)
    ->preview();   // ≤ 500 rows: checked now; larger files validate on the queue — poll isPreviewed()

$import->counts();                               // valid 47 · invalid 2 · duplicates 1
$batch = $import->commit();                      // a background job batch
$batch->rollback();                              // later: removes the rows it created, unless edited since

Tagy na publikovanie

TagPublikuje
imports-migrationsŠtyri migrácie s časovou pečiatkou z publikovania. Povinné: len sa publikujú a idú len dopredu.
options-migrationsTabuľka options-for-laravel — ukladajú sa v nej mapovania stĺpcov. Povinné, kým je zapnuté imports.mappings.enabled.
imports-configconfig/imports.php
imports-translationslang/vendor/imports/{en,sk}/ — booleans, enums, exceptions, preview, rejections, templates, validation
imports-routesroutes/imports.php — po publikovaní sa načíta namiesto súboru balíka, stále len pri zapnutom imports.routes.enabled.
php artisan vendor:publish --tag="imports-config"         # config/imports.php
php artisan vendor:publish --tag="imports-translations"   # lang/vendor/imports/{en,sk}/
php artisan vendor:publish --tag="imports-routes"         # routes/imports.php — loaded instead of the package's

Tabuľky

TabuľkaObsahuje
import_sessionsJeden riadok na nahratie (soft delete): importér, druh, morph vlastníka a aktéra, stav, zdroj (disk, cesta, názov, veľkosť, SHA-256, formát, kódovanie, oddeľovač, hárok, riadok hlavičky, hlavičky), mapovanie, režim, jazyk, časové pásmo, počty, priebeh, preview_version, posuny častí, pracovná kópia XLSX a unikátny lock_key — nikdy hodnoty riadkov.
import_batchesJedna na potvrdenú reláciu: morph toho, kto import spustil a kto ho vrátil, id z Laravel job_batches, stav, počítadlá častí, súhrn, stav a počty vrátenia, chyba, started_at, finished_at, undo_until.
import_row_resultsLen výnimky — neplatné, duplicitné, spárované a zlyhané riadky (a každá položka dávky súborov): stav, výsledok, chyby buniek, zhoda prirodzeného kľúča. Nikdy hodnoty riadkov.
imported_recordsEvidencia: jeden riadok na záznam, ktorý import vytvoril, prepojil alebo aktualizoval — polymorfný pivot „importované z“, s kontrolným súčtom pre vrátenie, digestom vlastníka a pri súboroch hashom obsahu. Unikátne (batch_id, row_number).

Názvy tabuliek sa dajú nastaviť (imports.tables.*). Každý dátum s časom sa ukladá ako reťazec v UTC a načíta sa ako CarbonImmutable v UTC. Uložené mapovania v týchto tabuľkách nie sú: sú v tabuľke options z options-for-laravel, jeden riadok na vlastníka.

Preklady

Všetko, čo balík hovorí používateľovi — odmietnutia, validačné správy, nápovedy v šablónach, popisy enumov, výnimky — je v angličtine aj slovenčine (imports::…). Ďalší jazyk pridáte publikovaním prekladov a skopírovaním priečinka.

Kontrola nastavenia

php artisan imports:doctor
php artisan about --only=imports

Doctor vypíše jedno zistenie na kontrolu (pozrite Príkazy Artisan) a pri akejkoľvek chybe skončí nenulovým kódom. Sekcia about ukáže počet importérov, front (spojenie a front len ako SET alebo DEFAULT), disk, limity, cesty, tri typy kľúčov a scope vlastníka.

Prechod z verzie 1.0.0

Bez migrácie a bez zmeny konfigurácie. Pozornosť si môžu vyžadovať tri veci:

  • Nekompatibilná zmena: metóda na čítanie uloženého počtu na modeloch ImportSession a ImportBatch sa premenovala z count(string $key) na countOf(string $key). Statické ImportSession::count() a ImportBatch::count() sú opäť počtom riadkov z Eloquentu.
  • Hodnoty polí DateTime teraz prichádzajú do importéra prevedené do app.timezone; predtým to bol miestny čas v imports.values.timezone. Pri prázdnom values.timezone (predvolené) sa nič nemení a polia Date sa nemenia nikdy.
  • options() s číselnými kľúčmi si ich ponechá ako uložené hodnoty: [1 => 'Male', 2 => 'Female'] teraz uloží 1 a 2. Len skutočný zoznam (kľúče 0, 1, 2, …) sa číta ako hodnoty bez popisov.
use RoundlyConsulting\Imports\Models\ImportSession;

// Before: a stored count on an ImportSession or ImportBatch model
$model->count('valid');

// Now
$model->countOf('valid');          // one stored count, 0 when absent
ImportSession::count();            // Eloquent's row count again (the same on ImportBatch)
// config/app.php: 'timezone' => 'UTC' · config/imports.php: 'values' => ['timezone' => 'Europe/Bratislava']
// A DateTime cell 2026-01-15 09:30

$row->get('accepted_at');
// before: 2026-01-15 09:30 in Europe/Bratislava (the wall clock)
// now:    2026-01-15 08:30 UTC — the same instant, in app.timezone, which is what Eloquent stores

Prejavte lásku k open source

Tento balík je zadarmo pod licenciou MIT. Ak vám šetrí čas, jednorazový príspevok alebo členstvo na Patreone nám pomôže ho ďalej udržiavať, testovať a dokumentovať.

Ďalšie spôsoby podpory vrátane kryptomien

Odoslaním daru súhlasíte s našimi podmienkami prijímania darov.

Chcete to zabudovať do svojho produktu?

Naše balíky integrujeme do zákazkových Laravel a AI riešení. Napíšte nám, na čom pracujete, a ozveme sa do 48 hodín.