Description
Scenario:
I want to have an AUTO_INCREMENT id
from my DB layer, and also have a hash
as Uuid.
If you have your entity like this:
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
class Foo
{
/**
* @var int
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* @var Uuid
* @ORM\Column(type="uuid", unique=true)
* @ORM\GeneratedValue(strategy="CUSTOM")
* @ORM\CustomIdGenerator(class="Ramsey\Uuid\Doctrine\UuidGenerator")
*/
private $uuid;
// ...
}
When you try to persist a new entity:
$foo = new Foo();
$em->persist($foo);
$em->flush($foo);
Problem:
You will get an error saying:
"detail": "An exception occurred while executing 'INSERT INTO db_name.foo (id, hash) VALUES (?, ?)' with params ["431548bf-1a89-4552-90dd-a1ee89b659f8", "36710515-8595-49c0-86b9-8c504b7fb243"]:
Notice: Object of class Ramsey\Uuid\Uuid could not be converted to int",
I was wondering why this was happening so I went deeper into Doctrine, and inside UnitOfWord::persistNew($class, $entity)
I found something interesting:
$idGen = $class->idGenerator; [line: 895]
is a UuidGenerator
!?
But shoulnd't it be the generator for the id
property the @ORM\Id | @ORM\GeneratedValue(strategy="IDENTITY")
auto increment by default? Why it seems to be overrite it by the new Ramsey Uuid Generator
?
After a little research I came with the conclusion that Doctrine annotations -in order to determine the idGenerator- it loads by order which is the idGenerator for the entity. Which means the last one (annotation) override the previous one.
I came with this solution:
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
class Foo
{
/**
* @var Uuid
* @ORM\Column(type="uuid", unique=true)
* @ORM\GeneratedValue(strategy="CUSTOM")
* @ORM\CustomIdGenerator(class="Ramsey\Uuid\Doctrine\UuidGenerator")
*/
private $uuid;
/**
* IMPORTANT! This field annotation must be the last one in order to prevent
* that Doctrine will use UuidGenerator as $`class->idGenerator`!
*
* @var int
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
// ...
}
Conclusion: the solution was just moving as last annotation the id
property from the entity which it is actually the real id (as AUTO_INCREMENT int from the DB) and still have the Uuid
from Ramsey\Uuid\Uuid
.
I think we should avoid this ordering problem in our entities files and takes the idGenerator from the property which has @ORM\Id
.