Monday, September 26, 2011

Deal with SET field in your entities with Doctrine2 / Symfony2

Given MyEntity is an entity (mapping table my_entity), given mySetField is a MySQL SET field from this entity (mapping column my_set_field). Its admissible values are 'Value1', 'Value2' and 'Value3' :
<?php

namespace MyCompany\MyBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * MyCompany\MyBundle\Entity\MyEntity
 */
class MyEntity
{
   //SET de la colonne my_set_field
   const MY_SET_FIELD_VALUE1 = 'Value1';
   const MY_SET_FIELD_VALUE2 = 'Value2';
   const MY_SET_FIELD_VALUE3 = 'Value3';

   static private $_mySetFieldValues = null;

   /**
    * @var array $mySetField
    */
   private $mySetField;

   static public function getMySetFieldChoices()
   {
      // Build $_mySetFieldValues only if this is the first call
      if (self::$_mySetFieldValues == null)
      {
         self::$_mySetFieldValues = array ();
         $oClass = new \ReflectionClass('\MyCompany\MyBundle\Entity\MyEntity');
         $classConstants = $oClass->getConstants();
         $constantPrefix = "MY_SET_FIELD_";
         foreach ($classConstants as $key => $val)
         {
            if (substr($key, 0, strlen($constantPrefix)) === $constantPrefix)
            {
               self::$_mySetFieldValues[$val] = $val;
            }
         }
      }
      return self::$_mySetFieldValues;
   }

   /**
    * Set mySetField
    *
    * @param array $mySetField
    */
   public function setMySetField(array $mySetField)
   {
      foreach ($mySetField as $mySetValue)
      {
         if (!in_array($mySetValue, self::getMySetFieldChoices()))
         {
            throw new \InvalidArgumentException(
               sprintf('Invalid value for my_entity.my_set_field : %s.', $mySetValue)
            );
         }
      }

      $this->mySetField = implode(',', $mySetField);
   }

   /**
    * Get mySetField
    *
    * @return array
    */
   public function getMySetField()
   {
      return explode(',', $this->mySetField);
   }

}
We will no longer refer to values ​​of the field but to the constants, it allows to centralize these values ​​somewhere ! PS: Thanks to guyaloni (http://forum.symfony-project.org/viewtopic.php?f=23&t=37406&p=125387#p125382) for the ReflectionClass enhancement ;)

Sunday, September 18, 2011

Deal with ENUM fields in your entities with Doctrine2 / Symfony2

MyEntity is an entity (mapping table my_entity), myEnumField is a MySQL ENUM field from this entity (mapping column my_enum_field). Its admissible values are 'Value1', 'Value2' and 'Value3' :
<?php

namespace MyCompany\MyBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * MyCompany\MyBundle\Entity\MyEntity 
 */
class MyEntity
{
   //ENUM de la colonne my_enum_field 
   const MY_ENUM_FIELD_VALUE1 = 'Value1';
   const MY_ENUM_FIELD_VALUE2 = 'Value2';
   const MY_ENUM_FIELD_VALUE3 = 'Value3';

   static private $_myEnumFieldValues = null;

   /**
    * @var string $myEnumField 
    */
   private $myEnumField;

   static public function getMyEnumFieldChoices()
   {
      // Build $_myEnumFieldValues if this is the first call
      if (self::$_myEnumFieldValues == null)
      {
         self::$_myEnumFieldValues = array ();
         $oClass = new \ReflectionClass('\MyCompany\MyBundle\Entity\MyEntity');
         $classConstants = $oClass->getConstants();
         $constantPrefix = "MY_ENUM_FIELD_";
         foreach ($classConstants as $key => $val)
         {
            if (substr($key, 0, strlen($constantPrefix)) === $constantPrefix)
            {
               self::$_myEnumFieldValues[$val] = $val;
            }
         }
      }
      return self::$_myEnumFieldValues;
   }

   /**
    * Set myEnumField 
    * 
    * @param string $myEnumField 
    */
   public function setMyEnumField($myEnumField)
   {
      if (!in_array($myEnumField, self::getMyEnumFieldChoices()))
      {
         throw new \InvalidArgumentException(
            sprintf('Invalid value for my_entity.my_enum_field : %s.', $myEnumField)
         );
      }

      $this->myEnumField = $myEnumField;
   }

}
We will no longer refer to values ​​of the field but to the constants, it allows to centralize these values ​​somewhere ! PS: Thanks to guyaloni (http://forum.symfony-project.org/viewtopic.php?f=23&t=37406&p=125387#p125382) for the ReflectrionClass enhancement ;)

Deal with MySQL types natively unsupported by Doctrine2

Some types of data, specific to MySQL are not supported by Doctrine2 when generating the mapping and entities from an existing database (reverse engineering).

Nevertheless, there remains the possibility to easily convert them into basic types. Example with ENUM, VARBINARY and TINYBLOB types.

Everything goes in app/config.yml, in the "doctrine" section (only conf, very convenient), see the "mapping_types" attribute :
# Doctrine Configuration doctrine: dbal: default_connection: default connections: default: driver: %database_driver% host: %database_host% port: %database_port% dbname: %database_name% user: %database_user% password: %database_password% charset: UTF8 mapping_types: enum: string varbinary: string tinyblob: text connection1: ... orm: auto_generate_proxy_classes: %kernel.debug% auto_mapping: true