Updated Symfony\Uid to version 6.2.5

This commit is contained in:
Netkas 2023-02-24 22:12:24 -05:00
parent 0f26bdc960
commit d272fe74a9
27 changed files with 365 additions and 127 deletions

View file

@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Updated `Symfony\polyfill-mbstring` to version 1.27.0
- Updated `Symfony\polyfill-uuid` to version 1.27.0
- Updated `Symfony\Process` to version 6.2.5
- Updated `Symfony\Uid` to version 6.2.5
## [1.0.1] - 2023-02-07

View file

@ -127,6 +127,14 @@ abstract class AbstractUid implements \JsonSerializable
return substr_replace($uuid, '-', 23, 0);
}
/**
* Returns the identifier as a prefixed hexadecimal case insensitive string.
*/
public function toHex(): string
{
return '0x'.bin2hex($this->toBinary());
}
/**
* Returns whether the argument is an AbstractUid and contains the same value as the current instance.
*/

View file

@ -1,6 +1,13 @@
CHANGELOG
=========
6.2
---
* Add `UuidV7` and `UuidV8`
* Add `TimeBasedUidInterface` to describe UIDs that embed a timestamp
* Add `MaxUuid` and `MaxUlid`
5.4
---

View file

@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
namespace ncc\ThirdParty\Symfony\uid\Command;
namespace ncc\ThirdParty\Symfony\Uid\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
@ -40,9 +40,6 @@ class GenerateUlidCommand extends Command
parent::__construct();
}
/**
* {@inheritdoc}
*/
protected function configure(): void
{
$this
@ -72,9 +69,6 @@ EOF
;
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output);

View file

@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
namespace ncc\ThirdParty\Symfony\uid\Command;
namespace ncc\ThirdParty\Symfony\Uid\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
@ -21,7 +21,7 @@ use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use ncc\ThirdParty\Symfony\Uid\Factory\UuidFactory;
use ncc\ThirdParty\Symfony\uid\Uuid;
use ncc\ThirdParty\Symfony\Uid\Uuid;
#[AsCommand(name: 'uuid:generate', description: 'Generate a UUID')]
class GenerateUuidCommand extends Command
@ -35,9 +35,6 @@ class GenerateUuidCommand extends Command
parent::__construct();
}
/**
* {@inheritdoc}
*/
protected function configure(): void
{
$this
@ -87,9 +84,6 @@ EOF
;
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output);

View file

@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
namespace ncc\ThirdParty\Symfony\uid\Command;
namespace ncc\ThirdParty\Symfony\Uid\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
@ -19,14 +19,11 @@ use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use ncc\ThirdParty\Symfony\uid\Ulid;
use ncc\ThirdParty\Symfony\Uid\Ulid;
#[AsCommand(name: 'ulid:inspect', description: 'Inspect a ULID')]
class InspectUlidCommand extends Command
{
/**
* {@inheritdoc}
*/
protected function configure(): void
{
$this
@ -44,9 +41,6 @@ EOF
;
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output);
@ -63,6 +57,7 @@ EOF
['toBase32 (canonical)', (string) $ulid],
['toBase58', $ulid->toBase58()],
['toRfc4122', $ulid->toRfc4122()],
['toHex', $ulid->toHex()],
new TableSeparator(),
['Time', $ulid->getDateTime()->format('Y-m-d H:i:s.v \U\T\C')],
]);

View file

@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
namespace ncc\ThirdParty\Symfony\uid\Command;
namespace ncc\ThirdParty\Symfony\Uid\Command;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
@ -19,16 +19,14 @@ use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use ncc\ThirdParty\Symfony\uid\Uuid;
use ncc\ThirdParty\Symfony\uid\UuidV1;
use ncc\ThirdParty\Symfony\uid\UuidV6;
use ncc\ThirdParty\Symfony\Uid\MaxUuid;
use ncc\ThirdParty\Symfony\Uid\NilUuid;
use ncc\ThirdParty\Symfony\Uid\TimeBasedUidInterface;
use ncc\ThirdParty\Symfony\Uid\Uuid;
#[AsCommand(name: 'uuid:inspect', description: 'Inspect a UUID')]
class InspectUuidCommand extends Command
{
/**
* {@inheritdoc}
*/
protected function configure(): void
{
$this
@ -46,9 +44,6 @@ EOF
;
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output): int
{
$io = new SymfonyStyle($input, $output instanceof ConsoleOutputInterface ? $output->getErrorOutput() : $output);
@ -62,10 +57,12 @@ EOF
return 1;
}
if (-1 === $version = uuid_type($uuid)) {
if (new NilUuid() == $uuid) {
$version = 'nil';
} elseif (0 === $version || 2 === $version || 6 < $version) {
$version = 'unknown';
} elseif (new MaxUuid() == $uuid) {
$version = 'max';
} else {
$version = uuid_type($uuid);
}
$rows = [
@ -73,9 +70,10 @@ EOF
['toRfc4122 (canonical)', (string) $uuid],
['toBase58', $uuid->toBase58()],
['toBase32', $uuid->toBase32()],
['toHex', $uuid->toHex()],
];
if ($uuid instanceof UuidV1 || $uuid instanceof UuidV6) {
if ($uuid instanceof TimeBasedUidInterface) {
$rows[] = new TableSeparator();
$rows[] = ['Time', $uuid->getDateTime()->format('Y-m-d H:i:s.u \U\T\C')];
}

View file

@ -9,11 +9,11 @@
* file that was distributed with this source code.
*/
namespace ncc\ThirdParty\Symfony\uid\Factory;
namespace ncc\ThirdParty\Symfony\Uid\Factory;
use ncc\ThirdParty\Symfony\uid\Uuid;
use ncc\ThirdParty\Symfony\uid\UuidV3;
use ncc\ThirdParty\Symfony\uid\UuidV5;
use ncc\ThirdParty\Symfony\Uid\Uuid;
use ncc\ThirdParty\Symfony\Uid\UuidV3;
use ncc\ThirdParty\Symfony\Uid\UuidV5;
class NameBasedUuidFactory
{

View file

@ -9,9 +9,9 @@
* file that was distributed with this source code.
*/
namespace ncc\ThirdParty\Symfony\uid\Factory;
namespace ncc\ThirdParty\Symfony\Uid\Factory;
use ncc\ThirdParty\Symfony\uid\UuidV4;
use ncc\ThirdParty\Symfony\Uid\UuidV4;
class RandomBasedUuidFactory
{

View file

@ -9,11 +9,10 @@
* file that was distributed with this source code.
*/
namespace ncc\ThirdParty\Symfony\uid\Factory;
namespace ncc\ThirdParty\Symfony\Uid\Factory;
use ncc\ThirdParty\Symfony\uid\Uuid;
use ncc\ThirdParty\Symfony\uid\UuidV1;
use ncc\ThirdParty\Symfony\uid\UuidV6;
use ncc\ThirdParty\Symfony\Uid\TimeBasedUidInterface;
use ncc\ThirdParty\Symfony\Uid\Uuid;
class TimeBasedUuidFactory
{
@ -26,7 +25,7 @@ class TimeBasedUuidFactory
$this->node = $node;
}
public function create(\DateTimeInterface $time = null): UuidV6|UuidV1
public function create(\DateTimeInterface $time = null): Uuid&TimeBasedUidInterface
{
$class = $this->class;

View file

@ -9,9 +9,9 @@
* file that was distributed with this source code.
*/
namespace ncc\ThirdParty\Symfony\uid\Factory;
namespace ncc\ThirdParty\Symfony\Uid\Factory;
use ncc\ThirdParty\Symfony\uid\Ulid;
use ncc\ThirdParty\Symfony\Uid\Ulid;
class UlidFactory
{

View file

@ -9,13 +9,13 @@
* file that was distributed with this source code.
*/
namespace ncc\ThirdParty\Symfony\uid\Factory;
namespace ncc\ThirdParty\Symfony\Uid\Factory;
use ncc\ThirdParty\Symfony\uid\Uuid;
use ncc\ThirdParty\Symfony\uid\UuidV1;
use ncc\ThirdParty\Symfony\uid\UuidV4;
use ncc\ThirdParty\Symfony\uid\UuidV5;
use ncc\ThirdParty\Symfony\uid\UuidV6;
use ncc\ThirdParty\Symfony\Uid\Uuid;
use ncc\ThirdParty\Symfony\Uid\UuidV1;
use ncc\ThirdParty\Symfony\Uid\UuidV4;
use ncc\ThirdParty\Symfony\Uid\UuidV5;
use ncc\ThirdParty\Symfony\Uid\UuidV6;
class UuidFactory
{
@ -44,7 +44,7 @@ class UuidFactory
$this->nameBasedNamespace = $nameBasedNamespace;
}
public function create(): UuidV6|UuidV4|UuidV1
public function create(): Uuid
{
$class = $this->defaultClass;

View file

@ -1,4 +1,4 @@
Copyright (c) 2020-2022 Fabien Potencier
Copyright (c) 2020-2023 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View file

@ -0,0 +1,20 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ncc\ThirdParty\Symfony\Uid;
class MaxUlid extends Ulid
{
public function __construct()
{
$this->uid = parent::MAX;
}
}

View file

@ -0,0 +1,22 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ncc\ThirdParty\Symfony\Uid;
class MaxUuid extends Uuid
{
protected const TYPE = -1;
public function __construct()
{
$this->uid = parent::MAX;
}
}

View file

@ -3,6 +3,9 @@ Uid Component
The UID component provides an object-oriented API to generate and represent UIDs.
It provides implementations that work on 32-bit and 64-bit CPUs
for ULIDs and for UUIDs version 1 and versions 3 to 8.
Resources
---------

View file

@ -0,0 +1,22 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ncc\ThirdParty\Symfony\Uid;
/**
* Interface to describe UIDs that contain a DateTimeImmutable as part of their behaviour.
*
* @author Barney Hanlon <barney.hanlon@cushon.co.uk>
*/
interface TimeBasedUidInterface
{
public function getDateTime(): \DateTimeImmutable;
}

View file

@ -18,9 +18,10 @@ namespace ncc\ThirdParty\Symfony\Uid;
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class Ulid extends AbstractUid
class Ulid extends AbstractUid implements TimeBasedUidInterface
{
protected const NIL = '00000000000000000000000000';
protected const MAX = '7ZZZZZZZZZZZZZZZZZZZZZZZZZ';
private static string $time = '';
private static array $rand = [];
@ -29,21 +30,17 @@ class Ulid extends AbstractUid
{
if (null === $ulid) {
$this->uid = static::generate();
return;
}
if (self::NIL === $ulid) {
} elseif (self::NIL === $ulid) {
$this->uid = $ulid;
} elseif (self::MAX === strtr($ulid, 'z', 'Z')) {
$this->uid = $ulid;
} else {
if (!self::isValid($ulid)) {
throw new \InvalidArgumentException(sprintf('Invalid ULID: "%s".', $ulid));
}
return;
$this->uid = strtoupper($ulid);
}
if (!self::isValid($ulid)) {
throw new \InvalidArgumentException(sprintf('Invalid ULID: "%s".', $ulid));
}
$this->uid = strtoupper($ulid);
}
public static function isValid(string $ulid): bool
@ -59,23 +56,20 @@ class Ulid extends AbstractUid
return $ulid[0] <= '7';
}
/**
* {@inheritdoc}
*/
public static function fromString(string $ulid): static
{
if (36 === \strlen($ulid) && Uuid::isValid($ulid)) {
$ulid = (new Uuid($ulid))->toBinary();
if (36 === \strlen($ulid) && preg_match('{^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$}Di', $ulid)) {
$ulid = uuid_parse($ulid);
} elseif (22 === \strlen($ulid) && 22 === strspn($ulid, BinaryUtil::BASE58[''])) {
$ulid = str_pad(BinaryUtil::fromBase($ulid, BinaryUtil::BASE58), 16, "\0", \STR_PAD_LEFT);
}
if (16 !== \strlen($ulid)) {
if (self::NIL === $ulid) {
return new NilUlid();
}
return new static($ulid);
return match (strtr($ulid, 'z', 'Z')) {
self::NIL => new NilUlid(),
self::MAX => new MaxUlid(),
default => new static($ulid),
};
}
$ulid = bin2hex($ulid);
@ -93,8 +87,12 @@ class Ulid extends AbstractUid
return new NilUlid();
}
if (self::MAX === $ulid = strtr($ulid, 'abcdefghijklmnopqrstuv', 'ABCDEFGHJKMNPQRSTVWXYZ')) {
return new MaxUlid();
}
$u = new static(self::NIL);
$u->uid = strtr($ulid, 'abcdefghijklmnopqrstuv', 'ABCDEFGHJKMNPQRSTVWXYZ');
$u->uid = $ulid;
return $u;
}
@ -137,7 +135,7 @@ class Ulid extends AbstractUid
}
if (4 > \strlen($time)) {
$time = str_pad($time, 4, '0', \STR_PAD_LEFT);
$time = '000'.$time;
}
return \DateTimeImmutable::createFromFormat('U.u', substr_replace($time, '.', -3, 0));
@ -145,47 +143,40 @@ class Ulid extends AbstractUid
public static function generate(\DateTimeInterface $time = null): string
{
if (null === $time) {
return self::doGenerate();
}
if (0 > $time = substr($time->format('Uu'), 0, -3)) {
if (null === $mtime = $time) {
$time = microtime(false);
$time = substr($time, 11).substr($time, 2, 3);
} elseif (0 > $time = $time->format('Uv')) {
throw new \InvalidArgumentException('The timestamp must be positive.');
}
return self::doGenerate($time);
}
private static function doGenerate(string $mtime = null): string
{
if (null === $time = $mtime) {
$time = microtime(false);
$time = substr($time, 11).substr($time, 2, 3);
}
if ($time !== self::$time) {
$r = unpack('nr1/nr2/nr3/nr4/nr', random_bytes(10));
$r['r1'] |= ($r['r'] <<= 4) & 0xF0000;
$r['r2'] |= ($r['r'] <<= 4) & 0xF0000;
$r['r3'] |= ($r['r'] <<= 4) & 0xF0000;
$r['r4'] |= ($r['r'] <<= 4) & 0xF0000;
unset($r['r']);
self::$rand = array_values($r);
if ($time > self::$time || (null !== $mtime && $time !== self::$time)) {
randomize:
$r = unpack('n*', random_bytes(10));
$r[1] |= ($r[5] <<= 4) & 0xF0000;
$r[2] |= ($r[5] <<= 4) & 0xF0000;
$r[3] |= ($r[5] <<= 4) & 0xF0000;
$r[4] |= ($r[5] <<= 4) & 0xF0000;
unset($r[5]);
self::$rand = $r;
self::$time = $time;
} elseif ([0xFFFFF, 0xFFFFF, 0xFFFFF, 0xFFFFF] === self::$rand) {
if (null === $mtime) {
usleep(100);
} elseif ([1 => 0xFFFFF, 0xFFFFF, 0xFFFFF, 0xFFFFF] === self::$rand) {
if (\PHP_INT_SIZE >= 8 || 10 > \strlen($time = self::$time)) {
$time = (string) (1 + $time);
} elseif ('999999999' === $mtime = substr($time, -9)) {
$time = (1 + substr($time, 0, -9)).'000000000';
} else {
self::$rand = [0, 0, 0, 0];
$time = substr_replace($time, str_pad(++$mtime, 9, '0', \STR_PAD_LEFT), -9);
}
return self::doGenerate($mtime);
goto randomize;
} else {
for ($i = 3; $i >= 0 && 0xFFFFF === self::$rand[$i]; --$i) {
for ($i = 4; $i > 0 && 0xFFFFF === self::$rand[$i]; --$i) {
self::$rand[$i] = 0;
}
++self::$rand[$i];
$time = self::$time;
}
if (\PHP_INT_SIZE >= 8) {
@ -201,10 +192,10 @@ class Ulid extends AbstractUid
return strtr(sprintf('%010s%04s%04s%04s%04s',
$time,
base_convert(self::$rand[0], 10, 32),
base_convert(self::$rand[1], 10, 32),
base_convert(self::$rand[2], 10, 32),
base_convert(self::$rand[3], 10, 32)
base_convert(self::$rand[3], 10, 32),
base_convert(self::$rand[4], 10, 32)
), 'abcdefghijklmnopqrstuv', 'ABCDEFGHJKMNPQRSTVWXYZ');
}
}

View file

@ -25,8 +25,9 @@ class Uuid extends AbstractUid
protected const TYPE = 0;
protected const NIL = '00000000-0000-0000-0000-000000000000';
protected const MAX = 'ffffffff-ffff-ffff-ffff-ffffffffffff';
public function __construct(string $uuid)
public function __construct(string $uuid, bool $checkVariant = false)
{
$type = preg_match('{^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$}Di', $uuid) ? (int) $uuid[14] : false;
@ -35,6 +36,10 @@ class Uuid extends AbstractUid
}
$this->uid = strtolower($uuid);
if ($checkVariant && !\in_array($this->uid[19], ['8', '9', 'a', 'b'], true)) {
throw new \InvalidArgumentException(sprintf('Invalid UUID%s: "%s".', static::TYPE ? 'v'.static::TYPE : '', $uuid));
}
}
public static function fromString(string $uuid): static
@ -51,7 +56,7 @@ class Uuid extends AbstractUid
$uuid = substr_replace($uuid, '-', 18, 0);
$uuid = substr_replace($uuid, '-', 23, 0);
} elseif (26 === \strlen($uuid) && Ulid::isValid($uuid)) {
$ulid = new Ulid('00000000000000000000000000');
$ulid = new NilUlid();
$ulid->uid = strtoupper($uuid);
$uuid = $ulid->toRfc4122();
}
@ -64,12 +69,22 @@ class Uuid extends AbstractUid
return new NilUuid();
}
if (self::MAX === $uuid = strtr($uuid, 'F', 'f')) {
return new MaxUuid();
}
if (!\in_array($uuid[19], ['8', '9', 'a', 'b', 'A', 'B'], true)) {
return new self($uuid);
}
return match ((int) $uuid[14]) {
UuidV1::TYPE => new UuidV1($uuid),
UuidV3::TYPE => new UuidV3($uuid),
UuidV4::TYPE => new UuidV4($uuid),
UuidV5::TYPE => new UuidV5($uuid),
UuidV6::TYPE => new UuidV6($uuid),
UuidV7::TYPE => new UuidV7($uuid),
UuidV8::TYPE => new UuidV8($uuid),
default => new self($uuid),
};
}
@ -105,9 +120,27 @@ class Uuid extends AbstractUid
return new UuidV6();
}
final public static function v7(): UuidV7
{
return new UuidV7();
}
final public static function v8(string $uuid): UuidV8
{
return new UuidV8($uuid);
}
public static function isValid(string $uuid): bool
{
if (!preg_match('{^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$}Di', $uuid)) {
if (self::NIL === $uuid && \in_array(static::class, [__CLASS__, NilUuid::class], true)) {
return true;
}
if (self::MAX === strtr($uuid, 'F', 'f') && \in_array(static::class, [__CLASS__, MaxUuid::class], true)) {
return true;
}
if (!preg_match('{^[0-9a-f]{8}(?:-[0-9a-f]{4}){2}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$}Di', $uuid)) {
return false;
}

View file

@ -16,18 +16,18 @@ namespace ncc\ThirdParty\Symfony\Uid;
*
* @author Grégoire Pineau <lyrixx@lyrixx.info>
*/
class UuidV1 extends Uuid
class UuidV1 extends Uuid implements TimeBasedUidInterface
{
protected const TYPE = 1;
private static ?string $clockSeq = null;
private static string $clockSeq;
public function __construct(string $uuid = null)
{
if (null === $uuid) {
$this->uid = uuid_create(static::TYPE);
} else {
parent::__construct($uuid);
parent::__construct($uuid, true);
}
}
@ -49,13 +49,13 @@ class UuidV1 extends Uuid
if ($node) {
// use clock_seq from the node
$seq = substr($node->uid, 19, 4);
} else {
} elseif (!$seq = self::$clockSeq ?? '') {
// generate a static random clock_seq to prevent any collisions with the real one
$seq = substr($uuid, 19, 4);
while (null === self::$clockSeq || $seq === self::$clockSeq) {
do {
self::$clockSeq = sprintf('%04x', random_int(0, 0x3FFF) | 0x8000);
}
} while ($seq === self::$clockSeq);
$seq = self::$clockSeq;
}

View file

@ -21,4 +21,9 @@ namespace ncc\ThirdParty\Symfony\Uid;
class UuidV3 extends Uuid
{
protected const TYPE = 3;
public function __construct(string $uuid)
{
parent::__construct($uuid, true);
}
}

View file

@ -30,7 +30,7 @@ class UuidV4 extends Uuid
$this->uid = substr($uuid, 0, 8).'-'.substr($uuid, 8, 4).'-'.substr($uuid, 12, 4).'-'.substr($uuid, 16, 4).'-'.substr($uuid, 20, 12);
} else {
parent::__construct($uuid);
parent::__construct($uuid, true);
}
}
}

View file

@ -21,4 +21,9 @@ namespace ncc\ThirdParty\Symfony\Uid;
class UuidV5 extends Uuid
{
protected const TYPE = 5;
public function __construct(string $uuid)
{
parent::__construct($uuid, true);
}
}

View file

@ -18,7 +18,7 @@ namespace ncc\ThirdParty\Symfony\Uid;
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class UuidV6 extends Uuid
class UuidV6 extends Uuid implements TimeBasedUidInterface
{
protected const TYPE = 6;
@ -29,7 +29,7 @@ class UuidV6 extends Uuid
if (null === $uuid) {
$this->uid = static::generate();
} else {
parent::__construct($uuid);
parent::__construct($uuid, true);
}
}

View file

@ -0,0 +1,114 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ncc\ThirdParty\Symfony\Uid;
/**
* A v7 UUID is lexicographically sortable and contains a 48-bit timestamp and 74 extra unique bits.
*
* Within the same millisecond, monotonicity is ensured by incrementing the random part by a random increment.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class UuidV7 extends Uuid implements TimeBasedUidInterface
{
protected const TYPE = 7;
private static string $time = '';
private static array $rand = [];
private static string $seed;
private static array $seedParts;
private static int $seedIndex = 0;
public function __construct(string $uuid = null)
{
if (null === $uuid) {
$this->uid = static::generate();
} else {
parent::__construct($uuid, true);
}
}
public function getDateTime(): \DateTimeImmutable
{
$time = substr($this->uid, 0, 8).substr($this->uid, 9, 4);
$time = \PHP_INT_SIZE >= 8 ? (string) hexdec($time) : BinaryUtil::toBase(hex2bin($time), BinaryUtil::BASE10);
if (4 > \strlen($time)) {
$time = '000'.$time;
}
return \DateTimeImmutable::createFromFormat('U.v', substr_replace($time, '.', -3, 0));
}
public static function generate(\DateTimeInterface $time = null): string
{
if (null === $mtime = $time) {
$time = microtime(false);
$time = substr($time, 11).substr($time, 2, 3);
} elseif (0 > $time = $time->format('Uv')) {
throw new \InvalidArgumentException('The timestamp must be positive.');
}
if ($time > self::$time || (null !== $mtime && $time !== self::$time)) {
randomize:
self::$rand = unpack('n*', isset(self::$seed) ? random_bytes(10) : self::$seed = random_bytes(16));
self::$rand[1] &= 0x03FF;
self::$time = $time;
} else {
if (!self::$seedIndex) {
$s = unpack('l*', self::$seed = hash('sha512', self::$seed, true));
$s[] = ($s[1] >> 8 & 0xFF0000) | ($s[2] >> 16 & 0xFF00) | ($s[3] >> 24 & 0xFF);
$s[] = ($s[4] >> 8 & 0xFF0000) | ($s[5] >> 16 & 0xFF00) | ($s[6] >> 24 & 0xFF);
$s[] = ($s[7] >> 8 & 0xFF0000) | ($s[8] >> 16 & 0xFF00) | ($s[9] >> 24 & 0xFF);
$s[] = ($s[10] >> 8 & 0xFF0000) | ($s[11] >> 16 & 0xFF00) | ($s[12] >> 24 & 0xFF);
$s[] = ($s[13] >> 8 & 0xFF0000) | ($s[14] >> 16 & 0xFF00) | ($s[15] >> 24 & 0xFF);
self::$seedParts = $s;
self::$seedIndex = 21;
}
self::$rand[5] = 0xFFFF & $carry = self::$rand[5] + (self::$seedParts[self::$seedIndex--] & 0xFFFFFF);
self::$rand[4] = 0xFFFF & $carry = self::$rand[4] + ($carry >> 16);
self::$rand[3] = 0xFFFF & $carry = self::$rand[3] + ($carry >> 16);
self::$rand[2] = 0xFFFF & $carry = self::$rand[2] + ($carry >> 16);
self::$rand[1] += $carry >> 16;
if (0xFC00 & self::$rand[1]) {
if (\PHP_INT_SIZE >= 8 || 10 > \strlen($time = self::$time)) {
$time = (string) (1 + $time);
} elseif ('999999999' === $mtime = substr($time, -9)) {
$time = (1 + substr($time, 0, -9)).'000000000';
} else {
$time = substr_replace($time, str_pad(++$mtime, 9, '0', \STR_PAD_LEFT), -9);
}
goto randomize;
}
$time = self::$time;
}
if (\PHP_INT_SIZE >= 8) {
$time = dechex($time);
} else {
$time = bin2hex(BinaryUtil::fromBase($time, BinaryUtil::BASE10));
}
return substr_replace(sprintf('%012s-%04x-%04x-%04x%04x%04x',
$time,
0x7000 | (self::$rand[1] << 2) | (self::$rand[2] >> 14),
0x8000 | (self::$rand[2] & 0x3FFF),
self::$rand[3],
self::$rand[4],
self::$rand[5],
), '-', 8, 0);
}
}

View file

@ -0,0 +1,27 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace ncc\ThirdParty\Symfony\Uid;
/**
* A v8 UUID has no explicit requirements except embedding its version + variant bits.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class UuidV8 extends Uuid
{
protected const TYPE = 8;
public function __construct(string $uuid)
{
parent::__construct($uuid, true);
}
}

View file

@ -1 +1 @@
6.1.3
6.2.5