Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Doctrine Enum Bundle Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. 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],
    
  2. 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';
    }
    
  3. 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;
    }
    
  4. Run migrations:

    php bin/console doctrine:migrations:diff
    php bin/console doctrine:migrations:migrate
    
  5. First query:

    $user = $entityManager->find(User::class, 1);
    echo $user->getStatus()->value; // Outputs: 'active'
    

Where to Look First


Implementation Patterns

Core Workflows

1. Entity Design with Enums

  • Pattern: Use enums for immutable, finite sets of values (e.g., statuses, roles, flags).
    #[EnumType]
    enum OrderStatus: string
    {
        case PENDING = 'pending';
        case PROCESSING = 'processing';
        case SHIPPED = 'shipped';
        case CANCELLED = 'cancelled';
    }
    
  • Anti-pattern: Avoid enums for dynamic values (e.g., user-generated tags). Use jsonb or relational tables instead.

2. Database Schema

  • The bundle generates native ENUM columns (PostgreSQL/MySQL) or string columns with checks (SQLite/MSSQL).
  • Migration tip: Use doctrine:migrations:diff to auto-generate schema changes. For existing tables, manually add:
    ALTER TABLE orders MODIFY status ENUM('pending', 'processing', 'shipped');
    

3. Form Integration

  • ChoiceType for dropdowns:
    $builder->add('status', ChoiceType::class, [
        'choices' => OrderStatus::cases(),
        'choice_label' => fn(OrderStatus $status) => $status->value,
    ]);
    
  • Hidden fields for APIs:
    $builder->add('status', HiddenType::class, [
        'data' => OrderStatus::PENDING,
    ]);
    

4. Twig Templating

  • Access enum values:
    {% if order.status == App\Enum\OrderStatus::SHIPPED %}
        <span class="badge bg-success">Shipped</span>
    {% endif %}
    
  • Render all options:
    {% for status in App\Enum\OrderStatus::cases() %}
        <option value="{{ status.value }}">{{ status.label }}</option>
    {% endfor %}
    
  • Use the enum_values filter (for custom labels):
    {{ App\Enum\OrderStatus|enum_values('full_name') }}
    

5. Validation and Business Logic

  • Type safety: Invalid values (e.g., "invalid") throw InvalidArgumentException at runtime.
  • State transitions: Enforce rules in setters:
    public function setStatus(OrderStatus $status): void
    {
        if ($this->status === OrderStatus::SHIPPED) {
            throw new \LogicException("Cannot change status after shipment.");
        }
        $this->status = $status;
    }
    

6. APIs and Serialization

  • Normalizers: Use #[Groups] with Symfony Serializer:
    #[SerializeAs('string')]
    public function getStatus(): string
    {
        return $this->status->value;
    }
    
  • API Platform: Works out-of-the-box with #[ApiProperty]:
    #[ApiProperty(enumType: OrderStatus::class)]
    private OrderStatus $status;
    

Integration Tips

With Doctrine Extensions

  • STI (Single Table Inheritance): Enums work but ensure the enum column is not inherited if values differ per child class.
  • Custom Repository Methods:
    public function findByStatus(OrderStatus $status): array
    {
        return $this->createQueryBuilder('o')
            ->where('o.status = :status')
            ->setParameter('status', $status->value)
            ->getQuery()
            ->getResult();
    }
    

With Symfony UX

  • Autocomplete: Pair with symfony/ux-autocomplete:
    {{ include_ux_autocomplete_path('order_status', {
        'choices': App\Enum\OrderStatus::cases(),
        'choice_label': 'value'
    }) }}
    

With API Platform

  • Filtering: Enable enum filtering in api_platform.yaml:
    filters:
        enum:
            properties:
                - status
    

With Tests

  • Factory Boy: Use enums directly in factories:
    $user = UserFactory::create(['status' => UserStatus::ACTIVE]);
    
  • PHPUnit: Assert enum values:
    $this->assertSame(UserStatus::ACTIVE, $user->getStatus());
    

Gotchas and Tips

Pitfalls

1. Database Compatibility

  • MySQL/MariaDB: ENUM columns are case-sensitive by default. Use utf8mb4_unicode_ci collation if case-insensitive comparisons are needed.
  • SQLite: Does not support native ENUM types. The bundle falls back to string with a CHECK constraint. Test performance with large enum sets.
  • MSSQL: Requires a custom type mapping. Ensure fresh/doctrine-enum-bundle is configured for SQL Server in config/packages/doctrine.yaml:
    dbal:
        types:
            enum: Fresh\DoctrineEnumBundle\DBAL\Types\EnumType
    

2. PHP 8.1+ Attributes

  • Legacy code: If using Symfony <6.0 or PHP <8.1, replace #[EnumType] with @Enum annotations:
    use Fresh\DoctrineEnumBundle\Attributes\Enum;
    
    #[Enum]
    class LegacyUserStatus { ... }
    
  • IDE support: Some older IDEs (e.g., PHPStorm <2021.3) may not recognize #[EnumType] attributes. Use @Enum as a fallback.

3. Migration Issues

  • Existing columns: If migrating an existing 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')"
    
  • Downgrades: Doctrine migrations may not handle enumstring downgrades gracefully. Write custom migration logic.

4. Twig Template Quirks

  • Enum constants in Twig: Avoid {% if order.status == 'active' %}—always use the enum constant:
    {% if order.status == App\Enum\OrderStatus::ACTIVE %}
    
  • Caching: Twig caches enum constants. Clear cache after adding new enum cases:
    php bin/console cache:clear
    

5. Performance

  • Large enums: Avoid enums with >50 cases. Consider a lookup table for dynamic values.
  • Indexing: Ensure enum columns are indexed in queries:
    #[ORM\Index(columns: ['status'])]
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor
spatie/laravel-javascript-views