Provides support of ENUM type for Doctrine in Symfony applications.
- MySQL
- SQLite
- PostgreSQL
- PHP >= 5.4
- Symfony >= 2.6, also works with Symfony 3.0
- Doctrine >= 2.2
php composer.phar require fresh/doctrine-enum-bundle='v4.0'
- PHP >= 5.4
- Symfony >= 2.3 and <= 2.8
- Doctrine >= 2.2
php composer.phar require fresh/doctrine-enum-bundle='v3.3'
- PHP >= 5.3
- Symfony >= 2.3 and <= 2.7
- Doctrine >= 2.2
php composer.phar require fresh/doctrine-enum-bundle='v2.6'
To start using the bundle, register it in app/AppKernel.php
:
public function registerBundles()
{
$bundles = [
// Other bundles...
new Fresh\DoctrineEnumBundle\FreshDoctrineEnumBundle(),
];
}
Add following lines for doctrine configuration in config.yml
file:
# Doctrine Configuration
doctrine:
dbal:
mapping_types:
enum: string
In this example will be shown how to create custom ENUM field for basketball positions. This ENUM should contain five values:
PG
- Point GuardSG
- Shooting GuardSF
- Small ForwardPF
- Power ForwardC
- Center
Create a class for new ENUM type BasketballPositionType
:
<?php
namespace AppBundle\DBAL\Types;
use Fresh\DoctrineEnumBundle\DBAL\Types\AbstractEnumType;
final class BasketballPositionType extends AbstractEnumType
{
const POINT_GUARD = 'PG';
const SHOOTING_GUARD = 'SG';
const SMALL_FORWARD = 'SF';
const POWER_FORWARD = 'PF';
const CENTER = 'C';
protected static $choices = [
self::POINT_GUARD => 'Point Guard',
self::SHOOTING_GUARD => 'Shooting Guard',
self::SMALL_FORWARD => 'Small Forward',
self::POWER_FORWARD => 'Power Forward',
self::CENTER => 'Center'
];
}
Register BasketballPositionType
for Doctrine in config.yml:
# Doctrine Configuration
doctrine:
dbal:
types:
BasketballPositionType: AppBundle\DBAL\Types\BasketballPositionType
Create a Player
entity that has a position
field:
<?php
namespace AppBundle\Entity;
use AppBundle\DBAL\Types\BasketballPositionType;
use Doctrine\ORM\Mapping as ORM;
use Fresh\DoctrineEnumBundle\Validator\Constraints as DoctrineAssert;
/**
* @ORM\Entity()
* @ORM\Table(name="players")
*/
class Player
{
/**
* @ORM\Id
* @ORM\Column(name="id", type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* Note, that type of a field should be same as you set in Doctrine config
* (in this case it is BasketballPositionType)
*
* @ORM\Column(name="position", type="BasketballPositionType", nullable=false)
* @DoctrineAssert\Enum(entity="AppBundle\DBAL\Types\BasketballPositionType")
*/
protected $position;
public function getId()
{
return $this->id;
}
public function setPosition($position)
{
$this->position = $position;
}
public function getPosition()
{
return $this->position;
}
}
Now you can set a position for Player
inside some action or somewhere else:
$player->setPosition(BasketballPositionType::POINT_GUARD);
But don't forget to define BasketballPositionType
in the use section:
use AppBundle\DBAL\Types\BasketballPositionType;
NULL
values are also supported by ENUM field. You can set nullable parameter of column to true
or false
depends on if you want or not to allow NULL
values:
/** @ORM\Column(name="position", type="BasketballPositionType", nullable=true) */
protected $position;
// or
/** @ORM\Column(name="position", type="BasketballPositionType", nullable=false) */
protected $position;
When build BasketballPositionType
as form field, you don't need to specify some additional parameters. Just add property to the form builder and EnumTypeGuesser will do all work for you. That's how:
$builder->add('position');
If you need to add some extra parameters, just skip the second field type parameter:
$builder->add('position', null, [
'required' => true,
'attr' => [
'class' => 'some-class'
]
]);
If for some reason you need to specify full config, it can look like this:
$builder->add('position', 'choice', [
'choices' => BasketballPositionType::getChoices()
]);
EnumTypeGuesser process only DBAL types that are children of AbstractEnumType. All other custom DBAL types, which are defined, will be skipped from guessing.
AbstractEnumType provides few additional methods, which might be useful.
If you need to check if some string value exists in the array of ENUM values:
BasketballPositionType::isValueExist('Pitcher'); // false
If you need to get value in readable format:
BasketballPositionType::getReadableValue(BasketballPositionType::SHOOTING_GUARD);
// Will output: Shooting Guard
If you need to get value in readable format:
BasketballPositionType::getValues();
// Will output an array: ['PG', 'SG', 'SF', 'PF', 'C']
You might want to show ENUM values rendered in your templates in readable format instead of values that are stored in DB.
It is easy to do by using the custom TWIG filter |readable
that was implemented for this purpose.
In the example below if Player is a Point Guard in their basketball team then position will be rendered in template as Point Guard
instead of PG
.
{{ player.position|readable }}
How it works? If there is no additional parameter for the filter, ReadableEnumValueExtension tries to find which ENUM type from registered ENUM types has this value. If only one ENUM type found, then it is possible to get the readable value from it. Otherwise it will throw an exception.
For example BasketballPositionType
and MapLocationType
can have same ENUM value C
with its readable variant Center
.
The code below will throw an exception, because without additional parameter for |readable
filter, it can't determine which ENUM type to use in which case:
{{ set player_position = 'C' }}
{{ set location_on_the_map = 'C' }}
{{ player_position|readable }}
{{ location_on_the_map|readable }}
So, the correct usage of |readable
filter in this case should be with additional parameter, that specifies the ENUM type:
{{ set player_position = 'C' }}
{{ set location_on_the_map = 'C' }}
{{ player_position|readable('BasketballPositionType') }}
{{ location_on_the_map|readable('MapLocationType') }}
There is also another custom TWIG filter |enum_constant
. It allows to use constants from ENUM classes in templates to print their values or to compare with other values.
{{ 'SHOOTING_GUARD'|enum_constant }}
{{ 'NORTH_WEST'|enum_constant }}
{% if player.position == 'SHOOTING_GUARD'|enum_constant %}
<span class="custom-class">{{ player.position }}</span>
{% endif %}
Same problem as for |readable
filter is present here too. If some constant is defined in few ENUM classes then an exception will be thrown.
You can specify the correct class for this constant and it solves the problem.
{{ 'CENTER'|enum_constant('BasketballPositionType') }}
{{ 'CENTER'|enum_constant('MapLocationType') }}
If you use Doctrine migrations in your project you should be able to create migrations for you custom ENUM types.
If you want to create migration for the new ENUM type, then just use console commands doctrine:migrations:diff
to create migration and doctrine:migrations:migrate
to execute it.
For the previous example of BasketballPositionType
for MySQL DB (e.g.) Doctrine will generate SQL statement, that looks like this:
CREATE TABLE players (
id INT AUTO_INCREMENT NOT NULL,
position ENUM('PG', 'SG', 'SF', 'PF', 'C') NOT NULL COMMENT '(DC2Type:BasketballPositionType)',
PRIMARY KEY(id)
) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB
You can see here the comment '(DC2Type:BasketballPositionType)' for position
column. Doctrine will know that this column should be processed as BasketballPositionType
.
If you later will need to add new values to ENUM or delete some existed, you also will need to create new migrations. But Doctrine won't detect any changes in your ENUM... :(
Fortunately you can do simple hook =) Access your database and delete comment for position
column. After that run console command doctrine:migrations:diff
it will create correct migrations.
You should repeat these steps after each update of your custom ENUM type!