Dealing with Enum in a Symfony App with Doctrine2 as ORM

How to handle Enums in a Symfony application with Doctrine2, with a reusable abstract PHP Enum class, entity validation and a Symfony choice form type — no database-specific ENUM column.

Maxence Poutord
2 min read
Cover for Dealing with Enum in a Symfony App with Doctrine2 as ORM

Using Enum in a Symfony App isn’t obvious. If your Enum is short, you can directly put it on your entity. But if it grows, it will be quickly unmanageable.

The problem

Ok given, you want to create a message object which contains an attribute called type. Like Twitter Bootstrap’s Alert, your Message type’s attribute must contain some specific strings (e.g. info, success…).

In the official documentation, Doctrine provides 2 solutions for MySQL Database. What happens if we want to use another Database like PostgreSQL? By the way, you can also take a look at these solutions. As far as I am concerned, I don’t like them because it didn’t solve the problem on the PHP side.

Obviously, we can also create a Table called MessageType. But according to me, a database table must be used to store data. In this case, a type isn’t managed by a human.

So we need custom reusable PHP Enum.
Let’s do this!

a kid on a ship

A solution

First, you need to create a MessageTypeEnum.

<?php
namespace DemoBundle\Enum;
abstract class MessageTypeEnum
{
const TYPE_INFO = "info";
const TYPE_WARNING = "warning";
const TYPE_SUCCESS = "success";
const TYPE_DANGER = "danger";
/** @var array user friendly named type */
protected static $typeName = [
self::TYPE_INFO => 'Information',
self::TYPE_WARNING => 'Attention',
self::TYPE_SUCCESS => 'Succès',
self::TYPE_DANGER => 'Danger',
];
/**
* @param string $typeShortName
* @return string
*/
public static function getTypeName($typeShortName)
{
if (!isset(static::$typeName[$typeShortName])) {
return "Unknown type ($typeShortName)";
}
return static::$typeName[$typeShortName];
}
/**
* @return array<string>
*/
public static function getAvailableTypes()
{
return [
self::TYPE_INFO,
self::TYPE_WARNING,
self::TYPE_SUCCESS,
self::TYPE_DANGER
];
}

Here is an example of use:

<?php
echo MessageTypeEnum::TYPE_INFO;
//info
echo MessageTypeEnum::getTypeName(MessageTypeEnum::TYPE_INFO);
//Information

Now, you need to adapt your Entity:

<?php
class Message
{
/**
* @var string
* @ORM\Column(name="type", type="string", length=255, nullable=false)
*/
private $type;
//...
/**
* @param string $type
* @return Message
*/
public function setType($type)
{
if (!in_array($type, MessageTypeEnum::getAvailableTypes())) {
throw new \InvalidArgumentException("Invalid type");
}
$this->type = $type;
return $this;
}
}

And this is the form: (MessageType.php)

<?php
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('content')
->add('type', 'choice', array(
'required' => true,
'choices' => MessageTypeEnum::getAvailableTypes(),
'choices_as_values' => true,
'choice_label' => function($choice) {
return MessageTypeEnum::getTypeName($choice);
},
))
;
}

And tadaaa it works!

Your Form should look like this:


Maxence Poutord

Written by

Maxence Poutord

Hey, I'm Maxence Poutord, a senior software engineer at Orderfox. I'm also an indie hacker behind Pedalyze and YoutubeMate. When I'm not shipping, you can find me cooking, cycling or running. I'm also on Twitter, Bluesky, GitHub, and LinkedIn.

Keep reading

Recommended posts