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

Advanced Export Laravel Package

filamentphp/advanced-export

Advanced export for Filament: export table data to Excel and CSV with configurable columns, formatting options, and a simple, customizable workflow. Integrates cleanly into Filament resources so you can ship polished exports with minimal setup.

View on GitHub
Deep Wiki
Context7

Getting Started

Treat this as an unproven package (8 stars, 0 known dependents). Before writing any feature code, budget 20 minutes to confirm it even installs against your stack — that is the real first step here.

  1. Install and inspect the constraint.

    composer require anselmocossa/filamentphp-advanced-export
    

    Then open vendor/anselmocossa/filamentphp-advanced-export/composer.json and read the require block. The single most important line is the filament/filament constraint (e.g. ^3.0 vs ^4.0). If it doesn't match your Filament major version, stop — you'll be debugging framework internals rather than shipping exports.

  2. Where to look first, in order:

    • README.md — the only usage documentation you're likely to get.
    • src/ — look for a *Plugin.php, a service provider, and the Action/Export classes. Filament plugins almost always expose a make() static or a Plugin class registered in a panel provider.
    • config/ — if a config file exists, it tells you what's configurable (disk, queue, file format, chunk size) far faster than the README.
    • migrations/ — if present, the package persists export records/jobs; you'll need to publish and run them.
    • tests/ — if there are none, that's your signal to write your own smoke test early.
  3. Register it. Typical Filament shape:

    // app/Providers/Filament/AdminPanelProvider.php
    public function panel(Panel $panel): Panel
    {
        return $panel->plugin(AdvancedExportPlugin::make());
    }
    

    Confirm the actual class name from src/; don't guess.

  4. First use case — keep it deliberately boring. Attach an export action to one existing Resource table, export the filtered query to CSV, and open the file. Concretely:

    ->headerActions([
        ExportAction::make(),
    ])
    

    or a bulk action if the package only supports selected rows. Verify the exported rows match what the table shows with a filter applied. That single check catches most integration mistakes.

  5. Publish anything publishable before you customise:

    php artisan vendor:publish --provider="AnselmoCossa\FilamentphpAdvancedExport\AdvancedExportServiceProvider"
    

    (Confirm the FQCN from composer.json's extra.laravel.providers.) If a config file lands in config/, commit it — you'll be editing it.

Minimum viable decision point: if you can't get a filtered CSV out of a table within an hour, the package is not worth the integration risk for a client project. Fork it or write a 60-line StreamedResponse CSV exporter instead.

Implementation Patterns

Start from the query, not the action. The most reliable pattern with any Filament exporter is to reuse the table's own query so exports and UI never diverge:

ExportAction::make()
    ->form(fn (ExportAction $action) => [
        // whatever filter form the package exposes
    ])
    ->modifyQueryUsing(fn (Builder $query) => $query
        ->with(['customer', 'status'])   // eager-load anything the export touches
    );

If the package doesn't offer a modifyQueryUsing-style hook, subclass the action and override the query builder method you find in src/. This is the first thing to check, because "export ignores my table filters" is the number one complaint about Filament export plugins.

Column mapping is where all your time goes. Whatever the API, you'll be declaring export columns with a label and a value resolver. Keep the mapping in one array or one class so the export and the table can't drift:

protected function exportColumns(): array
{
    return [
        'id'            => 'ID',
        'customer.name' => 'Customer',
        'total'         => fn ($record) => number_format($record->total / 100, 2),
        'created_at'    => fn ($record) => $record->created_at->toDateString(),
    ];
}

Note the two formatters: money stored in cents, and dates. Raw $record->total in a spreadsheet is a recurring embarrassment — format at the export boundary, not in the DB.

Match the export to the Filament primitive the user clicked. Three distinct workflows, don't conflate them:

  • Header action → export the full filtered set. Needs chunking/queueing.
  • Bulk action → export only $records->pluck('id'). Fast, safe, no queue needed.
  • Row action → single record, usually a PDF or a one-row CSV. Rarely worth a package.

Queue anything that can exceed a few thousand rows. If the package ships an export-job class, use it rather than building your own:

ExportAction::make()->shouldQueue()   // exact method name TBD — inspect src/

Pair it with a Filament notification on completion so users aren't left guessing, and store the artifact on a disk with a signed/temporary URL. If there's no queue support in the package, that's a strong reason to reach for maatwebsite/excel's ShouldQueue export directly instead.

Wrap it in your own class. Because the package is a single-maintainer, low-traffic project, insulate yourself. Create app/Exports/CustomerExport.php that extends or composes the package class and owns your column definitions, query, and formatting. If the package is abandoned or breaks on a Filament upgrade, you swap one extends and keep every Resource untouched. This is the single highest-leverage pattern for this specific dependency.

Test the artifact, not the UI. Filament action tests are fiddly; the export is just a file. Use Livewire::test() to call the action and assert the response, or unit-test your export class directly:

$response = (new CustomerExport(Customer::query()))->export();
$this->assertStringContainsString('text/csv', $response->headers->get('Content-Type'));

Gotchas and Tips

Version drift is the primary risk. Zero dependents means nobody is filing the Filament 4 incompatibility bug for you. Pin the package with a caret constraint, lock it, and add a comment in composer.json or your upgrade notes so the next person knows why filament/filament can't be bumped freely. Check the repo's last-commit date before you commit to it — if src/ hasn't moved in a year against an evolving Filament, assume you're the maintainer now.

Memory, not time, is what breaks exports. ->get() on 200k rows will exhaust PHP before it times out. Look for chunk()/lazy()/cursor() in the package source. If it uses ->get(), and you can't inject a chunked query, you must limit the exportable set (date-range filter, cap with a warning) — or don't use it for that Resource. Watch memory_limit locally, but the failure will show up in production on the biggest tenant's dataset first.

N+1 queries will make a 5k-row export take minutes. Every relation column you resolve ($record->customer->name) is a query unless eager-loaded. Dump the query log around an export to confirm:

DB::listen(fn ($q) => logger($q->sql));

If you see the same SQL repeated per row, the eager load is missing or the package re-queries the model per record.

Excel injection is a real vulnerability, not a nitpick. Any user-controlled string beginning with =, +, -, or @ becomes a formula in the recipient's spreadsheet. If the package doesn't sanitise, prefix those cells with ' in your formatter. Do this in your own export class so it survives a package swap.

CSV encoding for non-ASCII names. Add a UTF-8 BOM or users will see mojibake for accented characters in Excel. Most packages get this wrong or make it config-only — check the generated file in a spreadsheet app, not a text editor.

Config quirks to verify early: default disk (local will fail when the queue worker runs as a different user), storage_path vs Storage::disk(), temp-file cleanup (orphaned exports accumulate silently in storage/app), and date/format defaults that may not match your locale.

Debugging checklist when an export is empty or wrong:

  1. ->dd() / ->dump() the query builder right before execution.
  2. Confirm the filter state is actually being passed to the export — Filament table filters live in the Livewire component, not the query.
  3. Check the disk, not the download, for the generated file.
  4. For queued exports, check failed_jobs — serialization errors in closures are common and silent.

Extension points worth knowing: look for modifyQueryUsing, formatter/formatUsing callbacks, and a custom writer/driver registration. If formatting is only achievable by editing vendor code, copy the class into app/Exports/ and take ownership rather than patching — composer install will overwrite vendor changes and you'll lose the fix.

Have an exit plan. The realistic fallback is maatwebsite/excel (or spatie/simple-excel for streaming) inside a Filament Action and a queued Job. It's ~100 lines and fully under your control. Keep your column definitions in your own class so that swap is a one-file change — with a package this small, that discipline is the difference between a dependency and a liability.

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.
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings