Компонент UID

Дата оновлення перекладу 2022-12-12

Компонент UID

Компонент UID надає утиліти для роботи з унікальними ідентифиіаторами (UIDs), на кшталт UUID и ULID.

Установка

1
$ composer require symfony/uid

Note

Якщо ви встановлюєте цей компонент поза додатком Symfony, вам потрібно підключити файл vendor/autoload.phpу вашому коді для включення механізму автозавантаження класів, наданих Composer. Детальніше можна прочитати у цій статті.

UUID

UUID (універсально унікальні ідентифікатори) - це одні з найпопулярніших UID
в індустрії ПЗ. UUID - це 128-бітні числа, зазвичай представлені у вигляді 5 груп шістнадцяткових символів: xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx (знак M - UUID версія, а знак N - UUID-варіант).

Створення UUID

Використайте іменовані конструктри класу Uuid або будь-яких інших конкретних класів, щоб створити кожний тип UUID:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
use Symfony\Component\Uid\Uuid;

// UUID 1го типу генерує UUID, використовуючи MAC-адресу вашого приладу та часову відмітку.
// Обидва отримуються автоматично, тому вам не потрібно передавати ніякі аргументи конструктора.
$uuid = Uuid::v1(); // $uuid is an instance of Symfony\Component\Uid\UuidV1

// UUID 4го типу генерує рандомний UUID, тому вам не потрібно передавати ніякі аргументи конструктора.
$uuid = Uuid::v4(); // $uuid - це екземпляр Symfony\Component\Uid\UuidV4

// UUID 3го і 5го типів генерують UUID, хешуючи заданий простір імен та імʼя. 3ій тип використовує
// MD5-хеші, а 5ий тип використовує SHA-1. Простір імен - це ще один UUID (наприклад, UUID 4го типу),
// а імʼя - довільний рядок (наприклад, назва продукту; якщо вона унікальна).
$namespace = Uuid::v4();
$name = $product->getUniqueName();

$uuid = Uuid::v3($namespace, $name); // $uuid is an instance of Symfony\Component\Uid\UuidV3
$uuid = Uuid::v5($namespace, $name); // $uuid is an instance of Symfony\Component\Uid\UuidV5

// простори імен, визначені RFC 4122 (див. https://tools.ietf.org/html/rfc4122#appendix-C)
// доступні як PHP-константи і як значення рядків
$uuid = Uuid::v3(Uuid::NAMESPACE_DNS, $name);  // те ж саме що і: Uuid::v3('dns', $name);
$uuid = Uuid::v3(Uuid::NAMESPACE_URL, $name);  // те ж саме що і: Uuid::v3('url', $name);
$uuid = Uuid::v3(Uuid::NAMESPACE_OID, $name);  // те ж саме що і: Uuid::v3('oid', $name);
$uuid = Uuid::v3(Uuid::NAMESPACE_X500, $name); // те ж саме що і: Uuid::v3('x500', $name);

// UUID 6го типу не є частиною стандарту UUID. Він лексикографічно сортуємий (як ULID) та
// містить 60-бітну часову відмітку разом з 63 додатковими унікальними бітами.
// Він визначається в http://gh.peabody.io/uuidv6/
$uuid = Uuid::v6(); // $uuid is an instance of Symfony\Component\Uid\UuidV6

// UUID версії 7 представляє впорядковане в часі поле значень, виведене з добре відомого джерела
// часової відмітки Unix Epoch: кількість секунд з 1 січня 1970 UTC, без урахування високосних секунд.
// А також покращені ентропійні характеристики у порівнянні з версіями 1 або 6.
$uuid = Uuid::v7();

// UUID версії 8 надає сумісний з RFC формат для експериментальних або специфічних для постачальників випадків використання.
// Єдина вимога - біти варіанту та версії ПОВИННІ бути встановленими як визначені у розділі 4:
// https://www.ietf.org/archive/id/draft-peabody-dispatch-new-uuid-format-04.html#variant_and_version_fields
// Унікальність UUIDv8 буде залежати від конкретних умов реалізації і НЕ ПОВИННА бути припущена.
$uuid = Uuid::v8();

6.2

Версії UUID 7 та 8 були представлені в Symfony 6.2.

Якщо ваше значення UUID вже згенероване в іншому форматі, використайте будь-який з
наступних методів, щоб створити з нього обʼєкт Uuid:

1
2
3
4
5
6
// всі наступні приклади згенерують однаковий обʼєкт Uuid
$uuid = Uuid::fromString('d9e7a184-5d5b-11ea-a62a-3499710062d0');
$uuid = Uuid::fromBinary("\xd9\xe7\xa1\x84\x5d\x5b\x11\xea\xa6\x2a\x34\x99\x71\x00\x62\xd0");
$uuid = Uuid::fromBase32('6SWYGR8QAV27NACAHMK5RG0RPG');
$uuid = Uuid::fromBase58('TuetYWNHhmuSQ3xPoVLv9M');
$uuid = Uuid::fromRfc4122('d9e7a184-5d5b-11ea-a62a-3499710062d0');

Конвертація UUID

Використайте ці методи, щоб перетворити обʼєкти UUID на різні основи:

1
2
3
4
5
6
$uuid = Uuid::fromString('d9e7a184-5d5b-11ea-a62a-3499710062d0');

$uuid->toBinary();  // string(16) "\xd9\xe7\xa1\x84\x5d\x5b\x11\xea\xa6\x2a\x34\x99\x71\x00\x62\xd0"
$uuid->toBase32();  // string(26) "6SWYGR8QAV27NACAHMK5RG0RPG"
$uuid->toBase58();  // string(22) "TuetYWNHhmuSQ3xPoVLv9M"
$uuid->toRfc4122(); // string(36) "d9e7a184-5d5b-11ea-a62a-3499710062d0"

6.2

Метод toHex() було представлено ва Symfony 6.2.

Робота з UUID

UUID-обʼєкти, створені класом Uuid можуть використовувати наступні методи (які еквівалентні методу uuid_*() PHP-розширення):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
use Symfony\Component\Uid\NilUuid;
use Symfony\Component\Uid\Uuid;

// перевірка, чи є UUID null (відмітьте, що клас називається
// NilUuid замість NullUuid, щоб слідувати стандартній нотації UUID)
$uuid = Uuid::v4();
$uuid instanceof NilUuid; // false

// перевірка типу UUID
use Symfony\Component\Uid\UuidV4;
$uuid = Uuid::v4();
$uuid instanceof UuidV4; // true

// отримання дати та часу UUID (доступно лише в деяких типах UUID)
$uuid = Uuid::v1();
$uuid->getDateTime();  // returns a \DateTimeImmutable instance

// порівняння UUID та перевірка рівності
$uuid1 = Uuid::v1();
$uuid4 = Uuid::v4();
$uuid1->equals($uuid4); // false

// цей метод повертає:
//   * int(0), якщо $uuid1 і $uuid4 рівні
//   * int > 0, якщо $uuid1 більше, ніж $uuid4
//   * int < 0, якщо $uuid1 менше, ніж $uuid4
$uuid1->compare($uuid4); // наприклад, int(4)

Зберігання UUID в базах даних

Якщо ви використовуєте Doctrine, розгляньте використання типу Doctrine uuid, який перетворює з/на обʼєкти UUID автоматично:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// src/Entity/Product.php
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass="App\Repository\ProductRepository")
 */
class Product
{
    /**
     * @ORM\Column(type="uuid")
     */
    private $someProperty;

    // ...
}

6.2

Константа UuidType::NAME була представлена в Symfony 6.2.

Також існує генератор Doctrine, щоб допомогти з автоматичним генеруванням значень UUID для основних ключів сутності:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Types\UuidType;
use Symfony\Component\Uid\Uuid;

class User implements UserInterface
{
    #[ORM\Id]
    #[ORM\Column(type: UuidType::NAME, unique: true)]
    #[ORM\GeneratedValue(strategy: 'CUSTOM')]
    #[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]
    private $id;

    public function getId(): ?Uuid
    {
        return $this->id;
    }

    // ...
}

При використанні вбудованих методів сховища Doctrine (наприклад, findOneBy()), Doctrine знає, як перетворювати ці типи UUID, щоб створити SQL-запит (наприклад, ->findOneBy(['user' => $user->getUuid()])). Однак, при використанні DQL-запитів, або створенні запиту самостійно, вам знадобиться встановити uuid як тип UUID-параметрів:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// src/Repository/ProductRepository.php

// ...
use Symfony\Bridge\Doctrine\Types\UuidType;

class ProductRepository extends ServiceEntityRepository
{
    // ...

    public function findUserProducts(User $user): array
    {
        $qb = $this->createQueryBuilder('p')
            // ...
            // додайте 'uuid' як третій аргумент, щоб повідомити Doctrine, що це UUID
            ->setParameter('user', $user->getUuid(), UuidType::NAME)

            // як варіант, ви можете перетворити його на значення, сумісне з
            // типом, визначеним Doctrine
            ->setParameter('user', $user->getUuid()->toBinary())
        ;

        // ...
    }
}

ULID

ULID (Універсально унікальні лексикографічно сортовані ідентифікатори) - це 128-бітні числа, зазвичай представлені у вигляді рядків з 26 знаків: TTTTTTTTTTRRRRRRRRRRRRRRRR (де T - це часова відмітка, а R - рандомні біти).

ULID - це альтернатива UUID, коли використання останніх не є практичним. Вони представляють 128-бітну сумісність з UUID, лексикографічно сортовані та зашифровані як рядки з 26 знаків (проти 36-знакових UUID).

Note

Якщо ви генеруєте більше одного ULID під час однієї мілісекунди у простому процесі, тоді рандомна частина збільшується на один біт, щоб надати монотонність для сортування. В такому випадку, рандомна частина не настільки випадкова, як у порівнянні з попереднім ULID.

Створення ULID

Інстанціюйте клас Ulid, щоб згенерувати рандомне значення ULID:

1
2
3
use Symfony\Component\Uid\Ulid;

$ulid = new Ulid();  // наприклад, 01AN4Z07BY79KA1307SR9X4MV3

Якщо ваше значення ULID вже згенероване в іншому форматі, використайте будь-який з наступних методів, щоб створити з нього обʼєкт Ulid:

1
2
3
4
5
6
// всі наступні приклади створять однаковий обʼєкт Ulid
$ulid = Ulid::fromString('01E439TP9XJZ9RPFH3T1PYBCR8');
$ulid = Ulid::fromBinary("\x01\x71\x06\x9d\x59\x3d\x97\xd3\x8b\x3e\x23\xd0\x6d\xe5\xb3\x08");
$ulid = Ulid::fromBase32('01E439TP9XJZ9RPFH3T1PYBCR8');
$ulid = Ulid::fromBase58('1BKocMc5BnrVcuq2ti4Eqm');
$ulid = Ulid::fromRfc4122('0171069d-593d-97d3-8b3e-23d06de5b308');

Також існує спеціальний клас NilUlid, щоб представляти значення ULID null:

1
2
3
4
use Symfony\Component\Uid\NilUlid;

$ulid = new NilUlid();
// еквівалентно $ulid = new Ulid('00000000000000000000000000');

Конвертація ULID

Використовуйте ці методи, щоб перетворити обʼєкт ULID на різні основи:

1
2
3
4
5
6
7
$ulid = Ulid::fromString('01E439TP9XJZ9RPFH3T1PYBCR8');

$ulid->toBinary();  // string(16) "\x01\x71\x06\x9d\x59\x3d\x97\xd3\x8b\x3e\x23\xd0\x6d\xe5\xb3\x08"
$ulid->toBase32();  // string(26) "01E439TP9XJZ9RPFH3T1PYBCR8"
$ulid->toBase58();  // string(22) "1BKocMc5BnrVcuq2ti4Eqm"
$ulid->toRfc4122(); // string(36) "0171069d-593d-97d3-8b3e-23d06de5b308"
$ulid->toHex();     // string(34) "0x0171069d593d97d38b3e23d06de5b308"

6.2

Метод toHex() було представлено в Symfony 6.2.

Робота з ULID

ULID-обʼєкти, створені класом Ulid, можуть використовувати наступні методи:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
use Symfony\Component\Uid\Ulid;

$ulid1 = new Ulid();
$ulid2 = new Ulid();

// перевірка, чи є задане значення валідним як ULID
$isValid = Ulid::isValid($ulidValue); // true або false

// отримання часу та дати ULID
$ulid1->getDateTime(); // повертає \DateTimeImmutable instance

// порівняння ULID та перевірка рівності
$ulid1->equals($ulid2); // false
// this method returns $ulid1 <=> $ulid2
$ulid1->compare($ulid2); // наприклад, int(-1)

Зберігання ULID в базах даних

Якщо ви використовуєте Doctrine, розгляньте використання типу Doctrine ulid, який автоматично перетворить з/на ULID-обʼєкти:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// src/Entity/Product.php
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Types\UlidType;

#[ORM\Entity(repositoryClass: ProductRepository::class)]
class Product
{
    #[ORM\Column(type: UlidType::NAME)]
    private $someProperty;

    // ...
}

6.2

Константа UlidType::NAME була представлена в Symfony 6.2.

Також існує генератор Doctrine, щоб допомогти з автоматичним генеруванням ULID-значень для головних ключів сутностей:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Types\UlidType;
use Symfony\Component\Uid\Ulid;

class Product
{
    #[ORM\Id]
    #[ORM\Column(type: UlidType::NAME, unique: true)]
    #[ORM\GeneratedValue(strategy: 'CUSTOM')]
    #[ORM\CustomIdGenerator(class: 'doctrine.ulid_generator')]
    private $id;

    public function getId(): ?Ulid
    {
        return $this->id;
    }

    // ...

}

При використанні вбудованих методів сховища Doctrine (наприклад, findOneBy()), Doctrine знає, як перретворити ці ULID-типи для створення SQL-запиту (наприклад, ->findOneBy(['user' => $user->getUlid()])). Однак, при використанні DQL-запитів, вам потрібно буде встановити ulid як тип ULID-параметрів:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// src/Repository/ProductRepository.php

// ...
class ProductRepository extends ServiceEntityRepository
{
    // ...

    public function findUserProducts(User $user): array
    {
        $qb = $this->createQueryBuilder('p')
            // ...
            // додайте 'ulid' як третій аргумент, щоб повідомити Doctrine, що це ULID
            ->setParameter('user', $user->getUlid(), 'ulid')

            // як варіант, ви можете перетворити його на значення, сумісне з типом,
            // визначеним Doctrine
            ->setParameter('user', $user->getUlid()->toBinary())
        ;

        // ...
    }
}

Генерування та дослідження UUID/ULID в консолі

Этот компонент предоставляет несколько команд для генерирования и исследования UUID/ULID в консоли. Они не включены по умолчанию, поэтому вы должны добавить следующую конфигурацию в вашем приложении перед тем, как использовать эти команды:

  • YAML
  • XML
  • PHP
1
2
3
4
5
6
# config/services.yaml
services:
    Symfony\Component\Uid\Command\GenerateUlidCommand: ~
    Symfony\Component\Uid\Command\GenerateUuidCommand: ~
    Symfony\Component\Uid\Command\InspectUlidCommand: ~
    Symfony\Component\Uid\Command\InspectUuidCommand: ~

Тепер ви можете генерувати UUID/ULID наступним чином (додайте опцію --help до команд, щоб дізнатисся все про їх опції):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# згенерувати 1 рандомно-заснований UUID
$ php bin/console uuid:generate --random-based

# згенерувати 1 UUID, заснований на часі, з конкретним вузлом
$ php bin/console uuid:generate --time-based=now --node=fb3502dc-137e-4849-8886-ac90d07f64a7

# згенерувати 2 UUID та вивессти їх у форматі base58
$ php bin/console uuid:generate --count=2 --format=base58

# згенерувати 1 ULID з поточним часом в якості часової відмітки
$ php bin/console ulid:generate

# згенерувати 1 ULID з конкретною часовою відміткою
$ php bin/console ulid:generate --time="2021-02-02 14:00:00"

# згенерувати 2 ULID та вивести їх у форматі RFC4122
$ php bin/console ulid:generate --count=2 --format=rfc4122

На додаток до створення нових UID, ви також можете дослідити їх за допомогою наступних команд, щоб побачити всю інформацію про заданий UID:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ php bin/console uuid:inspect d0a3a023-f515-4fe0-915c-575e63693998
 ------------------------- --------------------------------------
  Ярлик                     Значення
 ------------------------- --------------------------------------
  Версія                    4
  Канонічність (RFC 4122)   d0a3a023-f515-4fe0-915c-575e63693998
  База 58                   SmHvuofV4GCF7QW543rDD9
  База 32                   6GMEG27X8N9ZG92Q2QBSHPJECR
 ------------------------- --------------------------------------

$ php bin/console ulid:inspect 01F2TTCSYK1PDRH73Z41BN1C4X
 ------------------------ --------------------------------------
  Ярлик                    Значення
 ------------------------ --------------------------------------
  Канонічність (База 32)   01F2TTCSYK1PDRH73Z41BN1C4X
  База 58                  1BYGm16jS4kX3VYCysKKq6
  RFC 4122                 0178b5a6-67d3-0d9b-889c-7f205750b09d
 ------------------------ --------------------------------------
  Часова відмітка.         2021-04-09 08:01:24.947
 ------------------------ --------------------------------------