Installation:
composer require egyg33k/csv-bundle
Ensure mbstring PHP extension is enabled (required for CSV handling).
First Use Case:
$reader = $this->get('egyg33k.csv.reader');
$csv = $reader::createFromPath('path/to/file.csv');
$firstRow = $csv->fetchOne(); // Returns first row as associative array
$writer = $this->get('egyg33k.csv.writer');
$csv = $writer::createFromFileObject(new \SplTempFileObject());
$csv->insertOne(['header1', 'header2']);
$csv->insertOne(['data1', 'data2']);
$csv->output('output.csv');
Key Files:
app/config/config.yml for bundle configuration (if any).Streaming Large Files:
Use fetchAssoc() or fetchBreakOnMissing() to process rows iteratively without loading the entire file into memory.
$csv = $reader::createFromPath('large_file.csv');
foreach ($csv as $row) {
// Process row-by-row
}
Dynamic CSV Generation:
Combine with Symfony’s Response for downloadable CSVs:
$response = new Response();
$response->headers->set('Content-Type', 'text/csv');
$response->headers->set('Content-Disposition', 'attachment; filename="export.csv"');
$writer = $this->get('egyg33k.csv.writer');
$csv = $writer::createFromFileObject($response->getBody());
$csv->insertOne(['headers']);
$csv->insertAll($data);
Validation & Transformation:
Use League CSV’s CsvReader/CsvWriter methods (e.g., setHeaderOffset(), setDelimiter()) via the bundle’s services:
$csv = $reader::createFromPath('file.csv', 'r');
$csv->setHeaderOffset(0); // Treat first row as headers
$records = $csv->getRecords();
Dependency Injection: Inject services directly into controllers/services:
use EGYG33K\CsvBundle\Services\CsvReader;
use EGYG33K\CsvBundle\Services\CsvWriter;
public function __construct(
private CsvReader $reader,
private CsvWriter $writer
) {}
Batch Processing:
Pair with Symfony’s EventDispatcher to trigger events per row/record:
$csv = $reader::createFromPath('data.csv');
$csv->on('parse', function ($record) {
$this->eventDispatcher->dispatch(new CsvRowEvent($record));
});
Memory Leaks:
Avoid loading entire CSVs into arrays (e.g., getRecords()). Use iterators (foreach) for large files.
// ❌ Bad (loads all rows)
$allRows = $csv->getRecords();
// ✅ Good (streaming)
foreach ($csv as $row) { ... }
Encoding Issues:
Ensure mbstring.func_overload is disabled in php.ini to avoid encoding conflicts. Use UTF-8 explicitly:
$csv = $reader::createFromPath('file.csv', 'r', ';', '"', '\\', 'utf-8');
Service Container Quirks:
The bundle registers services as egyg33k.csv.reader/writer, but not as league.csv.reader. Always use the bundle’s service IDs.
File Permissions:
Temporary files (e.g., SplTempFileObject) may fail if sys_temp_dir is misconfigured. Fall back to tmpfile():
$tempFile = tmpfile();
$csv = $writer::createFromFileObject($tempFile);
Deprecated Methods:
The bundle wraps League CSV v3.0 (released 2016). Some methods (e.g., insertAll()) may behave differently than newer versions. Check League’s migration guide.
Validate CSV Structure:
Use getHeader() and validate() to debug malformed files:
$csv = $reader::createFromPath('file.csv');
if (!$csv->validate()) {
throw new \RuntimeException('Invalid CSV: ' . $csv->getError());
}
Log Errors: Wrap CSV operations in try-catch blocks:
try {
$csv = $reader::createFromPath('file.csv');
} catch (\League\Csv\Exception\CsvException $e) {
$this->logger->error('CSV Error', ['error' => $e->getMessage()]);
}
Extension Points:
EGYG33K\CsvBundle\Services\AbstractCsvService to add logic (e.g., auto-formatting).league.csv.parse events for row-level hooks.config.yml keys. All settings are passed via method calls (e.g., setDelimiter()).services.yaml:
services:
EGYG33K\CsvBundle\Services\CsvReader: '@egyg33k.csv.reader'
EGYG33K\CsvBundle\Services\CsvWriter: '@egyg33k.csv.writer'
How can I help you explore Laravel packages today?