From d272fe74a919e1efb01a37166b8ad97b31f1f3b8 Mon Sep 17 00:00:00 2001 From: Netkas Date: Fri, 24 Feb 2023 22:12:24 -0500 Subject: [PATCH] Updated `Symfony\Uid` to version 6.2.5 --- CHANGELOG.md | 1 + .../ThirdParty/Symfony/Uid/AbstractUid.php | 8 ++ src/ncc/ThirdParty/Symfony/Uid/CHANGELOG.md | 7 ++ .../Uid/Command/GenerateUlidCommand.php | 8 +- .../Uid/Command/GenerateUuidCommand.php | 10 +- .../Uid/Command/InspectUlidCommand.php | 11 +- .../Uid/Command/InspectUuidCommand.php | 26 ++-- .../Uid/Factory/NameBasedUuidFactory.php | 8 +- .../Uid/Factory/RandomBasedUuidFactory.php | 4 +- .../Uid/Factory/TimeBasedUuidFactory.php | 9 +- .../Symfony/Uid/Factory/UlidFactory.php | 4 +- .../Symfony/Uid/Factory/UuidFactory.php | 14 +-- src/ncc/ThirdParty/Symfony/Uid/LICENSE | 2 +- src/ncc/ThirdParty/Symfony/Uid/MaxUlid.php | 20 +++ src/ncc/ThirdParty/Symfony/Uid/MaxUuid.php | 22 ++++ src/ncc/ThirdParty/Symfony/Uid/README.md | 3 + .../Symfony/Uid/TimeBasedUidInterface.php | 22 ++++ src/ncc/ThirdParty/Symfony/Uid/Ulid.php | 103 ++++++++-------- src/ncc/ThirdParty/Symfony/Uid/Uuid.php | 39 +++++- src/ncc/ThirdParty/Symfony/Uid/UuidV1.php | 12 +- src/ncc/ThirdParty/Symfony/Uid/UuidV3.php | 5 + src/ncc/ThirdParty/Symfony/Uid/UuidV4.php | 2 +- src/ncc/ThirdParty/Symfony/Uid/UuidV5.php | 5 + src/ncc/ThirdParty/Symfony/Uid/UuidV6.php | 4 +- src/ncc/ThirdParty/Symfony/Uid/UuidV7.php | 114 ++++++++++++++++++ src/ncc/ThirdParty/Symfony/Uid/UuidV8.php | 27 +++++ src/ncc/ThirdParty/Symfony/Uid/VERSION | 2 +- 27 files changed, 365 insertions(+), 127 deletions(-) create mode 100644 src/ncc/ThirdParty/Symfony/Uid/MaxUlid.php create mode 100644 src/ncc/ThirdParty/Symfony/Uid/MaxUuid.php create mode 100644 src/ncc/ThirdParty/Symfony/Uid/TimeBasedUidInterface.php create mode 100644 src/ncc/ThirdParty/Symfony/Uid/UuidV7.php create mode 100644 src/ncc/ThirdParty/Symfony/Uid/UuidV8.php diff --git a/CHANGELOG.md b/CHANGELOG.md index f4aa2ab..4e3a18d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/src/ncc/ThirdParty/Symfony/Uid/AbstractUid.php b/src/ncc/ThirdParty/Symfony/Uid/AbstractUid.php index 97611fc..00700d8 100644 --- a/src/ncc/ThirdParty/Symfony/Uid/AbstractUid.php +++ b/src/ncc/ThirdParty/Symfony/Uid/AbstractUid.php @@ -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. */ diff --git a/src/ncc/ThirdParty/Symfony/Uid/CHANGELOG.md b/src/ncc/ThirdParty/Symfony/Uid/CHANGELOG.md index 6b6605b..b821337 100644 --- a/src/ncc/ThirdParty/Symfony/Uid/CHANGELOG.md +++ b/src/ncc/ThirdParty/Symfony/Uid/CHANGELOG.md @@ -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 --- diff --git a/src/ncc/ThirdParty/Symfony/Uid/Command/GenerateUlidCommand.php b/src/ncc/ThirdParty/Symfony/Uid/Command/GenerateUlidCommand.php index 5ce7e86..b69f1d6 100644 --- a/src/ncc/ThirdParty/Symfony/Uid/Command/GenerateUlidCommand.php +++ b/src/ncc/ThirdParty/Symfony/Uid/Command/GenerateUlidCommand.php @@ -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); diff --git a/src/ncc/ThirdParty/Symfony/Uid/Command/GenerateUuidCommand.php b/src/ncc/ThirdParty/Symfony/Uid/Command/GenerateUuidCommand.php index 02a6aad..dc6ce99 100644 --- a/src/ncc/ThirdParty/Symfony/Uid/Command/GenerateUuidCommand.php +++ b/src/ncc/ThirdParty/Symfony/Uid/Command/GenerateUuidCommand.php @@ -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); diff --git a/src/ncc/ThirdParty/Symfony/Uid/Command/InspectUlidCommand.php b/src/ncc/ThirdParty/Symfony/Uid/Command/InspectUlidCommand.php index 9555e66..4a07ee5 100644 --- a/src/ncc/ThirdParty/Symfony/Uid/Command/InspectUlidCommand.php +++ b/src/ncc/ThirdParty/Symfony/Uid/Command/InspectUlidCommand.php @@ -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')], ]); diff --git a/src/ncc/ThirdParty/Symfony/Uid/Command/InspectUuidCommand.php b/src/ncc/ThirdParty/Symfony/Uid/Command/InspectUuidCommand.php index 101007b..49bc807 100644 --- a/src/ncc/ThirdParty/Symfony/Uid/Command/InspectUuidCommand.php +++ b/src/ncc/ThirdParty/Symfony/Uid/Command/InspectUuidCommand.php @@ -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')]; } diff --git a/src/ncc/ThirdParty/Symfony/Uid/Factory/NameBasedUuidFactory.php b/src/ncc/ThirdParty/Symfony/Uid/Factory/NameBasedUuidFactory.php index 783919b..2e64bab 100644 --- a/src/ncc/ThirdParty/Symfony/Uid/Factory/NameBasedUuidFactory.php +++ b/src/ncc/ThirdParty/Symfony/Uid/Factory/NameBasedUuidFactory.php @@ -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 { diff --git a/src/ncc/ThirdParty/Symfony/Uid/Factory/RandomBasedUuidFactory.php b/src/ncc/ThirdParty/Symfony/Uid/Factory/RandomBasedUuidFactory.php index 32383ae..3c42c13 100644 --- a/src/ncc/ThirdParty/Symfony/Uid/Factory/RandomBasedUuidFactory.php +++ b/src/ncc/ThirdParty/Symfony/Uid/Factory/RandomBasedUuidFactory.php @@ -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 { diff --git a/src/ncc/ThirdParty/Symfony/Uid/Factory/TimeBasedUuidFactory.php b/src/ncc/ThirdParty/Symfony/Uid/Factory/TimeBasedUuidFactory.php index 1f45a0e..7429a7f 100644 --- a/src/ncc/ThirdParty/Symfony/Uid/Factory/TimeBasedUuidFactory.php +++ b/src/ncc/ThirdParty/Symfony/Uid/Factory/TimeBasedUuidFactory.php @@ -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; diff --git a/src/ncc/ThirdParty/Symfony/Uid/Factory/UlidFactory.php b/src/ncc/ThirdParty/Symfony/Uid/Factory/UlidFactory.php index 7806329..d056bff 100644 --- a/src/ncc/ThirdParty/Symfony/Uid/Factory/UlidFactory.php +++ b/src/ncc/ThirdParty/Symfony/Uid/Factory/UlidFactory.php @@ -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 { diff --git a/src/ncc/ThirdParty/Symfony/Uid/Factory/UuidFactory.php b/src/ncc/ThirdParty/Symfony/Uid/Factory/UuidFactory.php index 973353d..79ec95c 100644 --- a/src/ncc/ThirdParty/Symfony/Uid/Factory/UuidFactory.php +++ b/src/ncc/ThirdParty/Symfony/Uid/Factory/UuidFactory.php @@ -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; diff --git a/src/ncc/ThirdParty/Symfony/Uid/LICENSE b/src/ncc/ThirdParty/Symfony/Uid/LICENSE index 406242f..0f262c2 100644 --- a/src/ncc/ThirdParty/Symfony/Uid/LICENSE +++ b/src/ncc/ThirdParty/Symfony/Uid/LICENSE @@ -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 diff --git a/src/ncc/ThirdParty/Symfony/Uid/MaxUlid.php b/src/ncc/ThirdParty/Symfony/Uid/MaxUlid.php new file mode 100644 index 0000000..8dd13d9 --- /dev/null +++ b/src/ncc/ThirdParty/Symfony/Uid/MaxUlid.php @@ -0,0 +1,20 @@ + + * + * 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; + } +} diff --git a/src/ncc/ThirdParty/Symfony/Uid/MaxUuid.php b/src/ncc/ThirdParty/Symfony/Uid/MaxUuid.php new file mode 100644 index 0000000..c3d3492 --- /dev/null +++ b/src/ncc/ThirdParty/Symfony/Uid/MaxUuid.php @@ -0,0 +1,22 @@ + + * + * 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; + } +} diff --git a/src/ncc/ThirdParty/Symfony/Uid/README.md b/src/ncc/ThirdParty/Symfony/Uid/README.md index 2ec5b76..acea6c7 100644 --- a/src/ncc/ThirdParty/Symfony/Uid/README.md +++ b/src/ncc/ThirdParty/Symfony/Uid/README.md @@ -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 --------- diff --git a/src/ncc/ThirdParty/Symfony/Uid/TimeBasedUidInterface.php b/src/ncc/ThirdParty/Symfony/Uid/TimeBasedUidInterface.php new file mode 100644 index 0000000..4dec0ac --- /dev/null +++ b/src/ncc/ThirdParty/Symfony/Uid/TimeBasedUidInterface.php @@ -0,0 +1,22 @@ + + * + * 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 + */ +interface TimeBasedUidInterface +{ + public function getDateTime(): \DateTimeImmutable; +} diff --git a/src/ncc/ThirdParty/Symfony/Uid/Ulid.php b/src/ncc/ThirdParty/Symfony/Uid/Ulid.php index cabfec3..1d87c59 100644 --- a/src/ncc/ThirdParty/Symfony/Uid/Ulid.php +++ b/src/ncc/ThirdParty/Symfony/Uid/Ulid.php @@ -18,9 +18,10 @@ namespace ncc\ThirdParty\Symfony\Uid; * * @author Nicolas Grekas */ -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'); } } diff --git a/src/ncc/ThirdParty/Symfony/Uid/Uuid.php b/src/ncc/ThirdParty/Symfony/Uid/Uuid.php index bc50219..27ed4b0 100644 --- a/src/ncc/ThirdParty/Symfony/Uid/Uuid.php +++ b/src/ncc/ThirdParty/Symfony/Uid/Uuid.php @@ -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; } diff --git a/src/ncc/ThirdParty/Symfony/Uid/UuidV1.php b/src/ncc/ThirdParty/Symfony/Uid/UuidV1.php index c293930..0709042 100644 --- a/src/ncc/ThirdParty/Symfony/Uid/UuidV1.php +++ b/src/ncc/ThirdParty/Symfony/Uid/UuidV1.php @@ -16,18 +16,18 @@ namespace ncc\ThirdParty\Symfony\Uid; * * @author Grégoire Pineau */ -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; } diff --git a/src/ncc/ThirdParty/Symfony/Uid/UuidV3.php b/src/ncc/ThirdParty/Symfony/Uid/UuidV3.php index 1edc81a..706a23f 100644 --- a/src/ncc/ThirdParty/Symfony/Uid/UuidV3.php +++ b/src/ncc/ThirdParty/Symfony/Uid/UuidV3.php @@ -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); + } } diff --git a/src/ncc/ThirdParty/Symfony/Uid/UuidV4.php b/src/ncc/ThirdParty/Symfony/Uid/UuidV4.php index c82d8f5..6cf8097 100644 --- a/src/ncc/ThirdParty/Symfony/Uid/UuidV4.php +++ b/src/ncc/ThirdParty/Symfony/Uid/UuidV4.php @@ -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); } } } diff --git a/src/ncc/ThirdParty/Symfony/Uid/UuidV5.php b/src/ncc/ThirdParty/Symfony/Uid/UuidV5.php index 473740d..ac2d267 100644 --- a/src/ncc/ThirdParty/Symfony/Uid/UuidV5.php +++ b/src/ncc/ThirdParty/Symfony/Uid/UuidV5.php @@ -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); + } } diff --git a/src/ncc/ThirdParty/Symfony/Uid/UuidV6.php b/src/ncc/ThirdParty/Symfony/Uid/UuidV6.php index f267565..ae43bb4 100644 --- a/src/ncc/ThirdParty/Symfony/Uid/UuidV6.php +++ b/src/ncc/ThirdParty/Symfony/Uid/UuidV6.php @@ -18,7 +18,7 @@ namespace ncc\ThirdParty\Symfony\Uid; * * @author Nicolas Grekas */ -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); } } diff --git a/src/ncc/ThirdParty/Symfony/Uid/UuidV7.php b/src/ncc/ThirdParty/Symfony/Uid/UuidV7.php new file mode 100644 index 0000000..236fae4 --- /dev/null +++ b/src/ncc/ThirdParty/Symfony/Uid/UuidV7.php @@ -0,0 +1,114 @@ + + * + * 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 + */ +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); + } +} diff --git a/src/ncc/ThirdParty/Symfony/Uid/UuidV8.php b/src/ncc/ThirdParty/Symfony/Uid/UuidV8.php new file mode 100644 index 0000000..f492f1f --- /dev/null +++ b/src/ncc/ThirdParty/Symfony/Uid/UuidV8.php @@ -0,0 +1,27 @@ + + * + * 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 + */ +class UuidV8 extends Uuid +{ + protected const TYPE = 8; + + public function __construct(string $uuid) + { + parent::__construct($uuid, true); + } +} diff --git a/src/ncc/ThirdParty/Symfony/Uid/VERSION b/src/ncc/ThirdParty/Symfony/Uid/VERSION index d7ff925..03825cd 100644 --- a/src/ncc/ThirdParty/Symfony/Uid/VERSION +++ b/src/ncc/ThirdParty/Symfony/Uid/VERSION @@ -1 +1 @@ -6.1.3 \ No newline at end of file +6.2.5 \ No newline at end of file