Reputation: 1262
This is a followup question from my original question: Best strategy for migrating mysql enums to doctrine entities with symfony2?
I have been successful at adding an enum data type following the instructions here: http://docs.doctrine-project.org/projects/doctrine-orm/en/2.0.x/cookbook/mysql-enums.html More specifically I used the solution 2 using the latter part where I created a base EnumType Class and then extend it like:
<?php
namespace CP\AdminBundle\DataTypes;
class EnumContactBasicGender extends EnumType
{
protected $name = 'EnumContactBasicGender';
protected $values = array('m','f');
}
My EnumType class looks like:
<?php
namespace CP\AdminBundle\DataTypes;
use Doctrine\DBAL\Types\Type;
use Doctrine\DBAL\Platforms\AbstractPlatform;
abstract class EnumType extends Type
{
protected $name;
protected $values = array();
public function getSqlDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
{
$values = array_map(function($val) { return "'".$val."'"; }, $this->values);
return "ENUM(".implode(", ", $values).") COMMENT '(DC2Type:".$this->name.")'";
}
public function convertToPHPValue($value, AbstractPlatform $platform)
{
return $value;
}
public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
if (!in_array($value, $this->values)) {
throw new \InvalidArgumentException("Invalid enum value given: '".$this->value."' for enum: '".$this->name."'");
}
return $value;
}
public function getName()
{
return $this->name;
}
}
And then I registered my enums like this:
<?php
namespace CP\AdminBundle;
use Doctrine\DBAL\Types\Type;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class CPAdminBundle extends Bundle
{
public function boot()
{
$em = $this->container->get('doctrine.orm.entity_manager');
Type::addType('EnumContactBasicGender', 'CP\AdminBundle\DataTypes\EnumContactBasicGender');
Type::addType('EnumContactBasicType', 'CP\AdminBundle\DataTypes\EnumContactBasicType');
$em->getConnection()->getDatabasePlatform()->registerDoctrineTypeMapping('EnumContactBasicGender','EnumContactBasicGender');
$em->getConnection()->getDatabasePlatform()->registerDoctrineTypeMapping('EnumContactBasicType','EnumContactBasicType');
}
}
When I run the command ./app/console doctrine:generate:entities CP it works! It creates my entities with the new enum data types, it creates the setters and getters with no problem, one of my entities looks like this:
<?php
namespace CP\AdminBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* CP\AdminBundle\Entity\ContactBasic
*
* @ORM\Table(name="contacts_basics")
* @ORM\Entity(repositoryClass="CP\AdminBundle\Entity\ContactBasicRepository")
*/
class ContactBasic
{
/** Field #1 (contacts_id) **/
/**
* @var integer $contacts_id
* @ORM\Column(type="integer",nullable=false)
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $contacts_id;
/** enum ('m','f') **/
/**
* @ORM\Column(type="EnumContactBasicGender",nullable=false)
*/
private $gender;
/** enum ('non-customer','customer','blacklisted') **/
/**
* @ORM\Column(type="EnumContactBasicType",nullable=false)
*/
private $type;
/** more omitted properties here **/
/**
* Set gender
*
* @param EnumContactBasicGender $gender
*/
public function setGender(\EnumContactBasicGender $gender)
{
$this->gender = $gender;
}
/**
* Get gender
*
* @return EnumContactBasicGender
*/
public function getGender()
{
return $this->gender;
}
/**
* Set type
*
* @param EnumContactBasicType $type
*/
public function setType(\EnumContactBasicType $type)
{
$this->type = $type;
}
/**
* Get type
*
* @return EnumContactBasicType
*/
public function getType()
{
return $this->type;
}
/** more omitted setters and getters here **/
}
My problem comes when I create a fixture loader, I do not know how to set any of the enum values to get them saved to the database, so far my fixture loader class looks like this:
<?php
namespace CP\AdminBundle\DataFixtures\ORM;
use Doctrine\Common\DataFixtures\FixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
use CP\AdminBundle\Entity\ContactBasic;
use CP\AdminBundle\DataTypes\EnumContactBasicGender;
use CP\AdminBundle\DataTypes\EnumContactBasicType;
class ContactBasicLoader implements FixtureInterface
{
public function load(ObjectManager $manager)
{
$contact = new ContactBasic();
// $contact->setGender(new EnumContactBasicGender());
$contact->setGender('m');
// $contact->setType(new EnumContactBasicType());
$contact->setType('customer');
$manager->persist($contact);
$manager->flush();
}
}
When I run ./app/console doctrine:fixtures:load I get the following error:
Catchable Fatal Error: Argument 1 passed to CP\AdminBundle\Entity\ContactBasic::setGender() must be an instance of EnumContactBasicGender, string given
but if I pass the class like the commented lines above I also get an error.
Can someone please explain how I need to set the values needed?
Upvotes: 2
Views: 7947
Reputation: 1896
I faced a very similar issue, I solved by adding in the XXXEnumType class the same array of values but public and static, in this way I specified in a single place the content of my enum, access it from every where and foreach it :)
But first, check if you added my_foo_type in app/config/config.yml:
# Doctrine Configuration
doctrine:
dbal:
driver: %database_driver%
host: %database_host%
port: %database_port%
dbname: %database_name%
user: %database_user%
password: %database_password%
charset: UTF8
types:
my_foo_type: use XXX\DBAL\XXXEnumType
mapping_types:
enum: string
<?php
namespace XXX\DBAL;
class XXXEnumType extends EnumType
{
protected $name = 'enum_xxx';
protected $values = array('first', 'second', 'last');
public static $static_name = 'enum_xxx';
public static $static_values = array('first', 'second', 'last');
public function getValues()
{
return $this->values;
}
}
and from elsewhere in my project I can do:
use XXX\DBAL\XXXEnumType;
foreach (XXXEnumType::$static_values as $value)
{
//do some stuff
}
Hope it helps,
Linuxatico
Upvotes: 1
Reputation: 1702
Doctrine has no full support for enums. The enum types looks PRO but nobody plays with enums in that way. The workaround is to set few static vars in entity with integer value and set the enum field to the integer type.
With your issue I will change the setter of gender:
Regards, Max
Upvotes: 1