toporia/tabula
Composer 安装命令:
composer require toporia/tabula
包简介
High-performance Excel/CSV import & export for Toporia Framework - handles millions of rows
关键字:
README 文档
README
High-performance Excel/CSV import & export for Toporia Framework. Handles millions of rows with O(1) memory usage.
Features
- Streaming I/O: O(1) memory - process millions of rows without memory issues
- Chunk Processing: Configurable batch sizes for optimal performance
- Queue Support: Background processing for large files
- Validation: Built-in row validation with custom rules
- Multiple Formats: XLSX, CSV, ODS support
- Multiple Sheets: Export to multiple sheets in one file
- Progress Tracking: Monitor import/export progress
- Event System: Hook into lifecycle events
- Clean Architecture: Interface-based design, SOLID principles
Installation
composer require toporia/tabula
Quick Start
Import
use Toporia\Tabula\Tabula; use Toporia\Tabula\Imports\BaseImport; use Toporia\Tabula\Contracts\WithChunkReadingInterface; use Toporia\Tabula\Contracts\WithHeadingRowInterface; class UsersImport extends BaseImport implements WithChunkReadingInterface, WithHeadingRowInterface { public function row(array $row, int $rowNumber): void { User::create([ 'name' => $row['name'], 'email' => $row['email'], ]); } public function chunkSize(): int { return 1000; } public function headingRow(): int { return 1; } } // Run import $result = Tabula::import(new UsersImport(), '/path/to/users.xlsx'); echo "Imported: {$result->getSuccessRows()} rows"; echo "Failed: {$result->getFailedRows()} rows"; echo "Duration: {$result->getDuration()} seconds";
Export
use Toporia\Tabula\Tabula; use Toporia\Tabula\Exports\BaseExport; class UsersExport extends BaseExport { public function data(): iterable { // Use generator for large datasets foreach (User::query()->cursor() as $user) { yield [ 'name' => $user->name, 'email' => $user->email, 'created_at' => $user->created_at, ]; } } public function headers(): array { return ['Name', 'Email', 'Created At']; } } // Export to file $result = Tabula::export(new UsersExport(), '/path/to/users.xlsx'); // Or download directly Tabula::download(new UsersExport(), 'users.xlsx');
Queue Large Files
// Queue import for background processing Tabula::queueImport(UsersImport::class, '/path/to/large-file.xlsx'); // Queue export Tabula::queueExport(UsersExport::class, '/path/to/output.xlsx');
Advanced Usage
Validation
use Toporia\Tabula\Contracts\WithValidationInterface; class UsersImport extends BaseImport implements WithValidationInterface { public function row(array $row, int $rowNumber): void { User::create($row); } public function rules(): array { return [ 'email' => 'required|email', 'name' => 'required|min_length:2', ]; } public function customValidationMessages(): array { return [ 'email.required' => 'Email is required', 'email.email' => 'Invalid email format', ]; } }
Row Mapping
use Toporia\Tabula\Contracts\WithMappingInterface; class UsersImport extends BaseImport implements WithMappingInterface { public function row(array $row, int $rowNumber): void { User::create($row); } public function map(array $row): array { return [ 'name' => $row['Full Name'] ?? $row[0], 'email' => strtolower($row['Email Address'] ?? $row[1]), 'age' => (int) ($row['Age'] ?? $row[2]), ]; } }
Multiple Sheets Export
use Toporia\Tabula\Contracts\WithMultipleSheetsInterface; use Toporia\Tabula\Contracts\WithTitleInterface; class ReportExport extends BaseExport implements WithMultipleSheetsInterface { public function sheets(): array { return [ new UsersSheet(), new OrdersSheet(), new ProductsSheet(), ]; } public function data(): iterable { return []; } public function headers(): array { return []; } } class UsersSheet extends BaseExport implements WithTitleInterface { public function title(): string { return 'Users'; } public function data(): iterable { return User::all(); } public function headers(): array { return ['ID', 'Name', 'Email']; } }
Progress Tracking
use Toporia\Tabula\Contracts\WithProgressInterface; class UsersImport extends BaseImport implements WithProgressInterface { public function row(array $row, int $rowNumber): void { User::create($row); } public function onProgress(int $current, int $total, float $percentage): void { echo "Progress: {$percentage}% ({$current}/{$total})\n"; } }
Events
use Toporia\Tabula\Contracts\WithEventsInterface; class UsersImport extends BaseImport implements WithEventsInterface { public function row(array $row, int $rowNumber): void { User::create($row); } public function registerEvents(): array { return [ 'beforeImport' => fn() => Log::info('Starting import'), 'afterImport' => fn($result) => Log::info("Imported {$result->getTotalRows()} rows"), 'beforeChunk' => fn($index) => Log::info("Processing chunk {$index}"), 'afterChunk' => fn($index, $count) => Log::info("Processed {$count} rows"), 'onError' => fn($e, $row, $rowNum) => Log::error("Error on row {$rowNum}"), ]; } }
Model Traits
use Toporia\Tabula\Concerns\Importable; use Toporia\Tabula\Concerns\Exportable; class User extends Model { use Importable, Exportable; } // Import with mapping User::importFrom('/path/to/users.xlsx', function ($row) { return [ 'name' => $row['name'], 'email' => $row['email'], ]; }); // Export specific columns User::exportTo('/path/to/users.xlsx', ['id', 'name', 'email']); // Download User::downloadAs('users.xlsx', ['id', 'name', 'email']);
Quick Exports (Fluent API)
use Toporia\Tabula\Exports\FromQueryExport; use Toporia\Tabula\Exports\FromCollectionExport; // Export from query with O(1) memory $export = FromQueryExport::make(User::query()->where('active', true)) ->columns(['id', 'name', 'email', 'created_at']) ->withHeaders(['ID', 'Name', 'Email', 'Created At']) ->format('created_at', fn($v) => $v?->format('Y-m-d')); Tabula::export($export, '/path/to/users.xlsx'); // Export from collection/array $export = FromCollectionExport::make($users) ->columns(['name', 'email']) ->withHeaders(['Name', 'Email']); Tabula::export($export, '/path/to/users.xlsx');
Quick Model Imports (Fluent API)
use Toporia\Tabula\Imports\ToModelImport; // Import directly to model with upsert $import = ToModelImport::make(User::class) ->map(fn($row) => [ 'name' => $row['name'], 'email' => $row['email'], ]) ->upsertBy(['email']) // Update if email exists ->chunk(1000) ->batch(500); Tabula::import($import, '/path/to/users.xlsx');
Console Commands
# Import from command line php console tabula:import "App\Imports\UsersImport" /path/to/file.xlsx --chunk=5000 # Export from command line php console tabula:export "App\Exports\UsersExport" /path/to/output.xlsx
Performance
Tested with files containing millions of rows:
| Operation | Rows | Memory | Time |
|---|---|---|---|
| Import | 1,000,000 | ~50MB | ~120s |
| Export | 1,000,000 | ~30MB | ~90s |
| CSV Import | 1,000,000 | ~20MB | ~45s |
| CSV Export | 1,000,000 | ~15MB | ~30s |
License
MIT
统计信息
- 总下载量: 0
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 0
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2025-12-17