fresh/doctrine-enum-bundle
Symfony bundle adding ENUM type support to Doctrine ORM/DBAL. Register custom enum types and map them to entity fields for safer, consistent values across databases. Works with modern Symfony/Doctrine versions and common platforms like PostgreSQL, MySQL, SQLite, and MSSQL.
Install the bundle:
composer require fresh/doctrine-enum-bundle
Symfony Flex will auto-register the bundle in config/bundles.php. If not, manually add:
Fresh\DoctrineEnumBundle\FreshDoctrineEnumBundle::class => ['all' => true],
Define your first enum:
Create a PHP 8.1+ enum (or use a backported class-based enum) in src/Enum/UserStatus.php:
namespace App\Enum;
use Fresh\DoctrineEnumBundle\Attributes\EnumType;
#[EnumType]
enum UserStatus: string
{
case ACTIVE = 'active';
case INACTIVE = 'inactive';
case PENDING = 'pending';
}
Use it in an entity:
use App\Enum\UserStatus;
use Doctrine\ORM\Mapping as ORM;
#[ORM\Entity]
class User
{
#[ORM\Column(type: 'enum', enumType: UserStatus::class)]
private UserStatus $status;
}
Run migrations:
php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate
First query:
$user = $entityManager->find(User::class, 1);
echo $user->getStatus()->value; // Outputs: 'active'
BooleanEnum, IntegerEnum) for quick adoption.#[EnumType]
enum OrderStatus: string
{
case PENDING = 'pending';
case PROCESSING = 'processing';
case SHIPPED = 'shipped';
case CANCELLED = 'cancelled';
}
jsonb or relational tables instead.doctrine:migrations:diff to auto-generate schema changes. For existing tables, manually add:
ALTER TABLE orders MODIFY status ENUM('pending', 'processing', 'shipped');
$builder->add('status', ChoiceType::class, [
'choices' => OrderStatus::cases(),
'choice_label' => fn(OrderStatus $status) => $status->value,
]);
$builder->add('status', HiddenType::class, [
'data' => OrderStatus::PENDING,
]);
{% if order.status == App\Enum\OrderStatus::SHIPPED %}
<span class="badge bg-success">Shipped</span>
{% endif %}
{% for status in App\Enum\OrderStatus::cases() %}
<option value="{{ status.value }}">{{ status.label }}</option>
{% endfor %}
enum_values filter (for custom labels):
{{ App\Enum\OrderStatus|enum_values('full_name') }}
"invalid") throw InvalidArgumentException at runtime.public function setStatus(OrderStatus $status): void
{
if ($this->status === OrderStatus::SHIPPED) {
throw new \LogicException("Cannot change status after shipment.");
}
$this->status = $status;
}
#[Groups] with Symfony Serializer:
#[SerializeAs('string')]
public function getStatus(): string
{
return $this->status->value;
}
#[ApiProperty]:
#[ApiProperty(enumType: OrderStatus::class)]
private OrderStatus $status;
public function findByStatus(OrderStatus $status): array
{
return $this->createQueryBuilder('o')
->where('o.status = :status')
->setParameter('status', $status->value)
->getQuery()
->getResult();
}
symfony/ux-autocomplete:
{{ include_ux_autocomplete_path('order_status', {
'choices': App\Enum\OrderStatus::cases(),
'choice_label': 'value'
}) }}
api_platform.yaml:
filters:
enum:
properties:
- status
$user = UserFactory::create(['status' => UserStatus::ACTIVE]);
$this->assertSame(UserStatus::ACTIVE, $user->getStatus());
utf8mb4_unicode_ci collation if case-insensitive comparisons are needed.string with a CHECK constraint. Test performance with large enum sets.fresh/doctrine-enum-bundle is configured for SQL Server in config/packages/doctrine.yaml:
dbal:
types:
enum: Fresh\DoctrineEnumBundle\DBAL\Types\EnumType
#[EnumType] with @Enum annotations:
use Fresh\DoctrineEnumBundle\Attributes\Enum;
#[Enum]
class LegacyUserStatus { ... }
#[EnumType] attributes. Use @Enum as a fallback.string column to enum, ensure all values match the enum cases. Use:
php bin/console doctrine:query:sql "UPDATE orders SET status = 'pending' WHERE status NOT IN ('pending', 'processing', 'shipped')"
enum → string downgrades gracefully. Write custom migration logic.{% if order.status == 'active' %}—always use the enum constant:
{% if order.status == App\Enum\OrderStatus::ACTIVE %}
php bin/console cache:clear
#[ORM\Index(columns: ['status'])]
How can I help you explore Laravel packages today?