Skip to content

Bug if you want to have an AUTO_INCREMENT id and an UUID #7215

Closed
@Chemaclass

Description

@Chemaclass

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.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions