ibrows/import-bundle
ibrows/import-bundle provides reusable import workflows for Symfony applications, including file parsing, field mapping, validation, and extensible handlers for importing data into Doctrine entities or custom services.
Framework check first — this decides everything. ibrows/import-bundle is a Symfony bundle, not a Laravel package. There is no ServiceProvider, no config/app.php registration, and the DI/Doctrine wiring will not boot inside Laravel. Before you type a single composer require, answer one question:
Install and register (Symfony path)
composer require ibrows/import-bundle
// app/AppKernel.php (Symfony 2/3)
new Ibrows\ImportBundle\IbrowsImportBundle(),
// config/bundles.php (Symfony 4+)
Ibrows\ImportBundle\IbrowsImportBundle::class => ['all' => true],
Run composer why-not ibrows/import-bundle against the target PHP/Symfony versions before committing. Do not trust a green badge on an old branch — execute the bundle's own test suite on your PHP version.
Where to look first (in this order)
DependencyInjection/Configuration.php — the full config tree. This is the only honest answer to "what is tunable vs. hardcoded."Resources/config/*.yml — service ids and constructor arguments. Fastest way to learn the intended object graph and what you will be injecting.IbrowsImportBundle.php and the Import / Model / Handler namespaces — the domain objects and the read → validate → persist flow.composer.json — PHP/Symfony/Doctrine version constraints and the license. If the license is absent, stop.First use case — get one CSV into one entity end-to-end before anything else
EntityManager.If the host app is Laravel, your "getting started" is instead: league/csv or spatie/simple-excel + a queued job + a validation ruleset + an imports audit table. Budget roughly 1–2 sprints and copy the shape from Import/Model/Handler, not the code.
Config-driven field mapping (the core value of the bundle). Declare the mapping in bundle config rather than per-importer code so non-trivial imports stay declarative:
# conceptual shape — confirm keys against DependencyInjection/Configuration.php
ibrows_import:
importers:
product_csv:
entity: AppBundle\Entity\Product
source: csv
mapping:
sku: sku
name: title
price: price
launched: launchedAt # transformed to \DateTime
The win is that onboarding a new import is a config change plus a fixture, not new parser code. Preserve this separation if you reimplement it: ImportDefinition (columns + target entity) should be data, not a subclass per file type.
Custom importer for non-CSV formats. Subclass/extend the base importer and override the read step, keeping mapping and persistence in the parent. This is the intended extension point — do not fork the parsing loop just to support XLSX or fixed-width.
Validation as a per-row hook, aggregated not thrown. Validate each row, collect errors with row numbers, and decide policy at the import level: fail-fast for back-office scheduled feeds, partial-success-with-report for anything a human will re-upload. Never let a validator throw on row 1 and abandon row 2 silently.
Doctrine persistence — chunk, flush, clear. The pattern that survives real files:
foreach ($rows as $i => $row) {
$em->persist($this->map($row));
if (($i + 1) % 100 === 0) {
$em->flush();
$em->clear(); // prevents unbounded identity-map growth
}
}
$em->flush();
Wrap each chunk (or the whole run) in an explicit transaction and store an idempotency key — the bundle does not give you either for free.
Run it from a command, schedule it, log the run record. Write a row to an imports table (filename, started_at, rows_read, rows_imported, rows_failed, status) around every run. This is the audit trail stakeholders will ask for within a month.
Laravel translation of the same pattern (the pragmatic path).
| Bundle concept | Laravel equivalent |
|---|---|
| Importer config | config/imports.php array of definitions |
| Read step | league/csv Reader / spatie/simple-excel |
| Transformer | small invokable classes or casts |
| Validation hook | Validator::make() per row, collect $errors[] |
| Persistence | chunked DB::transaction + upsert on idempotency key |
| Execution | ShouldQueue job, one per file, with tries/backoff |
| Audit | imports table + failed_import_rows table |
This gets you the bundle's architecture without the Symfony/Doctrine coupling, on maintained dependencies.
The framework mismatch is not a bug you can patch around. A Laravel integration means stripping the bundle class and DI extension, re-exposing services via a ServiceProvider, and replacing Doctrine metadata with Eloquent or laravel-doctrine/orm. That is a port, not an install — 1–2 weeks plus tests, and you own it forever.
Silent data loss is the default failure mode. Lenient CSV parsing plus unvalidated transformers drops or mangles rows without erroring. Always reconcile rows_read vs. rows_imported and surface the delta.
No transaction boundary or idempotency out of the box. Half-written imports with no rollback and no re-run safety are the most expensive import bug. Add a unique key (file hash + row number, or a natural key) and wrap in a transaction yourself.
PHP 8 will surface fatals in Symfony-era code. Expect each(), create_function, dynamic-property deprecations, and nullable-parameter warnings. Run the package's test suite on your target PHP before assuming it loads.
Doctrine version drift. DBAL 2→3 removed Statement::execute (now executeQuery/executeStatement), ORM 3 removed EntityManager::merge and renamed ClassMetadataInfo → ClassMetadata. Import code from this vintage touches all three. Use composer why-not and a smoke test.
Memory blows up on real files. Old importers load the whole file and hold one EntityManager open across thousands of entities. Add streaming reads, chunked flush, and clear() between batches — expect to have to.
Security has no upstream to patch it. Imports are a classic vector for CSV injection, path traversal, and resource exhaustion. Enforce MIME/size limits, treat every cell as hostile, and never let user-supplied filenames reach the filesystem unchecked.
Debugging the service graph. bin/console debug:container <service-id> and debug:config ibrows_import (or the bundle's config alias) are your fastest tools. Because there is no tutorial ecosystem, the source and the service YAML are the documentation.
Zero stars, zero dependents means zero external validation. No issue history, no security review, no one to ask. Pin the dependency, add it to your "vendored code we own" register with a named owner, and write characterization tests against real fixtures before refactoring anything.
Provenance. ibrows is a consultancy; a zero-traction bundle of this vintage is likely a subtree split of an internal app. Confirm the license file, the last commit date, and whether it still installs against a supported Symfony before any code enters the tree. Absent a clear license, do not vendor it.
Extension points to lean on if you do adopt it: custom importers (override read), field transformers (map/convert types), validation hooks (per-row policy), and the DI service definitions (replace a handler with your own). Those four seams are where the design is worth stealing even if you never ship the bundle.
How can I help you explore Laravel packages today?