Skip to content
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
5c5bf62
Added support for Snowflake identifiers and all variations
puzzledpolymath Jul 16, 2025
09c697e
Updated UUID and ULID keeping psalm satisfied
puzzledpolymath Jul 16, 2025
ddb97c1
Added tests for Snowflake identifiers as well as updated tests for UU…
puzzledpolymath Jul 16, 2025
5bc9eb0
Updated documentation
puzzledpolymath Jul 16, 2025
eca8ae4
Updated composer dependencies
puzzledpolymath Jul 22, 2025
76ff381
Added classes for handling identifier default values
puzzledpolymath Jul 27, 2025
70758a1
Integrated defaults into identifier classes
puzzledpolymath Jul 27, 2025
289505f
Added tests for identifier defaults
puzzledpolymath Jul 27, 2025
f9b8cc4
Updated documentation
puzzledpolymath Jul 27, 2025
df00756
Updated documentation
puzzledpolymath Jul 27, 2025
759cd17
Add base Snowflake listener
roxblnfk Aug 10, 2025
ed571a2
Refactor SnowflakeDiscord
roxblnfk Aug 10, 2025
5130bbb
Refactor SnowflakeInstagram
roxblnfk Aug 10, 2025
bf24d19
Refactor other Snowflakes
roxblnfk Aug 10, 2025
e51f831
Refactor UUID listeners
roxblnfk Aug 10, 2025
61ec5ef
style(php-cs-fixer): fix coding standards
Aug 10, 2025
fb6df50
Provides fixes after merged changes broke a lot of things
puzzledpolymath Aug 19, 2025
907158d
Provides fixes after merged changes broke a lot of things
puzzledpolymath Aug 19, 2025
259a8ba
Refactor Snowflace typecasters
roxblnfk Sep 9, 2025
376a260
Refactor UUID listeners
roxblnfk Sep 9, 2025
ea368f8
Update dependencies
puzzledpolymath Nov 1, 2025
e0b77a0
Update docblock description for each Snowflake identifier
puzzledpolymath Nov 1, 2025
70611d2
Updated Ulid following a consistent structure
puzzledpolymath Nov 1, 2025
a5e9f10
Updated Ulid following a consistent structure
puzzledpolymath Nov 1, 2025
bbbbc77
Adjustments to keep Psalm happy
puzzledpolymath Nov 2, 2025
c0e8efd
Adjusted code placement
puzzledpolymath Nov 2, 2025
233fce4
Renamed static factory method and added abstract getTypecast method
puzzledpolymath Nov 2, 2025
8b2d2c4
Implemented UUIDv1 factory and getTypecast
puzzledpolymath Nov 2, 2025
0966faf
Implemented UUIDv2 factory and getTypecast, ensure listener arg local…
puzzledpolymath Nov 2, 2025
46d4d3f
Implemented UUIDv3 factory and getTypecast, made namespace and name o…
puzzledpolymath Nov 2, 2025
8bc4244
Implemented UUIDv4 factory and getTypecast
puzzledpolymath Nov 2, 2025
163bed8
Implemented UUIDv5 factory and getTypecast, made namespace and name o…
puzzledpolymath Nov 2, 2025
605adbf
Implemented UUIDv6 factory and getTypecast
puzzledpolymath Nov 2, 2025
18e62bb
Implemented UUIDv7 factory and getTypecast
puzzledpolymath Nov 2, 2025
7fd75d3
Ensure SnowflakeDiscord getProcessId returns int within range
puzzledpolymath Nov 2, 2025
2aac843
Added UUID factory to base UUID Listener
puzzledpolymath Nov 2, 2025
2d61e62
Updated UUIDv1 Listener to use factory, changed return type to more s…
puzzledpolymath Nov 2, 2025
af7cd67
Updated UUIDv2 Listener to use factory, changed return type to more s…
puzzledpolymath Nov 2, 2025
e430af8
Updated UUIDv2 Listener to use factory, changed return type to more s…
puzzledpolymath Nov 2, 2025
47d01a5
Updated UUIDv2 Listener to use factory, changed return type to more s…
puzzledpolymath Nov 2, 2025
ef86bdd
Updated UUIDv5 Listener to use factory, changed return type to more s…
puzzledpolymath Nov 2, 2025
6240cd8
Updated UUIDv6 Listener to use factory, changed return type to more s…
puzzledpolymath Nov 2, 2025
3c87203
Updated UUIDv7 Listener to use factory, changed return type to more s…
puzzledpolymath Nov 2, 2025
21bc7b7
Additional test fixtures
puzzledpolymath Nov 2, 2025
f2c23d8
Updated test cases
puzzledpolymath Nov 2, 2025
2ecded9
Updated documentation
puzzledpolymath Nov 2, 2025
73c830e
style(php-cs-fixer): fix coding standards
Nov 2, 2025
cb7c1c3
Removed superfluous PHP docs
puzzledpolymath Nov 2, 2025
e54123e
Removed unused imports
puzzledpolymath Nov 2, 2025
1962700
Improved test structure for listener classes
puzzledpolymath Nov 2, 2025
8adf742
Merge remote-tracking branch 'origin/snowflake-identifier' into snowf…
puzzledpolymath Nov 2, 2025
17fc49e
Improved documentation format and content
puzzledpolymath Nov 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 88 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# Cycle ORM Entity Behavior Identifier
[![Latest Stable Version](https://poser.pugx.org/cycle/entity-behavior-Identifier/version)](https://packagist.org/packages/cycle/entity-behavior-identifier)
[![Latest Stable Version](https://poser.pugx.org/cycle/entity-behavior-identifier/version)](https://packagist.org/packages/cycle/entity-behavior-identifier)
[![Build Status](https://github.com/cycle/entity-behavior-identifier/workflows/build/badge.svg)](https://github.com/cycle/entity-behavior-identifier/actions)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/cycle/entity-behavior-identifier/badges/quality-score.png?b=1.x)](https://scrutinizer-ci.com/g/cycle/entity-behavior-identifier/?branch=1.x)
[![Codecov](https://codecov.io/gh/cycle/entity-behavior-identifier/graph/badge.svg)](https://codecov.io/gh/cycle/entity-behavior)
<a href="https://discord.gg/TFeEmCs"><img src="https://img.shields.io/badge/discord-chat-magenta.svg"></a>

Expand All @@ -19,9 +18,90 @@ composer require cycle/entity-behavior-identifier

## Snowflake Examples

**Snowflake:** A distributed ID generation system developed by Twitter that produces 64-bit unique, sortable identifiers. Each ID encodes a timestamp, machine ID, and sequence number, enabling high-throughput, ordered ID creation suitable for large-scale distributed applications.
**Generic:** A flexible Snowflake format that can use a node identifier and any epoch offset, suitable for various applications requiring unique identifiers. Default values for `node` and `epochOffset` can be defined globally via class `Cycle\ORM\Entity\Behavior\Identifier\Defaults\SnowflakeGeneric`.

> **Note:** Support for Snowflake identifiers will arrive soon, stay tuned.
```php
use Cycle\Annotated\Annotation\Column;
use Cycle\Annotated\Annotation\Entity;
use Cycle\ORM\Entity\Behavior\Identifier;
use Ramsey\Identifier\Snowflake;

#[Entity]
#[Identifier\SnowflakeGeneric(field: 'id', node: 1, epochOffset: 1738265600000)]
class User
{
#[Column(type: 'snowflake', primary: true)]
private Snowflake $id;
}
```

**Discord:** Snowflake identifier for Discord's platform (voice, text, video), starting from epoch `2015-01-01`. Can incorporate a worker and process ID's to generate distinct Snowflakes. Default values for `workerId` and `processId` can be defined globally via class `Cycle\ORM\Entity\Behavior\Identifier\Defaults\SnowflakeDiscord`.

```php
use Cycle\Annotated\Annotation\Column;
use Cycle\Annotated\Annotation\Entity;
use Cycle\ORM\Entity\Behavior\Identifier;
use Ramsey\Identifier\Snowflake;

#[Entity]
#[Identifier\SnowflakeDiscord(field: 'id', workerId: 12, processId: 24)]
class User
{
#[Column(type: 'snowflake', primary: true)]
private Snowflake $id;
}
```

**Instagram:** Snowflake identifier for Instagram's photo and video sharing platform, with an epoch starting at `2011-08-24`. Can incorporate a shard ID to generate distinct Snowflakes. Default values for `shardId` can be defined globally via class `Cycle\ORM\Entity\Behavior\Identifier\Defaults\SnowflakeInstagram`.

```php
use Cycle\Annotated\Annotation\Column;
use Cycle\Annotated\Annotation\Entity;
use Cycle\ORM\Entity\Behavior\Identifier;
use Ramsey\Identifier\Snowflake;

#[Entity]
#[Identifier\SnowflakeInstagram(field: 'id', shardId: 16)]
class User
{
#[Column(type: 'snowflake', primary: true)]
private Snowflake $id;
}
```

**Mastodon:** Snowflake identifier for Mastodon’s decentralized social network, generated within a database to ensure uniqueness and approximate order within 1ms. Can include a table name for distinct sequences per table; IDs are unique on a single database but not guaranteed across multiple machines. Default values for `tableName` can be defined globally via class `Cycle\ORM\Entity\Behavior\Identifier\Defaults\SnowflakeMastodon`.

```php
use Cycle\Annotated\Annotation\Column;
use Cycle\Annotated\Annotation\Entity;
use Cycle\ORM\Entity\Behavior\Identifier;
use Ramsey\Identifier\Snowflake;

#[Entity]
#[Identifier\SnowflakeMastodon(field: 'id', tableName: 'users')]
class User
{
#[Column(type: 'snowflake', primary: true)]
private Snowflake $id;
}
```

**Twitter:** Snowflake identifier for Twitter (X), beginning from `2010-11-04`. Can incorporate a machine ID to generate distinct Snowflakes. Default values for `machineId` can be defined globally via class `Cycle\ORM\Entity\Behavior\Identifier\Defaults\SnowflakeTwitter`.

```php
use Cycle\Annotated\Annotation\Column;
use Cycle\Annotated\Annotation\Entity;
use Cycle\ORM\Entity\Behavior\Identifier;
use Ramsey\Identifier\Snowflake;

#[Entity]
#[Identifier\SnowflakeTwitter(field: 'id', machineId: 30)]
class User
{
#[Column(type: 'snowflake', primary: true)]
private Snowflake $id;
}
```

## ULID Examples

Expand All @@ -44,7 +124,7 @@ class User

## UUID Examples

**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.
**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`.

```php
use Cycle\Annotated\Annotation\Column;
Expand All @@ -61,7 +141,7 @@ class User
}
```

**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.
**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`.

```php
use Cycle\Annotated\Annotation\Column;
Expand Down Expand Up @@ -137,7 +217,7 @@ class User
}
```

**UUID Version 6 (Draft/Upcoming):** An experimental or proposed version focused on improving time-based UUIDs with more sortable properties (not yet widely adopted).
**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`.

```php
use Cycle\Annotated\Annotation\Column;
Expand Down Expand Up @@ -171,7 +251,7 @@ class User
}
```

You can find more information about Entity behavior UUID [here](https://cycle-orm.dev/docs/entity-behaviors-identifier).
You can find more information about Entity behavior Identifier [here](https://cycle-orm.dev/docs/entity-behaviors-identifier).

## License:

Expand Down
43 changes: 22 additions & 21 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 31 additions & 0 deletions src/Defaults/SnowflakeDiscord.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace Cycle\ORM\Entity\Behavior\Identifier\Defaults;

final class SnowflakeDiscord
{
private static int $workerId = 0;
private static int $processId = 0;

public static function getWorkerId(): int
{
return self::$workerId;
}

public static function setWorkerId(int $workerId): void
{
self::$workerId = $workerId;
}

public static function getProcessId(): int
{
return self::$processId;
}

public static function setProcessId(int $processId): void
{
self::$processId = $processId;
}
}
33 changes: 33 additions & 0 deletions src/Defaults/SnowflakeGeneric.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace Cycle\ORM\Entity\Behavior\Identifier\Defaults;

use Ramsey\Identifier\Snowflake\Epoch;

final class SnowflakeGeneric
{
private static int $node = 0;
private static Epoch|int $epochOffset = 0;

public static function getNode(): int
{
return self::$node;
}

public static function setNode(int $node): void
{
self::$node = $node;
}

public static function getEpochOffset(): Epoch|int
{
return self::$epochOffset;
}

public static function setEpochOffset(Epoch|int $epochOffset): void
{
self::$epochOffset = $epochOffset;
}
}
20 changes: 20 additions & 0 deletions src/Defaults/SnowflakeInstagram.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace Cycle\ORM\Entity\Behavior\Identifier\Defaults;

final class SnowflakeInstagram
{
private static int $shardId = 0;

public static function getShardId(): int
{
return self::$shardId;
}

public static function setShardId(int $shardId): void
{
self::$shardId = $shardId;
}
}
29 changes: 29 additions & 0 deletions src/Defaults/SnowflakeMastodon.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace Cycle\ORM\Entity\Behavior\Identifier\Defaults;

final class SnowflakeMastodon
{
/**
* @var non-empty-string|null
*/
private static ?string $tableName = null;

/**
* @return non-empty-string|null
*/
public static function getTableName(): ?string
{
return self::$tableName;
}

/**
* @param non-empty-string|null $tableName
*/
public static function setTableName(?string $tableName): void
{
self::$tableName = $tableName;
}
}
Loading
Loading