PHP Doctrine: How to use Enum data type

Updated: January 13, 2024 By: Guest Contributor Post a comment

Introduction

When it comes to managing databases, it’s not only the SQL that matters, but also how you structure and handle your data helps in effectively modeling and querying your data. One important aspect is using appropriate data types that align with your data model. In this tutorial, we’ll explore the use of Enum data types in PHP Doctrine, an object-relational mapper (ORM) that bridges the gap between your PHP objects and database tables.

Enum, short for ‘enumeration’, is a data type that consists of a set of named values. These are typically used to represent a finite set of states or variations such as status codes, categories, weekdays, and more. Unlike other data types, Enum restricts the value to the defined set of constants, thereby ensuring that you always have a valid and expected value.

Understanding Enums in Doctrine

Doctrine doesn’t support Enum types natively. This is primarily because Enums are not a standard across all database platforms. However, you can map Enums in Doctrine through a custom data type or using Doctrine Extensions.

Defining Enum as a Custom Data Type

To create an Enum type in Doctrine, you need to define a custom data type class. Here’s a step-by-step guide on how to implement this:

  1. Extend the Doctrine\DBAL\Types\Type class.
  2. Implement the required methods: convertToPHPValue, convertToDatabaseValue, and getSQLDeclaration.
  3. Register the custom type with Doctrine and map it to the entity’s property.

Here is a simple example using a Status Enum:

namespace App\Db\Types;

use Doctrine\DBAL\Platforms\AbstractPlatform;
use Doctrine\DBAL\Types\Type;

class StatusType extends Type
{
    const STATUS_NEW = 'new';
    const STATUS_PENDING = 'pending';
    const STATUS_DONE = 'done';

    // Define the enum type name
    public function getName()
    {
        return 'enumstatus';
    }

    // Define the SQL declaration
    public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
    {
        return "ENUM('new', 'pending', 'done')";
    }

    // Convert database value to PHP Enum value
    public function convertToPHPValue($value, AbstractPlatform $platform)
    {
        switch ($value) {
            case self::STATUS_NEW:
                return self::STATUS_NEW;
            case self::STATUS_PENDING:
                return self::STATUS_PENDING;
            case self::STATUS_DONE:
                return self::STATUS_DONE;
            default:
                throw new \InvalidArgumentException("Unexpected status value");
        }
    }

    // Convert PHP Enum value to database value
    public function convertToDatabaseValue($value, AbstractPlatform $platform)
    {
        if (!in_array($value, [self::STATUS_NEW, self::STATUS_PENDING, self::STATUS_DONE])) {
            throw new \InvalidArgumentException("Invalid status");
        }
        return $value;
    }
}

This class declares a custom type ‘enumstatus’. When you define a field using this custom type, the getSQLDeclaration method returns the specific SQL needed to create an Enum column.

Mapping the Enum Type to an Entity

With the custom type created, you need to declare it within the mapping of your entity:

/**
 * @Entity
 * @Table(name="tasks")
 */

class Task
{
    /**
     * @Column(type="enumstatus")
     */
    protected $status;

    // getter and setter methods
}

Before using our custom type, it’s necessary to register it with Doctrine:

use App\Db\Types\StatusType;

Type::addType('enumstatus', StatusType::class);
$entityManager->getConnection()->getDatabasePlatform()->registerDoctrineTypeMapping('enumstatus', 'enumstatus');

Once registered, Doctrine will use our custom implementation when working with the status field on the Task entity.

Using Doctrine Extensions for Enum Types

Another approach is using a third-party library such as the Doctrine Extensions package. This library provides a set of Doctrine 2 behavioral extensions, one of which includes support for MySQL’s ENUM type. Here you would simply need to use the provided Enum type rather than writing your own.

Manipulating Enum Values

Working with Enums in your entities is straightforward. You will interact with these fields just as you would with any other field:

$task = new Task();
$task->setStatus(Task::STATUS_NEW);
$entityManager->persist($task);
$entityManager->flush();

Retrieving the value is simply a matter of using the appropriate getter method:

$status = $task->getStatus();

In addition, you could add validation to ensure the set and retrieved values are from the predefined Enum pool.

Conclusion

In this tutorial, we have covered how to work with Enum data types in PHP Doctrine. While Doctrine does not natively support Enum types, as it aims to be database-agnostic, there are ways around it. You can either define your own custom data types or use third-party libraries to manage your Enums. However, please be aware of the implications of using Enums, such as portability issues between different databases and difficulties in making changes to the Enum values once they’re in use. Carefully consider your use case before deciding to implement Enums in your database strategy.

Hopefully, this tutorial has offered the insights you need to make effective use of Enumerations in your PHP Doctrine-based applications. Good luck!