brokalia/doctrine-entity-generator
Installation Add the package via Composer:
composer require brokalia/doctrine-entity-generator
Enable the bundle in config/bundles.php (Symfony only):
return [
// ...
Brokalia\DoctrineEntityGeneratorBundle\BrokaliaDoctrineEntityGeneratorBundle::class => ['all' => true],
];
First Command Run the generator on a domain entity:
php artisan doctrine-generator:entity "App\\Domain\\MyDomainEntity"
(Note: Laravel uses php artisan instead of bin/console.)
Verify Output Check the generated Doctrine entity in:
src/Doctrine/Entity/MyDomainEntity.php
Generate a read-only domain entity with a UUID ID and map it to a Doctrine entity for persistence:
// src/Domain/MyDomainEntity.php
class MyDomainEntity {
public function __construct(
private Uuid $id,
private string $name,
) {}
}
Run the generator, then use the mapped entity in a repository:
// src/Repository/MyDomainEntityRepository.php
class MyDomainEntityRepository {
public function __construct(
private EntityManagerInterface $em,
) {}
public function save(MyDomainEntity $entity): void {
$doctrineEntity = DoctrineMyDomainEntity::fromDomain($entity);
$this->em->persist($doctrineEntity);
$this->em->flush();
}
}
Domain-First Development
php artisan doctrine-generator:entity "App\\Domain\\*" # Generate all
Value Object Handling
// Domain
class Address {
public function __construct(
private string $street,
private string $city,
) {}
}
// Generated Doctrine
#[Embeddable]
class DoctrineAddress {
#[Column(type: 'string')]
public string $street;
// ...
}
Repository Integration
fromDomain()/toDomain() methods:
$domain = $repository->find($id)
->map(fn ($entity) => DoctrineMyDomainEntity::toDomain($entity));
Partial Updates
php artisan doctrine-generator:entity "App\\Domain\\MyDomainEntity" --partial-updates
app/Console/Kernel.php to use php artisan:
protected $commands = [
\Brokalia\DoctrineEntityGeneratorBundle\Command\GenerateEntityCommand::class,
];
config/packages/brokalia_doctrine_entity_generator.yaml:
output_dir: '%kernel.project_dir%/database/doctrine-entities'
--force to overwrite generated files:
php artisan doctrine-generator:entity "App\\Domain\\*" --force
ID Field Requirements
id property.private ?string $id = null; // Temporary until domain logic is ready
Circular References
User ↔ Post) may cause infinite loops.--skip-relations or manually define mappings.Type Mismatches
int mapped to Doctrine string (or vice versa) without validation.toDomain()/fromDomain() methods:
public static function toDomain(DoctrineMyDomainEntity $entity): MyDomainEntity {
return new MyDomainEntity(
new Uuid($entity->id), // Cast string to Uuid
(int)$entity->quantity, // Cast int to string if needed
);
}
Laravel Eloquent Conflicts
# config/packages/brokalia_doctrine_entity_generator.yaml
namespace_prefix: 'App\\Doctrine\\'
--dry-run to preview changes without generating files:
php artisan doctrine-generator:entity "App\\Domain\\MyDomainEntity" --dry-run
-v for detailed logging:
php artisan doctrine-generator:entity "App\\Domain\\*" -v
var/cache/dev/doctrine-generator.log for paths.Custom Mappers
Override the default mapper by extending Brokalia\DoctrineEntityGeneratorBundle\Mapper\DefaultMapper:
// src/Service/CustomMapper.php
class CustomMapper extends DefaultMapper {
protected function mapProperty(Property $property): ?Attribute {
if ($property->getName() === 'createdAt') {
return new Attribute([new ORM\Column(['type' => 'datetime_immutable'])]);
}
return parent::mapProperty($property);
}
}
Register it in config/packages/brokalia_doctrine_entity_generator.yaml:
mapper: App\Service\CustomMapper
Post-Generation Hooks
Use Laravel’s generated:doctrine-entity event (if supported) or add a post-command hook:
// app/Console/Kernel.php
protected function schedule(Schedule $schedule) {
$schedule->command('doctrine-generator:entity {entity}')
->after(function () {
// Run migrations, tests, or other tasks
});
}
Skipping Properties Exclude properties from generation with PHPDoc:
/**
* @DoctrineIgnore
*/
private string $internalCache;
app/Console/Kernel.php for Laravel.$this->app->bind('doctrine.entity.generator', function () {
return new \Brokalia\DoctrineEntityGeneratorBundle\Generator();
});
$this->app->instance('doctrine.entity.generator', $mockGenerator);
How can I help you explore Laravel packages today?