Doctrine 2 ORM DateTime field in identifier

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;

Be careful with

return new DateTimeEx('@' . $dateTime->format('U'));

The timezone won't be good. You should do :

$val = new DateTimeEx('@' . $dateTime->format('U'));
$val->setTimezone($dateTime->getTimezone());

return $val;

Tags:

Doctrine Orm