Skip to content

Commit e51f831

Browse files
committed
Refactor UUID listeners
1 parent bf24d19 commit e51f831

20 files changed

+304
-358
lines changed

README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,8 @@ class User
129129

130130
## UUID Examples
131131

132-
**UUID Version 1 (Time-based):** Generated using the current timestamp and the MAC address of the computer, ensuring unique identification based on time and hardware. Default values for `node` and `clockSeq` can be defined globally via class `Cycle\ORM\Entity\Behavior\Identifier\Defaults\Uuid1`.
132+
### UUID Version 1 (Time-based)
133+
Generated using the current timestamp and the MAC address of the computer, ensuring unique identification based on time and hardware. Default values for `node` and `clockSeq` can be defined globally via the `\Cycle\ORM\Entity\Behavior\Identifier\Listener\Uuid1::setDefaults()` method.
133134

134135
```php
135136
use Cycle\Annotated\Annotation\Column;
@@ -146,7 +147,8 @@ class User
146147
}
147148
```
148149

149-
**UUID Version 2 (DCE Security):** Similar to version 1 but includes a local identifier such as a user ID or group ID, primarily used in DCE security contexts. Default values for `localDomain`, `localIdentifier`, `node` and `clockSeq` can be defined globally via class `Cycle\ORM\Entity\Behavior\Identifier\Defaults\Uuid2`.
150+
### UUID Version 2 (DCE Security)
151+
Similar to version 1 but includes a local identifier such as a user ID or group ID, primarily used in DCE security contexts. Default values for `localDomain`, `localIdentifier`, `node` and `clockSeq` can be defined globally via the `\Cycle\ORM\Entity\Behavior\Identifier\Listener\Uuid2::setDefaults()` method.
150152

151153
```php
152154
use Cycle\Annotated\Annotation\Column;
@@ -222,7 +224,8 @@ class User
222224
}
223225
```
224226

225-
**UUID Version 6 (Draft/Upcoming):** An experimental or proposed version focused on improving time-based UUIDs with more sortable properties (not yet widely adopted). Default values for `node` and `clockSeq` can be defined globally via class `Cycle\ORM\Entity\Behavior\Identifier\Defaults\Uuid6`.
227+
### UUID Version 6 (Draft/Upcoming)
228+
An experimental or proposed version focused on improving time-based UUIDs with more sortable properties (not yet widely adopted). Default values for `node` and `clockSeq` can be defined globally via the `\Cycle\ORM\Entity\Behavior\Identifier\Listener\Uuid6::setDefaults()` method.
226229

227230
```php
228231
use Cycle\Annotated\Annotation\Column;

src/Defaults/Uuid1.php

Lines changed: 0 additions & 43 deletions
This file was deleted.

src/Defaults/Uuid2.php

Lines changed: 0 additions & 67 deletions
This file was deleted.

src/Defaults/Uuid6.php

Lines changed: 0 additions & 43 deletions
This file was deleted.

src/Listener/BaseUuid.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Cycle\ORM\Entity\Behavior\Identifier\Listener;
6+
7+
use Cycle\ORM\Entity\Behavior\Attribute\Listen;
8+
use Cycle\ORM\Entity\Behavior\Event\Mapper\Command\OnCreate;
9+
10+
abstract class BaseUuid
11+
{
12+
/**
13+
* @param non-empty-string $field The name of the field to store the UUID
14+
* @param bool $nullable Indicates whether the UUID can be null
15+
*/
16+
public function __construct(
17+
private readonly string $field,
18+
private readonly bool $nullable = false,
19+
) {}
20+
21+
#[Listen(OnCreate::class)]
22+
public function __invoke(OnCreate $event): void
23+
{
24+
if ($this->nullable || isset($event->state->getData()[$this->field])) {
25+
return;
26+
}
27+
28+
$event->state->register($this->field, $this->createValue());
29+
}
30+
31+
abstract protected function createValue(): \Ramsey\Identifier\Uuid;
32+
}

src/Listener/SnowflakeDiscord.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@
1414
final class SnowflakeDiscord extends Snowflake
1515
{
1616
/** @var int<0, 281474976710655> */
17-
private static int $workerId = 0;
17+
private static int $defaultWorkerId = 0;
1818

1919
/** @var null|int<0, 281474976710655> */
20-
private static ?int $processId = null;
20+
private static ?int $defaultProcessId = null;
2121

2222
private DiscordSnowflakeFactory $factory;
2323

@@ -33,7 +33,7 @@ public function __construct(
3333
?int $workerId = null,
3434
?int $processId = null,
3535
) {
36-
$workerId ??= self::$workerId;
36+
$workerId ??= self::$defaultWorkerId;
3737
$processId ??= $this->getProcessId();
3838
$this->factory = new DiscordSnowflakeFactory($workerId, $processId);
3939
parent::__construct($field, $nullable);
@@ -54,8 +54,8 @@ public static function setDefaults(?int $workerId, ?int $processId): void
5454
throw new \InvalidArgumentException('Process ID must be between 0 and 281474976710655.');
5555
}
5656

57-
self::$workerId = (int) $workerId;
58-
self::$processId = $processId;
57+
self::$defaultWorkerId = (int) $workerId;
58+
self::$defaultProcessId = $processId;
5959
}
6060

6161
#[\Override]
@@ -71,6 +71,6 @@ protected function createValue(): DiscordSnowflake
7171
*/
7272
private function getProcessId(): int
7373
{
74-
return self::$processId ??= \getmypid();
74+
return self::$defaultProcessId ??= \getmypid();
7575
}
7676
}

src/Listener/SnowflakeGeneric.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ final class SnowflakeGeneric extends \Cycle\ORM\Entity\Behavior\Identifier\Liste
1717
/** @var int<0, 1023> */
1818
private static int $node = 0;
1919

20-
/** @var Epoch|int */
2120
private static Epoch|int $epochOffset = 0;
2221

2322
private GenericSnowflakeFactory $factory;

src/Listener/Uuid1.php

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,34 +4,53 @@
44

55
namespace Cycle\ORM\Entity\Behavior\Identifier\Listener;
66

7-
use Cycle\ORM\Entity\Behavior\Attribute\Listen;
8-
use Cycle\ORM\Entity\Behavior\Event\Mapper\Command\OnCreate;
9-
use Ramsey\Identifier\Uuid\UuidFactory;
7+
use Ramsey\Identifier\Uuid\UuidV1Factory;
108

11-
final class Uuid1
9+
/**
10+
* Generates UUIDv1 identifiers for entities.
11+
* You can set default node and clock sequence using the {@see setDefaults()} method.
12+
*/
13+
final class Uuid1 extends BaseUuid
1214
{
15+
/** @var int<0, 281474976710655>|non-empty-string|null */
16+
private static int|string|null $defaultNode = null;
17+
18+
private static ?int $defaultClockSeq = null;
19+
private UuidV1Factory $factory;
20+
1321
/**
14-
* @param int<0, 281474976710655>|non-empty-string|null $node
22+
* @param non-empty-string $field The name of the field to store the UUID
23+
* @param bool $nullable Indicates whether the UUID can be null
24+
* @param int<0, 281474976710655>|non-empty-string|null $node A 48-bit integer or hexadecimal string representing the hardware address
25+
* @param int|null $clockSeq A number used to help avoid duplicates that could arise when the clock is set backwards in time
1526
*/
1627
public function __construct(
17-
private string $field = 'uuid',
18-
private int|string|null $node = null,
19-
private ?int $clockSeq = null,
20-
private bool $nullable = false,
21-
) {}
22-
23-
#[Listen(OnCreate::class)]
24-
public function __invoke(OnCreate $event): void
25-
{
26-
if ($this->nullable || isset($event->state->getData()[$this->field])) {
27-
return;
28-
}
28+
string $field,
29+
bool $nullable = false,
30+
private readonly int|string|null $node = null,
31+
private readonly ?int $clockSeq = null,
32+
) {
33+
$this->factory = new UuidV1Factory();
34+
parent::__construct($field, $nullable);
35+
}
2936

30-
$identifier = (new UuidFactory())->v1(
31-
$this->node,
32-
$this->clockSeq,
33-
);
37+
/**
38+
* Set default node and clock sequence for UUIDv1 generation.
39+
*
40+
* @param int<0, 281474976710655>|non-empty-string|null $node The node to set
41+
* @param int|null $clockSeq The clock sequence to set
42+
*/
43+
public static function setDefaults(int|string|null $node, ?int $clockSeq): void
44+
{
45+
self::$defaultNode = $node;
46+
self::$defaultClockSeq = $clockSeq;
47+
}
3448

35-
$event->state->register($this->field, $identifier);
49+
#[\Override]
50+
protected function createValue(): \Ramsey\Identifier\Uuid
51+
{
52+
$node = $this->node ?? self::$defaultNode;
53+
$clockSeq = $this->clockSeq ?? self::$defaultClockSeq;
54+
return $this->factory->create($node, $clockSeq);
3655
}
3756
}

0 commit comments

Comments
 (0)