danaki/doctrine-enum-type-bundle
Install the Bundle
composer require danaki/doctrine-enum-type-bundle
Configure Enums
Create config/packages/doctrine_enum_type.yaml:
danaki_doctrine_enum_type:
types:
App\Enum\YourEnum: ~
Replace App\Enum\YourEnum with your actual enum class (must extend Acelaya\Enum\AbstractEnum).
Define an Enum
Example in app/Enum/Status.php:
namespace App\Enum;
use Acelaya\Enum\AbstractEnum;
final class Status extends AbstractEnum
{
public const ACTIVE = 'active';
public const INACTIVE = 'inactive';
protected static function getValues(): array
{
return [
self::ACTIVE,
self::INACTIVE,
];
}
}
Use in Doctrine Entities
use App\Enum\Status;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
class User
{
#[ORM\Column(type: 'enum_gender')] // Default type; configure in YAML
private Status $status;
}
Clear Cache
php bin/console cache:clear
Replace a string column (status: string) with an enum column:
# config/packages/doctrine_enum_type.yaml
danaki_doctrine_enum_type:
types:
App\Enum\Status: ~
Update the entity:
#[ORM\Column(type: 'enum_status')] // Custom type name (optional)
private Status $status;
Run migrations and update existing data via a migration or repository method.
Define Enums Early
Create enums for domain-specific values (e.g., OrderStatus, UserRole) before modeling entities.
Example:
namespace App\Enum;
final class OrderStatus extends AbstractEnum {
public const PENDING = 'pending';
public const SHIPPED = 'shipped';
public const CANCELLED = 'cancelled';
// ...
}
Consistent Type Naming
Use a naming convention for Doctrine types (e.g., enum_{EnumClassName}):
danaki_doctrine_enum_type:
types:
enum_order_status: App\Enum\OrderStatus
Reference in entities:
#[ORM\Column(type: 'enum_order_status')]
private OrderStatus $status;
Integration with Forms
Use EnumType from Symfony’s form component:
use App\Enum\Status;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
$builder->add('status', EnumType::class, [
'class' => Status::class,
'choice_label' => fn($status) => ucfirst($status->value),
]);
Querying with Enums Filter by enum values in repositories:
$activeUsers = $entityManager->getRepository(User::class)
->createQueryBuilder('u')
->where('u.status = :status')
->setParameter('status', Status::ACTIVE)
->getQuery()
->getResult();
API Responses Serialize enums to strings in JSON:
#[Serializer\SerializedName('status')]
public function getStatusValue(): string {
return $this->status->value;
}
Database Compatibility
Ensure your database supports ENUM types (MySQL) or use string with validation (PostgreSQL/SQLite).
For PostgreSQL, configure a custom type in doctrine_enum_type.yaml:
danaki_doctrine_enum_type:
types:
App\Enum\Status:
type: string
length: 20
Validation Combine with Symfony’s validator for runtime checks:
use Symfony\Component\Validator\Constraints as Assert;
#[ORM\Column(type: 'enum_status')]
#[Assert\Type(type: 'App\Enum\Status')]
private Status $status;
Testing Mock enums in unit tests:
$this->entity->setStatus(Status::ACTIVE);
$this->assertEquals(Status::ACTIVE, $this->entity->getStatus());
Cache Dependencies
php bin/console cache:clear
rm -rf var/cache/*
Enum Class Requirements
Acelaya\Enum\AbstractEnum and implement getValues().use Acelaya\Enum\AbstractEnum;
final class Status extends AbstractEnum { ... }
Database-Specific Quirks
ENUM type (limited to 64 values).string; ensure length constraints in YAML:
danaki_doctrine_enum_type:
types:
App\Enum\Status:
type: string
length: 20
Case Sensitivity
strtolower()) or use constants consistently.Migration Order
nullable: true temporarily.Check Configuration
Validate doctrine_enum_type.yaml syntax and enum class paths. Use:
php bin/console debug:config danaki_doctrine_enum_type
Doctrine Events
Listen for loadClassMetadata to debug type mapping:
$eventManager->addEventListener(ORM\Events::loadClassMetadata, function (ORM\Event\LoadClassMetadataEvent $event) {
if ($event->getClassMetadata()->hasField('status')) {
dump($event->getClassMetadata()->getTypeOfField('status'));
}
});
SQL Logging Enable Doctrine SQL logging to verify generated queries:
# config/packages/dev/doctrine.yaml
doctrine:
dbal:
logging: true
logging_format: '%%sql%% %%params%%'
Custom Type Mappings Extend the bundle’s configuration for non-standard types:
danaki_doctrine_enum_type:
types:
App\Enum\Priority:
type: integer
values:
LOW: 1
HIGH: 2
Dynamic Enum Registration Register enums programmatically in a compiler pass:
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
class EnumCompilerPass implements CompilerPassInterface {
public function process(ContainerBuilder $container) {
$definition = $container->findDefinition('danaki_doctrine_enum_type.type_registry');
$definition->addMethodCall('addType', ['App\Enum\DynamicEnum', []]);
}
}
Symfony UX Autocomplete Integrate with Symfony UX for dynamic enum selection:
use Symfony\UX\Autocomplete\Attribute\AutocompleteSource;
#[AutocompleteSource('status_autocomplete')]
public function getStatusChoices(): array {
return array_map(fn($status) => ['value' => $status, 'label' => ucfirst($status)], Status::getValues());
}
Enum Utilities Add helper methods to enums for common operations:
final class Status extends AbstractEnum {
public static function isActive(string $value): bool {
return $value === self::ACTIVE;
}
}
API Platform Integration
Use @ApiProperty to customize OpenAPI schema:
use ApiPlatform\Metadata\ApiProperty;
#[ApiProperty(enum: [Status::ACTIVE, Status::INACTIVE])]
private Status $status;
Performance For large datasets, index enum columns:
#[ORM\Column(type: 'enum_status')]
#[ORM\Index]
private Status $status;
How can I help you explore Laravel packages today?