Installation
composer require darkilliant/import
Ensure your project uses Symfony 3.4.x (not Laravel, but Symfony-based) and PHP 7.0+.
Enable the Bundle
Add to app/AppKernel.php (Symfony) or config/bundles.php (Symfony Flex):
new Darkilliant\ImportBundle\DarkilliantImportBundle(),
First Use Case
Define a CSV import route in routing.yml:
darkilliant_import:
resource: "@DarkilliantImportBundle/Resources/config/routing.yml"
prefix: /import
Test with a sample CSV file (e.g., users.csv) and a form type to map fields.
src/Darkilliant/ImportBundle/Resources/config/routing.yml: Default routes.src/Darkilliant/ImportBundle/Import/ImportInterface.php: Core import logic contract.src/Darkilliant/ImportBundle/Import/Import.php: Base import class (extend this).src/Darkilliant/ImportBundle/Form/Type/ImportType.php: Form type for file uploads.Extend Darkilliant\ImportBundle\Import\Import to handle your data model:
// src/AppBundle/Import/UserImporter.php
namespace AppBundle\Import;
use Darkilliant\ImportBundle\Import\Import;
use AppBundle\Entity\User;
class UserImporter extends Import
{
protected function transformRow(array $row): User
{
$user = new User();
$user->setEmail($row['email']);
$user->setName($row['name']);
return $user;
}
protected function getEntityManager(): \Doctrine\ORM\EntityManagerInterface
{
return $this->container->get('doctrine')->getManager();
}
}
Use the ImportType in a controller:
// src/AppBundle/Controller/ImportController.php
use Darkilliant\ImportBundle\Form\Type\ImportType;
use AppBundle\Import\UserImporter;
class ImportController extends Controller
{
public function importAction(Request $request)
{
$importer = new UserImporter($this->get('doctrine'));
$form = $this->createForm(ImportType::class, $importer, [
'csv_file' => 'users.csv',
]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$importer->run();
$this->addFlash('success', 'Import completed!');
}
return $this->render('import/index.html.twig', ['form' => $form->createView()]);
}
}
Define validation rules in transformRow() and handle errors:
protected function transformRow(array $row): User
{
if (empty($row['email'])) {
throw new \RuntimeException('Email is required.');
}
$user = new User();
$user->setEmail($row['email']);
return $user;
}
For large datasets, implement chunking:
protected function persistEntity($entity): void
{
$this->entityManager->persist($entity);
if ($this->getCount() % 20 === 0) {
$this->entityManager->flush();
$this->entityManager->clear();
}
}
Extend functionality via events (e.g., pre/post-import):
// src/AppBundle/EventListener/ImportListener.php
use Darkilliant\ImportBundle\Event\ImportEvent;
class ImportListener
{
public function onImport(ImportEvent $event)
{
if ($event->getImport()->getClass() === User::class) {
// Log or notify
}
}
}
Register in services.yml:
services:
AppBundle\EventListener\ImportListener:
tags:
- { name: kernel.event_listener, event: darkilliant.import, method: onImport }
Symfony Dependency
EventDispatcher or Doctrine patterns if migrating to Laravel.Outdated Codebase
symfony/validator, doctrine/orm).No Laravel Adapter
Request for file handling).Memory Limits
memory_limit. Use chunking or fgetcsv() for streaming.Enable Verbose Logging
Add to config/packages/monolog.yaml:
handlers:
import:
type: stream
path: "%kernel.logs_dir%/import.log"
level: debug
Validate CSV Structure
Use League\Csv\Reader to pre-validate files before import:
$csv = Reader::createFromPath($file->getPathname(), 'r');
$csv->setHeaderOffset(0);
foreach ($csv as $record) {
if (!isset($record['email'])) {
throw new \RuntimeException('Invalid CSV format.');
}
}
Doctrine Flush Issues If entities aren’t saving, check:
entityManager->flush() is called.$em->getConnection()->beginTransaction()).Custom File Parsers
Override Darkilliant\ImportBundle\Import\Import::parseFile() to support Excel/JSON:
protected function parseFile(SplFileInfo $file): array
{
$csv = Reader::createFromPath($file->getPathname(), 'r');
return iterator_to_array($csv);
}
Progress Tracking
Add a progress bar using Symfony’s ProgressComponent:
use Symfony\Component\Console\Helper\ProgressBar;
$progress = new ProgressBar($this->output);
$progress->start($this->getTotalRows());
foreach ($this->getRows() as $row) {
$this->transformRow($row);
$progress->advance();
}
$progress->finish();
Rollback on Failure Wrap imports in a Doctrine transaction:
$this->entityManager->beginTransaction();
try {
foreach ($this->getRows() as $row) {
$this->persistEntity($this->transformRow($row));
}
$this->entityManager->flush();
$this->entityManager->commit();
} catch (\Exception $e) {
$this->entityManager->rollback();
throw $e;
}
If using in Laravel:
File Uploads
Replace ImportType with Laravel’s FormRequest:
use Illuminate\Http\Request;
public function import(Request $request)
{
$file = $request->file('csv_file');
$importer = new UserImporter($this->app->make('db'));
$importer->setFile($file->getPathname());
$importer->run();
}
Doctrine Alternative
Use Laravel’s Eloquent or a Symfony bridge (e.g., spatie/laravel-symfony-support).
Event System
Use Laravel’s Events instead of Symfony’s EventDispatcher.
How can I help you explore Laravel packages today?