vitorccs / laravel-csv
PHP Laravel package to create CSV files in a memory-optimized way
Installs: 79 814
Dependents: 0
Suggesters: 0
Security: 0
Stars: 26
Watchers: 1
Forks: 5
Open Issues: 2
Requires
- php: >=8.0
Requires (Dev)
- ext-sqlite3: *
- laravel/legacy-factories: 1.x-dev
- orchestra/testbench: ^5.0 || ^6.0 || ^7.0 || ^8.0
- phpunit/phpunit: ^9.5
Suggests
- league/flysystem-aws-s3-v3: Required to use the Flysystem S3 driver (^1.0).
This package is not auto-updated.
Last update: 2024-11-05 18:52:01 UTC
README
PHP Laravel package to export and import CSV files in a memory-optimized way.
Description
Export CSV files from PHP arrays, Laravel Collections or Laravel Queries and choose to prompt the user to download the file, store it in a Laravel disk or create the file in background as a Laravel Job.
Import CSV files from Laravel Disks, local files, strings or resources and choose to retrieve the full content or in small chunks.
The memory usage is optimized in this project by using PHP streams, which places the content in a temporary file (rather than PHP thread memory) and reads/writes content one line at a time.
NOTE: This project was inspired on https://github.com/maatwebsite/Laravel-Excel which is a great project and can handle many formats (Excel, PDF, OpenOffice and CSV). But since it uses PhpSpreadsheet, it is not optimized for handling large CSV files (thousands of records) causing the PHP memory exhaustion.
Upgrading from v1.0 to v2.0
Version 2.0 adds the importing feature so the only required action is to change the importing namespace:
// v1.0 (old) use Vitorccs\LaravelCsv\Concerns\Exportable; use Vitorccs\LaravelCsv\Concerns\FromArray; use Vitorccs\LaravelCsv\Concerns\FromCollection; use Vitorccs\LaravelCsv\Concerns\FromQuery;
// v2.0 (new) use Vitorccs\LaravelCsv\Concerns\Exportables\Exportable; use Vitorccs\LaravelCsv\Concerns\Exportables\FromArray; use Vitorccs\LaravelCsv\Concerns\Exportables\FromCollection; use Vitorccs\LaravelCsv\Concerns\Exportables\FromQuery;
Requirements
- PHP >= 8.0
- Laravel >= 6.x
Installation
Step 1) Add composer dependency
composer require vitorccs/laravel-csv
Step 2) Publish the config file
php artisan vendor:publish --provider="Vitorccs\LaravelCsv\ServiceProviders\CsvServiceProvider" --tag=config
Step 3) Edit your local config\csv.php
file per your project preferences
How to Export
Step 1) Create an Export class file as shown below
Note: you may implement FromArray, FromCollection or FromQuery
namespace App\Exports; use App\User; use Vitorccs\LaravelCsv\Concerns\Exportables\Exportable; use Vitorccs\LaravelCsv\Concerns\Exportables\FromQuery; class UsersExport implements FromQuery { use Exportable; public function query() { return User::query() ->where('created_at', '>=', '2024-01-01 00:00:00'); } }
Step 2) The file can now be generated by using a single line:
# prompt the client browser to download the file return (new UsersExport)->download('users.csv');
In case you want the file to be stored in the disk:
# will save the file in 's3' disk return (new UsersExport)->store('users.csv', 's3');
You may also get the content as stream for better control over the output:
# will get the content in a stream (content placed in a temporary file) return (new UsersExport)->stream();
For larger files, you may want to generate the file in background as a Laravel Job
use App\Jobs\NotifyCsvCreated; # generate a {uuid-v4}.csv filename $filename = CsvHelper::filename(); # will create a job to create and store the file in disk # and afterwards notify the user (new BillsExport()) ->queue($filename, 's3') ->allOnQueue('default') ->chain([ // You must create the Laravel Job below new NotifyCsvCreated($filename) ]);
Export - Data sources
Note: Only FromQuery
can chunk results per chunk_size
parameter from config file.
Laravel Eloquent Query Builder
namespace App\Exports; use App\User; use Vitorccs\LaravelCsv\Concerns\Exportables\Exportable; use Vitorccs\LaravelCsv\Concerns\Exportables\FromQuery; class MyQueryExport implements FromQuery { use Exportable; public function query() { return User::query(); } }
Laravel Database Query Builder
namespace App\Exports; use App\User; use Illuminate\Support\Facades\DB; use Vitorccs\LaravelCsv\Concerns\Exportables\Exportable; use Vitorccs\LaravelCsv\Concerns\Exportables\FromQuery; class MyQueryExport implements FromQuery { use Exportable; public function query() { return DB::table('users'); } }
Laravel Collection
namespace App\Exports; use Vitorccs\LaravelCsv\Concerns\Exportables\Exportable; use Vitorccs\LaravelCsv\Concerns\Exportables\FromCollection; class MyCollectionExport implements FromCollection { use Exportable; public function collection() { return collect([ ['a1', 'b1', 'c1'], ['a2', 'b2', 'c2'], ['a3', 'b3', 'c3'] ]); } }
Laravel LazyCollection
namespace App\Exports; use App\User; use Vitorccs\LaravelCsv\Concerns\Exportables\Exportable; use Vitorccs\LaravelCsv\Concerns\Exportables\FromCollection; class MyQueryExport implements FromCollection { use Exportable; public function collection() { return User::cursor(); } }
PHP Arrays
namespace App\Exports; use Vitorccs\LaravelCsv\Concerns\Exportables\Exportable; use Vitorccs\LaravelCsv\Concerns\Exportables\FromArray; class MyArrayExport implements FromArray { use Exportable; public function array(): array { return [ ['a1', 'b1', 'c1'], ['a2', 'b2', 'c2'], ['a3', 'b3', 'c3'] ]; } }
How to Import
Step 1) Create an Import class file as shown below
Note: you may implement FromDisk, FromFile, FromResource or FromContents
namespace App\Exports; use Vitorccs\LaravelCsv\Concerns\Importables\Importable; use Vitorccs\LaravelCsv\Concerns\Importables\FromDisk; class UsersImport implements FromDisk { use Importable; public function disk(): ?string { return 's3'; } public function filename(): string { return 'users.csv'; } }
Step 2) The content can now be retrieved by using a single line:
# get the records in array format return (new UsersImport)->getArray();
# in case the result is too large, you may receive small chunk of results # at a time in your callback function, preventing memory exhaustion. (new UsersImport)->chunkArray(function(array $rows, int $index) { // do something with the rows echo "Chunk $index has the following records:"; print_r($rows); });
Import - Data sources
From string
namespace App\Imports; use Vitorccs\LaravelCsv\Concerns\Importables\Importable; use Vitorccs\LaravelCsv\Concerns\Importables\FromContents; class MyContents implements FromContents { use Importable; public function contents(): string { return "A1,B1,C1\nA2,B2,C2\n,A3,B3,C3"; } }
From local File
namespace App\Imports; use Vitorccs\LaravelCsv\Concerns\Importables\Importable; use Vitorccs\LaravelCsv\Concerns\Importables\FromFile; class MyFileImport implements FromFile { use Importable; public function filename(): string; { return storage_path() . '/users.csv'; } }
From resource
namespace App\Imports; use Vitorccs\LaravelCsv\Concerns\Importables\Importable; use Vitorccs\LaravelCsv\Concerns\Importables\FromResource; class MyResourceImport implements FromResource { use Importable; public function resource() { $contents = "A1,B1,C1\nA2,B2,C2\n,A3,B3,C3"; $resource = fopen('php://memory', 'w+'); fputs($resource, $contents); return $resource; } }
From Laravel Disk
namespace App\Exports; use Vitorccs\LaravelCsv\Concerns\Importables\Importable; use Vitorccs\LaravelCsv\Concerns\Importables\FromDisk; class UsersImport implements FromDisk { use Importable; public function disk(): ?string { return 'local'; } public function filename(): string { return 'my_imports/users.csv'; } }
Implementations
The implementations below work with both Export and Import mode.
Headings
Implement WithHeadings
for setting a heading to the CSV file.
use Vitorccs\LaravelCsv\Concerns\Exportables\Exportable; use Vitorccs\LaravelCsv\Concerns\Exportables\FromArray; use Vitorccs\LaravelCsv\Concerns\WithHeadings; class UsersExport implements FromArray, WithHeadings { use Exportable; public function headings(): array { return ['ID', 'Name', 'Email']; } }
Mapping rows
Implement WithMapping
if you either need to set the value of each column or apply some custom formatting.
use Vitorccs\LaravelCsv\Concerns\Exportables\Exportable; use Vitorccs\LaravelCsv\Concerns\Exportables\FromArray; use Vitorccs\LaravelCsv\Concerns\WithMapping; class UsersExport implements FromArray, WithMapping { use Exportable; public function map($user): array { return [ $user->id, $user->name, $user->email ?: 'N/A' ]; } }
Formatting columns
Implement WithColumnFormatting
to format date and numeric fields.
In export mode, the Date must be either a Carbon or a Datetime object, and the number must be any kind of numeric data (numeric string, integer or float).
In import mode, the string content must match with the formatting set (e.g: yyyy-mm-dd for dates).
The formatting preferences are set in the config file csv.php
.
use Carbon\Carbon; use Vitorccs\LaravelCsv\Concerns\Exportables\Exportable; use Vitorccs\LaravelCsv\Concerns\Exportables\FromArray; use Vitorccs\LaravelCsv\Concerns\WithColumnFormatting; use Vitorccs\LaravelCsv\Enum\CellFormat; class UsersExport implements FromArray, WithColumnFormatting { use Exportable; public function array(): array { return [ [ Carbon::now(), Carbon::now(), 2.50, 1.00 ], [ new DateTime(), new DateTime(), 3, 2.00 ] ]; } public function columnFormats(): array { return [ 'A' => CellFormat::DATE, 'B' => CellFormat::DATETIME, 'C' => CellFormat::DECIMAL, 'D' => CellFormat::INTEGER, ]; } }
Limiting the results
Implement the method below if you need to limit the quantity of results to be exported/imported.
use Vitorccs\LaravelCsv\Concerns\Exportables\Exportable; use Vitorccs\LaravelCsv\Concerns\Exportables\FromQuery; class UsersExport implements FromQuery { use Exportable; public function limit(): ?int { return 5000; } }
License
Released under the MIT License.