Entity identifiers

← Entity identifiers

Ashterix

docs: Doctrine section with Doctrine Behaviors and Doctrine Helper (uk + en)

en/docs/doctrine/doctrine-helper/entity_ids.md new file +149 āˆ’0

1 + # Entity identifiers
2 +
3 + The traits in `Ufo\DoctrineHelper\Traits` add a `protected $id` property with the `#[ORM\Id]` and `#[ORM\Column]` attributes and a `getId()` method to an entity. The rest of the entity mapping (`#[ORM\Entity]`, table, other fields) is described as usual.
4 +
5 + | Trait | Column | Generation | `getId()` |
6 + |-------|--------|------------|-----------|
7 + | `AutoIncrementIdTrait` | `INTEGER`, unsigned | by the database (`#[ORM\GeneratedValue]`) | `?int` |
8 + | `UuidIdTrait` | `string(36)`, unique | in code: `generateUniqueId()` → UUID v7 | `string` |
9 + | `UniqueIdTrait` | `string(13)`, unique | in code: `generateUniqueId()` → `uniqid()` | `string` |
10 + | `UniqueUuidIdTrait` (deprecated) | `string(36)`, unique | as in `UuidIdTrait` | `string` |
11 +
12 + ## AutoIncrementIdTrait
13 +
14 + ```php
15 + use Doctrine\ORM\Mapping as ORM;
16 + use Ufo\DoctrineHelper\Traits\AutoIncrementIdTrait;
17 +
18 + #[ORM\Entity]
19 + class Customer
20 + {
21 + use AutoIncrementIdTrait;
22 + }
23 + ```
24 +
25 + The trait declares:
26 +
27 + ```php
28 + #[ORM\Id]
29 + #[ORM\Column(type: Types::INTEGER, options: ['unsigned' => true])]
30 + #[ORM\GeneratedValue]
31 + protected ?int $id = null;
32 + ```
33 +
34 + The value appears after `flush()`; until then `getId()` returns `null`.
35 +
36 + :::warning
37 + Do not combine the trait with the `IHaveAutoincrementId` interface: the trait's `getId(): ?int` is incompatible with the interface's `getId(): int`, and PHP stops with a fatal error. Details and a workaround are in [Known issues](/docs/doctrine/doctrine-helper/known_issues/open).
38 + :::
39 +
40 + ## UuidIdTrait
41 +
42 + ```php
43 + #[ORM\Id]
44 + #[ORM\Column(type: Types::STRING, length: 36, unique: true)]
45 + #[ORM\GeneratedValue(strategy: 'NONE')]
46 + protected string $id;
47 + ```
48 +
49 + Doctrine does not generate the value (`strategy: 'NONE'`), so the entity sets its own identifier, usually in the constructor:
50 +
51 + ```php
52 + use Doctrine\ORM\Mapping as ORM;
53 + use Ufo\DoctrineHelper\Interfaces\IHaveUniqueUuid;
54 + use Ufo\DoctrineHelper\Traits\UuidIdTrait;
55 +
56 + #[ORM\Entity]
57 + class Order implements IHaveUniqueUuid
58 + {
59 + use UuidIdTrait;
60 +
61 + public function __construct()
62 + {
63 + $this->generateUniqueId(); // e.g. 01a155a4-36cd-7341-9406-48aa6d401e53
64 + }
65 + }
66 + ```
67 +
68 + Trait methods:
69 +
70 + * `protected generateUniqueId(): void` — writes a new UUID v7 (`Uuid::generate()`) to `$id`. UUID v7 values are ordered by creation time, so they work well as an indexed primary key.
71 + * `public getId(): string`.
72 + * `public static uniqueIdFromString(string $string): string` — a deterministic UUID v3 from a string (`Uuid::hash()`): the same string always gives the same identifier.
73 +
74 + A deterministic identifier is handy when an entity is uniquely defined by a natural key:
75 +
76 + ```php
77 + #[ORM\Entity]
78 + class Tag implements IHaveUniqueUuid
79 + {
80 + use UuidIdTrait;
81 +
82 + #[ORM\Column]
83 + private string $name;
84 +
85 + public function __construct(string $name)
86 + {
87 + $this->id = self::uniqueIdFromString($name);
88 + $this->name = $name;
89 + }
90 + }
91 + ```
92 +
93 + If you neither call `generateUniqueId()` nor assign `$id`, the property stays uninitialized, and `getId()` or `persist()` fail with an error.
94 +
95 + ## UniqueIdTrait
96 +
97 + The same approach, but the identifier is the result of `uniqid()`: 13 hexadecimal characters (`string(13)`, unique), e.g. `6ad66fabb1662`.
98 +
99 + ```php
100 + use Ufo\DoctrineHelper\Traits\UniqueIdTrait;
101 +
102 + #[ORM\Entity]
103 + class Session
104 + {
105 + use UniqueIdTrait;
106 +
107 + public function __construct()
108 + {
109 + $this->generateUniqueId();
110 + }
111 + }
112 + ```
113 +
114 + `uniqid()` is built from the current time in microseconds and does not guarantee uniqueness when identifiers are created in parallel by several processes. Where that matters, use `UuidIdTrait`. This trait has no `uniqueIdFromString()` method.
115 +
116 + ## UniqueUuidIdTrait
117 +
118 + Marked `@deprecated Use UuidIdTrait instead`. It differs from `UuidIdTrait` only in lacking the `#[ORM\GeneratedValue]` attribute (for `#[ORM\Id]` without it Doctrine does not generate the value either). Switching is a one-line `use` change.
119 +
120 + ## Interfaces
121 +
122 + | Interface | Method | Compatible traits |
123 + |-----------|--------|-------------------|
124 + | `IHaveUniqueUuid` | `getId(): string` | `UuidIdTrait`, `UniqueIdTrait`, `UniqueUuidIdTrait` |
125 + | `IHaveAutoincrementId` | `getId(): int` | none (see the warning above) |
126 +
127 + The interfaces let you type code that works with any entity of a given key kind without binding it to a concrete class:
128 +
129 + ```php
130 + use Ufo\DoctrineHelper\Interfaces\IHaveUniqueUuid;
131 +
132 + function cacheKey(IHaveUniqueUuid $entity): string
133 + {
134 + return $entity::class . ':' . $entity->getId();
135 + }
136 + ```
137 +
138 + ## Uuid
139 +
140 + `Ufo\DoctrineHelper\Utils\Uuid` is a wrapper over `ramsey/uuid` used by the traits. It can also be called directly:
141 +
142 + ```php
143 + use Ufo\DoctrineHelper\Utils\Uuid;
144 +
145 + Uuid::generate(); // a new UUID v7
146 + Uuid::hash('test'); // UUID v3 in the OID namespace: always 61df151d-7508-321d-ada6-27936752b809
147 + ```
148 +
149 + Before 1.1.0 `Uuid::generate()` returned a UUID v4 (see the [Changelog](/docs/doctrine/doctrine-helper/change_log)).