Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Exporter Bundle Laravel Package

idci/exporter-bundle

IDCI Exporter Bundle offers a flexible Symfony-based framework for exporting data into multiple formats using configurable exporters, profiles, and writers, with support for custom export logic and easy integration into Symfony applications.

View on GitHub
Deep Wiki
Context7

Getting Started

Treat this as a read-only reference implementation, not a dependency. There is no composer require idci/exporter-bundle path into a Laravel app: the bundle's constraints target Symfony 2.x, which cannot co-resolve with Laravel 9+ (which pulls symfony/* ^6/^7 transitively). Attempting it produces an unresolvable dependency graph, not a working install.

Minimal steps for a Laravel dev:

  1. Clone the repo into a scratch directory (git clone https://github.com/IDCI-Consulting/ExporterBundle) — do not add it to composer.json.
  2. Read these files, in this order, and take notes:
    • DependencyInjection/Configuration.php — the authoritative config schema for idci_exporter (the README lags the code).
    • Resources/config/services.yml — service ids and tag names; this is how the bundle wires exporters into a registry.
    • Manager/ExporterManager.php — the public entry point; note the exact export(...) signature.
    • Exporter/ and Format/ — the built-in CSV/JSON/XML/XLS writers and how each is parameterized.
  3. Translate what you find into Laravel idioms: a ExportManager bound in a service provider, a tagged exporters registry keyed by format string, and a ExportService domain class with no framework imports.

Where it maps in Laravel: the bundle's Manager → tagged exporters → writers chain is exactly analogous to Laravel's driver-based managers (Manager::driver()->export() mirrors Cache::store()->put() / Filesystem::disk()->put()). That is the design worth borrowing.

First use case: a CSV download of an admin report. In Laravel, that's a one-class build:

// app/Services/Export/ExportManager.php
class ExportManager {
    public function driver(string $format): ExporterContract {
        return app(config("exports.drivers.$format"));
    }
}

…with csv bound to CsvExporter using league/csv's Writer and a LazyCollection/generator row source. You will be productive in an afternoon; the bundle's contribution is telling you what the abstraction should look like, not code you can run.

Implementation Patterns

Registry-by-tag (the pattern worth extracting). The bundle tags each exporter service and resolves them by name. The Laravel equivalent is a container tag + a manager:

// AppServiceProvider::register()
$this->app->tag([CsvExporter::class, XlsxExporter::class], 'exporters');
// Manager resolves via tag, keyed by a static ->format() string
foreach ($this->app->tagged('exporters') as $exporter) {
    $this->exporters[$exporter->format()] = $exporter;
}

Contract-first. The bundle's value is isolating format-specific logic behind a ExporterInterface. Keep that boundary razor-thin:

interface Exporter {
    public function format(): string; // 'csv', 'xlsx'
    /** @param iterable<array<string,mixed>> $rows */
    public function write(iterable $rows, string $path): void;
}

Streaming, not materialization. This is the single most important porting decision. The Symfony2-era writers (PHPExcel) build full in-memory object graphs; a 50k-row XLSX export can consume gigabytes. In Laravel:

  • Read rows with DB::table(...)->lazyById(1000) or cursor() — never ->get().
  • Write CSV with league/csv or openspout's streaming writer directly to a StreamedResponse.
  • For downloads, response()->streamDownload(fn () => $export->write($rows, 'php://output'), 'report.csv').

Queued exports for anything non-trivial. The original bundle assumes a synchronous HTTP request context (it returns an HttpFoundation response at the boundary). Don't inherit that assumption. Model exports as a job:

// ExportReportJob::handle()
$path = "exports/{$this->reportId}.xlsx";
$this->export->write($rows, Storage::path($path));
// broadcast/log the completion, email a signed temporary URL

Config-driven definitions. The bundle's "configurable export definitions" (YAML per entity) map cleanly to config/exports.php:

return [
    'drivers' => ['csv' => CsvExporter::class, 'xlsx' => XlsxExporter::class],
    'definitions' => [
        'orders' => ['columns' => [...], 'query' => fn () => Order::query()],
    ],
];

Preserve the extraction test harness. Whatever CSV fixture you build in the spike, keep it. Assert byte-level output against a known-good golden file — this is what lets you later swap the writer implementation without regression.

Gotchas and Tips

The composer wall is hard, not soft. symfony/symfony ~2.x will not resolve alongside Laravel's symfony/* ^6/^7 transitives. Don't attempt --ignore-platform-reqs or composer require --with-all-dependencies workarounds — you'll enter dependency hell and end up with a partially installed bundle that fails at runtime, not install time.

PHPExcel is the likely writer backend, and it's archived. If the Format/ directory imports PHPExcel, treat any code path that touches it as unusable. openspout is the streaming successor you actually want.

Configuration.php is the source of truth. The README is stale. When reading the bundle, cross-check every config key against the NodeBuilder tree — the docs will show keys that no longer exist and miss keys that do.

Character encoding on CSV. Older writers omit a UTF-8 BOM; Excel then mangles non-ASCII. In Laravel, prefix "\xEF\xBB\xBF" for Excel-targeted CSVs. Also check the bundle's Format/Csv for a hardcoded charset — the Symfony2 era defaulted to ISO-8859-1 in some paths.

Silent truncation is the worst failure mode. If you inherit any writer-like code, explicitly test the boundary: what happens at row 10,000, 50,000, 1,000,000? Verify the row count matches the source. A "successful" download missing rows is a support nightmare.

Memory and max_execution_time blow-ups. The bundle provides no guardrails against either — no chunking, no progress state, no resume. Your Laravel implementation must: cap rows per export, run via queue, and log completion with row counts.

Temp file accumulation. The Symfony-era pattern writes to sys_get_temp_dir() and returns a BinaryFileResponse. Under concurrency, orphaned temp files accumulate. Use Storage::disk('local') with a try/finally unlink in Laravel, or a Storage::put with a signed URL delivery — no temp files at all.

HttpFoundation at the boundary. If you fork the bundle, note that every StreamedResponse/BinaryFileResponse return is dead weight in Laravel — replace with response()->streamDownload(). Grep for Symfony\\Component\\HttpFoundation per file as your first-pass audit metric for what survives extraction.

Extension point worth keeping. The bundle's tagged-collector approach is the only piece with real design value: it lets you register a new format (say, JSON Lines or Parquet) without touching existing code. Reproduce it with app->tag(), and keep the format() key stable so configs don't silently break.

No tests means no contract. With zero dependents and no test suite in the repo, there's no external signal that any behavior is correct. The fixture-based golden tests you write during extraction are your contract — invest the extra half-day.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource