roundly-consulting / imports-for-laravel
Import CSV and XLSX files into Eloquent models: templates, column mapping, validated preview, duplicate handling, background batches and undo.
Package info
github.com/roundly-consulting/imports-for-laravel
pkg:composer/roundly-consulting/imports-for-laravel
Fund package maintenance!
Requires
- php: ^8.4
- ext-mbstring: *
- ext-xmlreader: *
- ext-xmlwriter: *
- ext-zip: *
- illuminate/bus: ^13.0
- illuminate/cache: ^13.0
- illuminate/console: ^13.0
- illuminate/contracts: ^13.0
- illuminate/database: ^13.0
- illuminate/events: ^13.0
- illuminate/filesystem: ^13.0
- illuminate/http: ^13.0
- illuminate/pagination: ^13.0
- illuminate/queue: ^13.0
- illuminate/routing: ^13.0
- illuminate/support: ^13.0
- illuminate/translation: ^13.0
- illuminate/validation: ^13.0
- roundly-consulting/crypto-for-laravel: ^2.1
- roundly-consulting/enums-for-laravel: ^2.0
- roundly-consulting/options-for-laravel: ^2.0
- roundly-consulting/package-toolkit-for-laravel: ^2.0
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.18
- nunomaduro/collision: ^8.5
- orchestra/testbench: ^11.0
- pestphp/pest: ^5.0
- pestphp/pest-plugin-arch: ^5.0
- pestphp/pest-plugin-laravel: ^5.0
- phpstan/extension-installer: ^1.4
- roundly-consulting/testing-for-laravel: ^2.0
Suggests
- roundly-consulting/sentinel-for-laravel: Seal imported records or audit imports from the package events (recipe in the docs).
- roundly-consulting/teams-for-laravel: Keep every import inside the current team (the TeamsOwnerScope recipe in the docs).
Provides
None
Conflicts
None
Replaces
None
README
Imports for Laravel
CSV and XLSX imports into your Eloquent models: one importer class per record type, downloadable templates, column mapping, a validated preview, duplicate handling, background batches and undo. Nothing is saved until the user commits, and invalid rows never are.
Installation
Requires PHP 8.4 (with the zip, xmlreader, xmlwriter and mbstring extensions) and Laravel 13.
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
Schedule imports:sweep (every five minutes) and imports:prune (daily) so stuck imports are released and old files deleted.
Usage
Describe one record type in an importer and list it in 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 } }
Then upload, preview, commit — and undo if needed:
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
Documentation
The full documentation — configuration, every feature and its API, and testing — lives on our website: roundly-consulting.com/open-source/docs/imports-for-laravel
Release notes are in CHANGELOG.md. To contribute, see the contributing guide.
Support our work
This package is free and open source, built and maintained by Roundly Consulting. If it saves you time, please consider supporting our open-source work — a one-time donation, a monthly pledge on Patreon or a crypto donation helps fund maintenance, new features and new packages.
License
The MIT License (MIT). See LICENSE.md.