diff --git a/src/Uuid.php b/src/Uuid.php index 144a7a0..7cbfb17 100644 --- a/src/Uuid.php +++ b/src/Uuid.php @@ -14,6 +14,7 @@ declare(strict_types=1); namespace Ramsey\Uuid; +use BadMethodCallException; use DateTimeInterface; use Ramsey\Uuid\Codec\CodecInterface; use Ramsey\Uuid\Converter\NumberConverterInterface; @@ -514,6 +515,33 @@ class Uuid implements UuidInterface return self::getFactory()->fromDateTime($dateTime, $node, $clockSeq); } + /** + * Creates a UUID from the Hexadecimal object + * + * @param Hexadecimal $hex Hexadecimal object representing a hexadecimal number + * + * @return UuidInterface A UuidInterface instance created from the Hexadecimal + * object representing a hexadecimal number + * + * @psalm-pure note: changing the internal factory is an edge case not covered by purity invariants, + * but under constant factory setups, this method operates in functionally pure manners + * @psalm-suppress MixedInferredReturnType,MixedReturnStatement + */ + public static function fromHexadecimal(Hexadecimal $hex): UuidInterface + { + $factory = self::getFactory(); + + if (method_exists($factory, 'fromHexadecimal')) { + /** + * @phpstan-ignore-next-line + * @psalm-suppress UndefinedInterfaceMethod + */ + return self::getFactory()->fromHexadecimal($hex); + } + + throw new BadMethodCallException('The method fromHexadecimal() does not exist on the provided factory'); + } + /** * Creates a UUID from a 128-bit integer string * @@ -527,6 +555,7 @@ class Uuid implements UuidInterface */ public static function fromInteger(string $integer): UuidInterface { + /** @psalm-suppress ImpureMethodCall */ return self::getFactory()->fromInteger($integer); } @@ -544,6 +573,7 @@ class Uuid implements UuidInterface */ public static function isValid(string $uuid): bool { + /** @psalm-suppress ImpureMethodCall */ return self::getFactory()->getValidator()->validate($uuid); } @@ -554,7 +584,7 @@ class Uuid implements UuidInterface * @param Hexadecimal|int|string|null $node A 48-bit number representing the * hardware address; this number may be represented as an integer or a * hexadecimal string - * @param int $clockSeq A 14-bit number used to help avoid duplicates that + * @param int|null $clockSeq A 14-bit number used to help avoid duplicates that * could arise when the clock is set backwards in time or if the node ID * changes * @@ -658,7 +688,7 @@ class Uuid implements UuidInterface * * @param Hexadecimal|null $node A 48-bit number representing the hardware * address - * @param int $clockSeq A 14-bit number used to help avoid duplicates that + * @param int|null $clockSeq A 14-bit number used to help avoid duplicates that * could arise when the clock is set backwards in time or if the node ID * changes * diff --git a/src/UuidFactory.php b/src/UuidFactory.php index fae8fbb..1b06ea6 100644 --- a/src/UuidFactory.php +++ b/src/UuidFactory.php @@ -312,6 +312,14 @@ class UuidFactory implements UuidFactoryInterface return $this->uuidFromBytesAndVersion($bytes, Uuid::UUID_TYPE_TIME); } + /** + * @psalm-pure + */ + public function fromHexadecimal(Hexadecimal $hex): UuidInterface + { + return $this->codec->decode($hex->__toString()); + } + /** * @inheritDoc */ @@ -436,6 +444,7 @@ class UuidFactory implements UuidFactoryInterface */ public function uuid(string $bytes): UuidInterface { + /** @psalm-suppress ImpurePropertyFetch */ return $this->uuidBuilder->build($this->codec, $bytes); } @@ -498,6 +507,7 @@ class UuidFactory implements UuidFactoryInterface return LazyUuidFromString::fromBytes($bytes); } + /** @psalm-suppress ImpureVariable */ return $this->uuid($bytes); } } diff --git a/tests/UuidTest.php b/tests/UuidTest.php index 4c1bd5c..17b62a9 100644 --- a/tests/UuidTest.php +++ b/tests/UuidTest.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace Ramsey\Uuid\Test; +use BadMethodCallException; use Brick\Math\BigDecimal; use Brick\Math\RoundingMode; use DateTimeImmutable; @@ -73,6 +74,37 @@ class UuidTest extends TestCase ); } + public function testFromHexadecimal(): void + { + $hex = new Hexadecimal('0x1EA78DEB37CE625E8F1A025041000001'); + $uuid = Uuid::fromHexadecimal($hex); + $this->assertInstanceOf(Uuid::class, $uuid); + $this->assertEquals('1ea78deb-37ce-625e-8f1a-025041000001', $uuid->toString()); + } + + public function testFromHexadecimalShort(): void + { + $hex = new Hexadecimal('0x1EA78DEB37CE625E8F1A0250410000'); + + $this->expectException(InvalidUuidStringException::class); + $this->expectExceptionMessage('Invalid UUID string:'); + + Uuid::fromHexadecimal($hex); + } + + public function testFromHexadecimalThrowsWhenMethodDoesNotExist(): void + { + $factory = Mockery::mock(UuidFactoryInterface::class); + Uuid::setFactory($factory); + + $hex = new Hexadecimal('0x1EA78DEB37CE625E8F1A025041000001'); + + $this->expectException(BadMethodCallException::class); + $this->expectExceptionMessage('The method fromHexadecimal() does not exist on the provided factory'); + + Uuid::fromHexadecimal($hex); + } + /** * Tests that UUID and GUID's have the same textual representation but not * the same binary representation.