Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Doctrine 2 ORM DateTime field in identifier

Tags:

In our DB tables, we columns refID and date are a composite primary key, with one field of the identifier being mapped as a datetime:

class corpWalletJournal {     /**      * @ORM\Column(name="refID", type="bigint", nullable=false)      * @ORM\Id      * @ORM\GeneratedValue(strategy="NONE")      */     private $refID;      /**      * @ORM\Column(name="date", type="datetime", nullable=false)           * @ORM\Id      * @ORM\GeneratedValue(strategy="NONE")      */     private $date;      public function setRefID($refID)     {         $this->refID = $refID;     }      public function setDate(\DateTime $date)     {         $this->date = $date;     } } 

If we describe them in entity as @ORM\Id this code will return exception "cannot convert datetime to string"...

$filter = array(     'date' => $this->stringToDate($loopData['date']),      'refID' => $loopData['refID'] ));  $oCorpWJ = $this->em->getRepository('EveDataBundle:corpWalletJournal')->findOneBy($filter); // ... $oCorpWJ->setDate($this->stringToDate($loopData['date'])); // ... 

If we describe corpWalletJournal#date as a simple column, code works fine. Why?

How can we deal with it? We need to have both date and refID in the primary key.

ADDED:

So i created new class

use \DateTime;  class DateTimeEx extends DateTime {  public function __toString() {     return $this->format('Y-m-d h:i:s'); }  } 

And new type for it

use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Platforms\AbstractPlatform; use Eve\DataBundle\Entity\Type\DateTimeEx;  class DateTimeEx extends Type {     const DateTimeEx = 'datetime_ex';      public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)     {         return 'my_datetime_ex';     }      public function convertToPHPValue($value, AbstractPlatform $platform)     {         return new DateTimeEx($value);     }      public function convertToDatabaseValue($value, AbstractPlatform $platform)     {         return $value->format('Y-m-d h:i:s');     }      public function getName()     {         return self::DateTimeEx;     }      public function canRequireSQLConversion()     {         return true;     }  } 

How can i use them in entity?

My (edited) Type Class

    use Doctrine\DBAL\Types\Type; use Doctrine\DBAL\Platforms\AbstractPlatform;  class DateTimeEx extends Type {     const DateTimeEx = 'datetime_ex';      public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)     {         return 'my_datetime_ex';     }      public function convertToPHPValue($value, AbstractPlatform $platform)     {         return $value;     }      public function convertToDatabaseValue($value, AbstractPlatform $platform)     {         return $value;     }      public function getName()     {         return self::DateTimeEx;     }  } 
like image 336
user1954544 Avatar asked Feb 26 '13 02:02

user1954544


1 Answers

Doctrine 2 ORM needs to convert identifier fields to strings in the UnitOfWork. This is required to have the EntityManager being able to track changes to your objects.

Since objects of type DateTime don't natively implement method __toString, converting them to strings is not as simple as casting them to strings.

Therefore, the default date, datetime and time types are not supported as part of the identifier.

To deal with it, you should define your own custom field type mydatetime mapped to your own MyDateTime class which implements __toString. That way, the ORM can handle identifiers also if they contain objects.

Here's an example of how that class may look like:

class MyDateTime extends \DateTime  {     public function __toString()     {         return $this->format('U');     } } 

And here's an example of how the custom DBAL type would look like:

use Doctrine\DBAL\Types\DateTimeType; use Doctrine\DBAL\Platforms\AbstractPlatform;  class MyDateTimeType extends DateTimeType {     public function convertToPHPValue($value, AbstractPlatform $platform)     {         $dateTime = parent::convertToPHPValue($value, $platform);                  if ( ! $dateTime) {             return $dateTime;         }          $val = new MyDateTime('@' . $dateTime->format('U'));         $val->setTimezone($dateTime->getTimezone());         return $val;     }      public function requiresSQLCommentHint(AbstractPlatform $platform)     {         return true;     }      public function getName()     {         return 'mydatetime';     } } 

Then you register it with your ORM configuration during bootstrap (depends on the framework you are using). In symfony, it is documented on the symfony doctrine documentation.

After that, you can use it in your entities:

class corpWalletJournal {     // ...      /**      * @ORM\Column(name="date", type="mydatetime", nullable=false)           * @ORM\Id      * @ORM\GeneratedValue(strategy="NONE")      */     private $date; 
like image 68
Ocramius Avatar answered Oct 01 '22 01:10

Ocramius