avadim/fast-excel-helper
A lightweight Laravel/PHP helper for fast Excel import and export. It provides a simple API for reading, writing, and streaming spreadsheet data efficiently, reducing boilerplate for common Excel tasks.
This package is a thin convenience layer on top of rap2hpoutre/fast-excel (itself a thin layer over PhpSpreadsheet). Its entire value proposition is one-line global helpers for export/import, so the install path is short and you should read the source, not just the README — it is small enough to audit in ten minutes.
composer require avadim/fast-excel-helper
php artisan vendor:publish --tag=fast-excel-helper # if a config tag exists
The service provider is auto-discovered. Confirm what you actually got before writing code against it:
src/ — specifically the helpers file (global functions) and any Facade. That file is the source of truth for argument order and option keys. Because it is tiny, there is no hidden abstraction you will trip over later.composer.lock to see which fast-excel / phpoffice/phpspreadsheet versions were resolved. Almost every bug you hit will be a PhpSpreadsheet behaviour, not this package's.First use case: an admin "Export users" button. The idiomatic first call is a single helper that takes a collection/array plus a filename and returns a download response:
Route::get('/admin/users/export', function () {
return excel_export(User::with('team')->get()->toArray(), 'users.xlsx');
});
(Exact helper name/signature — excel_export, fastexcel_export, etc. — verify in src/; they are global functions and the naming is the thing most likely to have drifted.)
Wrap the helpers, don't sprinkle them. Because you cannot rely on this package's maintenance cadence, put one class between your app and it:
final class SpreadsheetService
{
public function export(string $filename, iterable $rows): BinaryFileResponse
{
return excel_export($rows, $filename); // single call site to swap later
}
}
When (not if) you migrate to maatwebsite/excel or raw FastExcel, you touch one file.
Export from a query, not a hydrated collection. Prefer ->cursor() or ->lazy() feeding the exporter over ->get()->toArray(), which doubles memory for large tables. If the helper only accepts arrays, chunk it and write sheets incrementally.
Import to arrays for small files, to a sheet/iterator for large ones. The common pattern is: validate the upload, hand the path to the import helper, then map rows to DTOs before touching the database — never Model::create() straight from spreadsheet rows, because header typos produce silently-null columns.
$rows = excel_import($request->file('file')->getRealPath());
$header = array_shift($rows);
$records = collect($rows)->map(fn ($r) => array_combine($header, $r));
Do the work in a job when files exceed a few thousand rows. Exports belong in a queued job that writes to a disk and notifies the user with a signed URL; imports belong in a job with a progress column. The helper is synchronous and returns a download response — that is fine for interactive use and wrong for 50k rows.
Storage::disk('local')->put("exports/{$name}.xlsx", $binary);
Validate uploads before you parse them. mimes:xlsx,xls,csv plus a size cap. A malicious or corrupt file reaches PhpSpreadsheet otherwise, and the resulting exception is not user-friendly.
Header mapping over positional access. Build an explicit ['spreadsheet label' => 'db column'] map. It absorbs reordered columns from users, which is the single most common real-world support ticket for import features.
Treat it as vendored code. 1 star, 0 dependents, and a single maintainer means: pin the exact version in composer.json (no ^), and if it is load-bearing, copy the helper file into app/Support/ and drop the dependency. The whole package is a few dozen lines around FastExcel; you are not losing much.
Dates are the classic trap. PhpSpreadsheet gives you a float serial for date cells unless the format is explicitly handled. You will see 45292 where you expected 2024-01-01. Convert with \PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject() and cast at the boundary, not in your models.
Leading zeros and long IDs. Phone numbers, postal codes, and 18-digit IDs get coerced to int/float (0123 → 123, and large ints lose precision). Read cells with an explicit cast-to-string / setReadDataOnly(false) strategy, or instruct users to format columns as Text. This bites in production and never in testing.
Formula cells return the formula, not the value. If users hand you spreadsheets with =SUM(...), you need calculated values — which means the file must have been saved by Excel after calculation, or you compute it yourself. Budget for this.
Global helper name collisions. These are namespaced global functions. If you or another package already defines excel_export, you get a fatal redeclare. Grep before installing; consider calling the Facade instead of the helper.
Config caching. If you publish a config file, remember php artisan config:cache in deploy — a stale cached config is the reason "my options are ignored" almost every time.
Testing. Don't assert on binary output. Use Storage::fake('local'), run the export, assert Storage::disk('local')->exists(...) and assertSee-style checks on parsed rows. For imports, commit small fixture files under tests/fixtures/ — generated-on-the-fly xlsx files are slow and flaky.
Extension points. The realistic extensibility is upstream: bind your own FastExcel/PhpSpreadsheet reader-writer configuration, or subclass the exporter. This package exposes almost no hooks, so plan for replacement rather than extension.
Debugging workflow. When an import misbehaves, dump the raw parsed rows before your mapping layer. Nine times out of ten the helper did exactly what it promised and the problem is a merged-cell header, an empty first row, or a trailing blank column.
Honest recommendation. If this is greenfield, reach for maatwebsite/excel (huge ecosystem, queue support, well-documented import/export lifecycle) or rap2hpoutre/fast-excel directly. Adopt fast-excel-helper when you specifically want a two-line export and are comfortable owning a pinned, small dependency yourself.
How can I help you explore Laravel packages today?