Installation:
composer require dmytrof/import-bundle
Enable in config/bundles.php:
Dmytrof\ImportBundle\DmytrofImportBundle::class => ['all' => true],
First Use Case:
Create a CSV file (data.csv) with headers matching your entity fields (e.g., name,email,role).
Define an importer class (e.g., UserImporter) extending Dmytrof\ImportBundle\Importer\AbstractImporter:
namespace App\Importer;
use App\Entity\User;
use Dmytrof\ImportBundle\Importer\AbstractImporter;
class UserImporter extends AbstractImporter
{
protected $entityClass = User::class;
protected $fields = ['name', 'email', 'role'];
public function transform(array $data): array
{
return [
'name' => $data['name'],
'email' => strtolower($data['email']),
'roles' => ['ROLE_' . strtoupper($data['role'])],
];
}
}
Run Import: Use the CLI command:
php bin/console dmytrof:import:run App\Importer\UserImporter data.csv
Define Importers:
Extend AbstractImporter for each entity type. Key methods:
getEntityClass(): Return the target entity class.getFields(): Define CSV headers → entity properties mapping.transform(array $data): Sanitize/convert raw data (e.g., normalize emails, map roles).Batch Processing:
Configure chunk size in config/packages/dmytrof_import.yaml:
dmytrof_import:
chunk_size: 50 # Process 50 rows per transaction
Validation:
Override validate(array $data) to enforce rules (e.g., email format):
public function validate(array $data): void
{
if (!filter_var($data['email'], FILTER_VALIDATE_EMAIL)) {
throw new \RuntimeException('Invalid email: ' . $data['email']);
}
}
Post-Import Actions:
Use postImport() to trigger events (e.g., send welcome emails):
public function postImport(array $entities): void
{
foreach ($entities as $user) {
$this->mailer->send(new WelcomeEmail($user));
}
}
prePersist/preUpdate for additional logic.ImportType to build admin forms for file uploads.AbstractImporter in PHPUnit:
$importer = $this->createMock(UserImporter::class);
$importer->method('transform')->willReturn(['name' => 'Test']);
Field Mismatches:
getFields() (case-sensitive).trim() in transform() to handle whitespace.Transaction Limits:
chunk_size or use flush() manually in transform().Circular References:
User → Profile) may fail.setEntityManager() to bypass Doctrine’s proxy detection:
$this->setEntityManager($entityManager);
Memory Leaks:
SplFileObject or use validate() sparingly.$this->getData() in transform() to inspect input:
file_put_contents('debug.csv', print_r($this->getData(), true));
dmytrof_import.debug in config to track import stats.writeEntity() to support non-Doctrine storage (e.g., Elasticsearch):
protected function writeEntity($entity): void
{
$this->elasticsearch->index($entity);
}
Dmytrof\ImportBundle\Mapper\ArrayMapper for dynamic field mapping:
$mapper = new ArrayMapper($this->getEntityClass());
$mapper->map($data, $entity);
dmytrof.import.pre/post events in services:
# config/services.yaml
App\EventListener\ImportListener:
tags:
- { name: kernel.event_listener, event: dmytrof.import.pre, method: onPreImport }
How can I help you explore Laravel packages today?