From b28029fbc7850228d11871708d5117f6980fac04 Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Fri, 17 Oct 2014 16:52:56 +0200 Subject: [PATCH 01/30] Add support for MS GUIDs --- src/Uuid.php | 52 +++++++++++++++++++++++++++++++++------------- tests/UuidTest.php | 37 +++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 15 deletions(-) diff --git a/src/Uuid.php b/src/Uuid.php index 01976e9..821b105 100644 --- a/src/Uuid.php +++ b/src/Uuid.php @@ -149,6 +149,12 @@ class Uuid implements \JsonSerializable 'node' => '000000000000', ); + /** + * Whether the first three fields are stored in little endian format (GUID's) + * @var bool + */ + protected $isLittleEndian; + /** * Creates a universally unique identifier (UUID) from an array of fields. * @@ -156,11 +162,13 @@ class Uuid implements \JsonSerializable * UUIDs. * * @param array $fields + * @param bool $littleEndian Whether the first three fields are in little-endian format. * @link Rhumsaa.Uuid.Uuid.html#method_getFields */ - protected function __construct(array $fields) + protected function __construct(array $fields, $littleEndian = false) { $this->fields = $fields; + $this->isLittleEndian = (bool)$littleEndian; } /** @@ -445,7 +453,7 @@ class Uuid implements \JsonSerializable */ public function getHex() { - return str_replace('-', '', $this->toString()); + return str_replace('-', '', $this->toString(true)); } /** @@ -834,11 +842,20 @@ class Uuid implements \JsonSerializable * * @return string */ - public function toString() + public function toString($forceBigEndian = false) { + $fields = array_values($this->fields); + + if ($this->isLittleEndian && $forceBigEndian == false) { + // Swap byte-order on the first three fields + $fields[0] = unpack('H*', pack('V', hexdec($fields[0])))[1]; + $fields[1] = unpack('H*', pack('v', hexdec($fields[1])))[1]; + $fields[2] = unpack('H*', pack('v', hexdec($fields[2])))[1]; + } + return vsprintf( '%08s-%04s-%04s-%02s%02s-%012s', - $this->fields + $fields ); } @@ -849,22 +866,18 @@ class Uuid implements \JsonSerializable * @return Uuid * @throws InvalidArgumentException If the $bytes string does not contain 16 characters */ - public static function fromBytes($bytes) + public static function fromBytes($bytes, $littleEndian = false) { if (strlen($bytes) !== 16) { throw new InvalidArgumentException('$bytes string should contain 16 characters.'); } - $uuid = ''; - foreach (range(0, 15) as $step) { - $uuid .= sprintf('%02x', ord($bytes[$step])); + $hexUuid = unpack('H*', $bytes); - if (in_array($step, array(3, 5, 7, 9))) { - $uuid .= '-'; - } - } + $uuid = Uuid::fromString($hexUuid[1], false); + $uuid->isLittleEndian = $littleEndian; - return Uuid::fromString($uuid); + return $uuid; } /** @@ -872,10 +885,11 @@ class Uuid implements \JsonSerializable * in the toString() method. * * @param string $name A string that specifies a UUID + * @param bool $littleEndian A boolean specifying whether the time_low, time_mid, time_hi_and_version are encoded in little-endian format. * @return Uuid * @throws InvalidArgumentException If the $name isn't a valid UUID */ - public static function fromString($name) + public static function fromString($name, $littleEndian = false) { $nameParsed = str_replace(array('urn:', 'uuid:', '{', '}', '-'), '', $name); @@ -889,6 +903,14 @@ class Uuid implements \JsonSerializable substr($nameParsed, 16, 4), substr($nameParsed, 20), ); + + // Swap byte-order on the first three fields + if ($littleEndian) { + $components[0] = unpack('H*', pack('V', hexdec($components[0])))[1]; + $components[1] = unpack('H*', pack('v', hexdec($components[1])))[1]; + $components[2] = unpack('H*', pack('v', hexdec($components[2])))[1]; + } + $nameParsed = implode('-', $components); if (!self::isValid($nameParsed)) { @@ -904,7 +926,7 @@ class Uuid implements \JsonSerializable 'node' => sprintf('%012s', $components[4]), ); - return new self($fields); + return new self($fields, $littleEndian); } /** diff --git a/tests/UuidTest.php b/tests/UuidTest.php index 8be8b26..fe56804 100644 --- a/tests/UuidTest.php +++ b/tests/UuidTest.php @@ -23,6 +23,21 @@ class UuidTest extends TestCase $this->assertEquals('ff6f8cb0-c57d-11e1-9b21-0800200c9a66', $uuid->toString()); } + /** + * @covers Rhumsaa\Uuid\Uuid::fromString + */ + public function testFromLittleEndianString() + { + $uuid = Uuid::fromString('b08c6fff-7dc5-e111-9b21-0800200c9a66'); + $guid = Uuid::fromString('b08c6fff-7dc5-e111-9b21-0800200c9a66', true); + + $this->assertInstanceOf('\Rhumsaa\Uuid\Uuid', $guid); + // UUID's and GUID's share the same textual representation + $this->assertEquals($uuid->toString(), $guid->toString()); + // But not the same binary representation + $this->assertNotEquals(bin2hex($uuid->getBytes()), bin2hex($guid->getBytes())); + } + /** * @covers Rhumsaa\Uuid\Uuid::fromString */ @@ -1435,6 +1450,28 @@ class UuidTest extends TestCase $this->assertTrue($uuid->equals($fromBytesUuid)); } + public function testFromLittleEndianBytes() + { + // Check that parsing BE bytes as LE reverses fields + $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); + $bytes = $uuid->getBytes(); + + $guid = Uuid::fromBytes($bytes, true); + + // First three fields should be reversed + $this->assertEquals('b08c6fff-7dc5-e111-9b21-0800200c9a66', $guid->toString()); + // Except if forcing big endian + $this->assertEquals($uuid->toString(), $guid->toString(true)); + + // Check that parsing LE bytes as LE preserves fields + $guid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66', true); + $bytes = $guid->getBytes(); + + $parsedGuid = Uuid::fromBytes($bytes, true); + + $this->assertEquals($guid->toString(), $parsedGuid->toString()); + } + /** * @covers Rhumsaa\Uuid\Uuid::fromBytes * @expectedException InvalidArgumentException From 0650b46d0eb61b95a3403e5f8336f1057d5cb531 Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Fri, 17 Oct 2014 17:00:21 +0200 Subject: [PATCH 02/30] Remove non PHP 5.3 syntax --- src/Uuid.php | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/Uuid.php b/src/Uuid.php index 821b105..a5bed74 100644 --- a/src/Uuid.php +++ b/src/Uuid.php @@ -848,9 +848,12 @@ class Uuid implements \JsonSerializable if ($this->isLittleEndian && $forceBigEndian == false) { // Swap byte-order on the first three fields - $fields[0] = unpack('H*', pack('V', hexdec($fields[0])))[1]; - $fields[1] = unpack('H*', pack('v', hexdec($fields[1])))[1]; - $fields[2] = unpack('H*', pack('v', hexdec($fields[2])))[1]; + $hex = unpack('H*', pack('V', hexdec($fields[0]))); + $fields[0] = $hex[1]; + $hex = unpack('H*', pack('v', hexdec($fields[1]))); + $fields[1] = $hex[1]; + $hex = unpack('H*', pack('v', hexdec($fields[2]))); + $fields[2] = $hex[1]; } return vsprintf( @@ -906,9 +909,12 @@ class Uuid implements \JsonSerializable // Swap byte-order on the first three fields if ($littleEndian) { - $components[0] = unpack('H*', pack('V', hexdec($components[0])))[1]; - $components[1] = unpack('H*', pack('v', hexdec($components[1])))[1]; - $components[2] = unpack('H*', pack('v', hexdec($components[2])))[1]; + $hex = unpack('H*', pack('V', hexdec($components[0]))); + $components[0] = $hex[1]; + $hex = unpack('H*', pack('v', hexdec($components[1]))); + $components[1] = $hex[1]; + $hex = unpack('H*', pack('v', hexdec($components[2]))); + $components[2] = $hex[1]; } $nameParsed = implode('-', $components); From 65916f292844f27c046ba35c58a49e61f85b598f Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Fri, 17 Oct 2014 17:49:49 +0200 Subject: [PATCH 03/30] Set default timezone in PHPUnit bootstrap to pass HHVM tests --- tests/bootstrap.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 786bef2..72c9c19 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -9,6 +9,11 @@ if (!file_exists(dirname(__DIR__) . '/vendor/autoload.php')) { . "See http://getcomposer.org for help with installing composer\n"); } +var_dump(phpversion()); + +// Set a default timezone for HHVM tests +date_default_timezone_set('UTC'); + // Include the Composer autoloader $loader = include realpath(dirname(__FILE__) . '/../vendor/autoload.php'); From 13b3bf7ed9a4ca026a6ed972a585ba68c33c50b5 Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Thu, 30 Oct 2014 09:53:43 +0100 Subject: [PATCH 04/30] Refactor from/toString methods to codecs --- src/Codec.php | 12 ++++ src/Codec/GuidStringCodec.php | 93 +++++++++++++++++++++++++++++ src/Codec/StringCodec.php | 72 ++++++++++++++++++++++ src/Uuid.php | 85 ++++++-------------------- src/UuidInterface.php | 46 ++++++++++++++ tests/Codec/GuidStringCodecTest.php | 18 ++++++ tests/Codec/StringCodecTest.php | 18 ++++++ tests/bootstrap.php | 2 - 8 files changed, 276 insertions(+), 70 deletions(-) create mode 100644 src/Codec.php create mode 100644 src/Codec/GuidStringCodec.php create mode 100644 src/Codec/StringCodec.php create mode 100644 src/UuidInterface.php create mode 100644 tests/Codec/GuidStringCodecTest.php create mode 100644 tests/Codec/StringCodecTest.php diff --git a/src/Codec.php b/src/Codec.php new file mode 100644 index 0000000..0e045c7 --- /dev/null +++ b/src/Codec.php @@ -0,0 +1,12 @@ +getFieldsHex()); + + // Swap byte-order on the first three fields + $hex = unpack('H*', pack('V', hexdec($fields[0]))); + $fields[0] = $hex[1]; + $hex = unpack('H*', pack('v', hexdec($fields[1]))); + $fields[1] = $hex[1]; + $hex = unpack('H*', pack('v', hexdec($fields[2]))); + $fields[2] = $hex[1]; + + return vsprintf( + '%08s-%04s-%04s-%02s%02s-%012s', + $fields + ); + } + + public function decode($encodedUuid) + { + return $this->_decode($encodedUuid, true); + } + + public function decodeBytes($bytes) + { + if (strlen($bytes) !== 16) { + throw new InvalidArgumentException('$bytes string should contain 16 characters.'); + } + + $hexUuid = unpack('H*', $bytes); + + return $this->_decode($hexUuid, false); + } + + private function _decode($hex, $swap) + { + $nameParsed = str_replace(array( + 'urn:', + 'uuid:', + '{', + '}', + '-' + ), '', $hex); + + // We have stripped out the dashes and are breaking up the string using + // substr(). In this way, we can accept a full hex value that doesn't + // contain dashes. + $components = array( + substr($nameParsed, 0, 8), + substr($nameParsed, 8, 4), + substr($nameParsed, 12, 4), + substr($nameParsed, 16, 4), + substr($nameParsed, 20) + ); + + if ($swap) { + $hex = unpack('H*', pack('V', hexdec($components[0]))); + $components[0] = $hex[1]; + $hex = unpack('H*', pack('v', hexdec($components[1]))); + $components[1] = $hex[1]; + $hex = unpack('H*', pack('v', hexdec($components[2]))); + $components[2] = $hex[1]; + $nameParsed = implode('-', $components); + } + + if (! Uuid::isValid($nameParsed)) { + throw new InvalidArgumentException('Invalid UUID string: ' . $name); + } + + $fields = array( + 'time_low' => sprintf('%08s', $components[0]), + 'time_mid' => sprintf('%04s', $components[1]), + 'time_hi_and_version' => sprintf('%04s', $components[2]), + 'clock_seq_hi_and_reserved' => sprintf('%02s', substr($components[3], 0, 2)), + 'clock_seq_low' => sprintf('%02s', substr($components[3], 2)), + 'node' => sprintf('%012s', $components[4]) + ); + + return new Uuid($fields, $this); + } +} diff --git a/src/Codec/StringCodec.php b/src/Codec/StringCodec.php new file mode 100644 index 0000000..a65f108 --- /dev/null +++ b/src/Codec/StringCodec.php @@ -0,0 +1,72 @@ +getFieldsHex()); + + return vsprintf( + '%08s-%04s-%04s-%02s%02s-%012s', + $fields + ); + } + + public function decode($encodedUuid) + { + $nameParsed = str_replace(array( + 'urn:', + 'uuid:', + '{', + '}', + '-' + ), '', $encodedUuid); + + // We have stripped out the dashes and are breaking up the string using + // substr(). In this way, we can accept a full hex value that doesn't + // contain dashes. + $components = array( + substr($nameParsed, 0, 8), + substr($nameParsed, 8, 4), + substr($nameParsed, 12, 4), + substr($nameParsed, 16, 4), + substr($nameParsed, 20) + ); + + $nameParsed = implode('-', $components); + + if (! Uuid::isValid($nameParsed)) { + throw new InvalidArgumentException('Invalid UUID string: ' . $name); + } + + $fields = array( + 'time_low' => sprintf('%08s', $components[0]), + 'time_mid' => sprintf('%04s', $components[1]), + 'time_hi_and_version' => sprintf('%04s', $components[2]), + 'clock_seq_hi_and_reserved' => sprintf('%02s', substr($components[3], 0, 2)), + 'clock_seq_low' => sprintf('%02s', substr($components[3], 2)), + 'node' => sprintf('%012s', $components[4]) + ); + + return new Uuid($fields, $this); + } + + public function decodeBytes($bytes) + { + if (strlen($bytes) !== 16) { + throw new InvalidArgumentException('$bytes string should contain 16 characters.'); + } + + $hexUuid = unpack('H*', $bytes); + + return $this->decode($hexUuid); + } +} diff --git a/src/Uuid.php b/src/Uuid.php index a5bed74..4cdbddc 100644 --- a/src/Uuid.php +++ b/src/Uuid.php @@ -12,6 +12,8 @@ namespace Rhumsaa\Uuid; use InvalidArgumentException; +use Rhumsaa\Uuid\Codec\GuidStringCodec; +use Rhumsaa\Uuid\Codec\StringCodec; /** * Represents a universally unique identifier (UUID), according to RFC 4122 @@ -29,7 +31,8 @@ use InvalidArgumentException; * @link http://docs.python.org/3/library/uuid.html * @link http://docs.oracle.com/javase/6/docs/api/java/util/UUID.html */ -class Uuid implements \JsonSerializable + +final class Uuid implements UuidInterface, \JsonSerializable { /** * When this namespace is specified, the name string is a fully-qualified domain name. @@ -150,10 +153,10 @@ class Uuid implements \JsonSerializable ); /** - * Whether the first three fields are stored in little endian format (GUID's) - * @var bool + * String codec + * @var Codec */ - protected $isLittleEndian; + protected $codec; /** * Creates a universally unique identifier (UUID) from an array of fields. @@ -162,13 +165,13 @@ class Uuid implements \JsonSerializable * UUIDs. * * @param array $fields - * @param bool $littleEndian Whether the first three fields are in little-endian format. + * @param Codec $codec String codec * @link Rhumsaa.Uuid.Uuid.html#method_getFields */ - protected function __construct(array $fields, $littleEndian = false) + public function __construct(array $fields, Codec $codec = null) { $this->fields = $fields; - $this->isLittleEndian = (bool)$littleEndian; + $this->codec = $codec ?: new StringCodec(); } /** @@ -209,7 +212,7 @@ class Uuid implements \JsonSerializable * @param Uuid $uuid UUID to which this UUID is to be compared * @return int -1, 0 or 1 as this UUID is less than, equal to, or greater than $uuid */ - public function compareTo(Uuid $uuid) + public function compareTo(UuidInterface $uuid) { $comparison = null; @@ -844,22 +847,7 @@ class Uuid implements \JsonSerializable */ public function toString($forceBigEndian = false) { - $fields = array_values($this->fields); - - if ($this->isLittleEndian && $forceBigEndian == false) { - // Swap byte-order on the first three fields - $hex = unpack('H*', pack('V', hexdec($fields[0]))); - $fields[0] = $hex[1]; - $hex = unpack('H*', pack('v', hexdec($fields[1]))); - $fields[1] = $hex[1]; - $hex = unpack('H*', pack('v', hexdec($fields[2]))); - $fields[2] = $hex[1]; - } - - return vsprintf( - '%08s-%04s-%04s-%02s%02s-%012s', - $fields - ); + return $this->codec->encode($this); } /** @@ -871,16 +859,11 @@ class Uuid implements \JsonSerializable */ public static function fromBytes($bytes, $littleEndian = false) { - if (strlen($bytes) !== 16) { - throw new InvalidArgumentException('$bytes string should contain 16 characters.'); + if ($littleEndian) { + return (new GuidStringCodec())->decodeBytes($bytes); } - $hexUuid = unpack('H*', $bytes); - - $uuid = Uuid::fromString($hexUuid[1], false); - $uuid->isLittleEndian = $littleEndian; - - return $uuid; + return (new StringCodec())->decodeBytes($bytes); } /** @@ -894,45 +877,11 @@ class Uuid implements \JsonSerializable */ public static function fromString($name, $littleEndian = false) { - $nameParsed = str_replace(array('urn:', 'uuid:', '{', '}', '-'), '', $name); - - // We have stripped out the dashes and are breaking up the string using - // substr(). In this way, we can accept a full hex value that doesn't - // contain dashes. - $components = array( - substr($nameParsed, 0, 8), - substr($nameParsed, 8, 4), - substr($nameParsed, 12, 4), - substr($nameParsed, 16, 4), - substr($nameParsed, 20), - ); - - // Swap byte-order on the first three fields if ($littleEndian) { - $hex = unpack('H*', pack('V', hexdec($components[0]))); - $components[0] = $hex[1]; - $hex = unpack('H*', pack('v', hexdec($components[1]))); - $components[1] = $hex[1]; - $hex = unpack('H*', pack('v', hexdec($components[2]))); - $components[2] = $hex[1]; + return (new GuidStringCodec())->decode($name); } - $nameParsed = implode('-', $components); - - if (!self::isValid($nameParsed)) { - throw new InvalidArgumentException('Invalid UUID string: ' . $name); - } - - $fields = array( - 'time_low' => sprintf('%08s', $components[0]), - 'time_mid' => sprintf('%04s', $components[1]), - 'time_hi_and_version' => sprintf('%04s', $components[2]), - 'clock_seq_hi_and_reserved' => sprintf('%02s', substr($components[3], 0, 2)), - 'clock_seq_low' => sprintf('%02s', substr($components[3], 2)), - 'node' => sprintf('%012s', $components[4]), - ); - - return new self($fields, $littleEndian); + return (new StringCodec())->decode($name); } /** diff --git a/src/UuidInterface.php b/src/UuidInterface.php new file mode 100644 index 0000000..d268ff2 --- /dev/null +++ b/src/UuidInterface.php @@ -0,0 +1,46 @@ +decode('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); + + $this->assertInstanceOf('\Rhumsaa\Uuid\Uuid', $uuid); + $this->assertEquals('ff6f8cb0-c57d-11e1-9b21-0800200c9a66', $uuid->toString()); + } +} diff --git a/tests/Codec/StringCodecTest.php b/tests/Codec/StringCodecTest.php new file mode 100644 index 0000000..5426b66 --- /dev/null +++ b/tests/Codec/StringCodecTest.php @@ -0,0 +1,18 @@ +decode('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); + + $this->assertInstanceOf('\Rhumsaa\Uuid\Uuid', $uuid); + $this->assertEquals('ff6f8cb0-c57d-11e1-9b21-0800200c9a66', $uuid->toString()); + } +} diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 72c9c19..50e981f 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -9,8 +9,6 @@ if (!file_exists(dirname(__DIR__) . '/vendor/autoload.php')) { . "See http://getcomposer.org for help with installing composer\n"); } -var_dump(phpversion()); - // Set a default timezone for HHVM tests date_default_timezone_set('UTC'); From 723ef345bf759e4c7ae49a948a1680d51e39b0fa Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Thu, 30 Oct 2014 10:16:22 +0100 Subject: [PATCH 05/30] Refactor factory functions Remove $littleEndian parameter Add fromGuidString/Bytes factory methods for GUIDs No longer possible to output GUIDs as UUIDs and vice-versa Pass tests --- src/Codec.php | 4 +++- src/Codec/GuidStringCodec.php | 14 +++++++++++--- src/Codec/StringCodec.php | 15 +++++++++++++-- src/Uuid.php | 32 ++++++++++++++------------------ src/UuidInterface.php | 2 ++ tests/UuidTest.php | 10 ++++------ 6 files changed, 47 insertions(+), 30 deletions(-) diff --git a/src/Codec.php b/src/Codec.php index 0e045c7..9912851 100644 --- a/src/Codec.php +++ b/src/Codec.php @@ -4,7 +4,9 @@ namespace Rhumsaa\Uuid; interface Codec { - public function encode(UuidInterface $plainUuid); + public function encode(UuidInterface $uuid); + + public function encodeBinary(UuidInterface $uuid); public function decode($encodedUuid); diff --git a/src/Codec/GuidStringCodec.php b/src/Codec/GuidStringCodec.php index a8afb25..1e03e6e 100644 --- a/src/Codec/GuidStringCodec.php +++ b/src/Codec/GuidStringCodec.php @@ -28,6 +28,13 @@ class GuidStringCodec implements Codec ); } + public function encodeBinary(UuidInterface $uuid) + { + $reversed = $this->_decode($this->encode($uuid), false); + + return (new StringCodec())->encodeBinary($reversed); + } + public function decode($encodedUuid) { return $this->_decode($encodedUuid, true); @@ -41,7 +48,7 @@ class GuidStringCodec implements Codec $hexUuid = unpack('H*', $bytes); - return $this->_decode($hexUuid, false); + return $this->_decode($hexUuid[1], false); } private function _decode($hex, $swap) @@ -72,11 +79,12 @@ class GuidStringCodec implements Codec $components[1] = $hex[1]; $hex = unpack('H*', pack('v', hexdec($components[2]))); $components[2] = $hex[1]; - $nameParsed = implode('-', $components); } + $nameParsed = implode('-', $components); + if (! Uuid::isValid($nameParsed)) { - throw new InvalidArgumentException('Invalid UUID string: ' . $name); + throw new InvalidArgumentException('Invalid UUID string: ' . $hex); } $fields = array( diff --git a/src/Codec/StringCodec.php b/src/Codec/StringCodec.php index a65f108..b787a6e 100644 --- a/src/Codec/StringCodec.php +++ b/src/Codec/StringCodec.php @@ -20,6 +20,17 @@ class StringCodec implements Codec ); } + public function encodeBinary(UuidInterface $uuid) + { + $bytes = ''; + + foreach (range(-2, -32, 2) as $step) { + $bytes = chr(hexdec(substr($uuid->getHex(), $step, 2))) . $bytes; + } + + return $bytes; + } + public function decode($encodedUuid) { $nameParsed = str_replace(array( @@ -44,7 +55,7 @@ class StringCodec implements Codec $nameParsed = implode('-', $components); if (! Uuid::isValid($nameParsed)) { - throw new InvalidArgumentException('Invalid UUID string: ' . $name); + throw new InvalidArgumentException('Invalid UUID string: ' . $encodedUuid); } $fields = array( @@ -67,6 +78,6 @@ class StringCodec implements Codec $hexUuid = unpack('H*', $bytes); - return $this->decode($hexUuid); + return $this->decode($hexUuid[1]); } } diff --git a/src/Uuid.php b/src/Uuid.php index 4cdbddc..3cc6d69 100644 --- a/src/Uuid.php +++ b/src/Uuid.php @@ -258,13 +258,7 @@ final class Uuid implements UuidInterface, \JsonSerializable */ public function getBytes() { - $bytes = ''; - - foreach (range(-2, -32, 2) as $step) { - $bytes = chr(hexdec(substr($this->getHex(), $step, 2))) . $bytes; - } - - return $bytes; + return $this->codec->encodeBinary($this); } /** @@ -845,7 +839,7 @@ final class Uuid implements UuidInterface, \JsonSerializable * * @return string */ - public function toString($forceBigEndian = false) + public function toString() { return $this->codec->encode($this); } @@ -857,15 +851,16 @@ final class Uuid implements UuidInterface, \JsonSerializable * @return Uuid * @throws InvalidArgumentException If the $bytes string does not contain 16 characters */ - public static function fromBytes($bytes, $littleEndian = false) + public static function fromBytes($bytes) { - if ($littleEndian) { - return (new GuidStringCodec())->decodeBytes($bytes); - } - return (new StringCodec())->decodeBytes($bytes); } + public static function fromGuidBytes($bytes) + { + return (new GuidStringCodec())->decodeBytes($bytes); + } + /** * Creates a UUID from the string standard representation as described * in the toString() method. @@ -875,15 +870,16 @@ final class Uuid implements UuidInterface, \JsonSerializable * @return Uuid * @throws InvalidArgumentException If the $name isn't a valid UUID */ - public static function fromString($name, $littleEndian = false) + public static function fromString($name) { - if ($littleEndian) { - return (new GuidStringCodec())->decode($name); - } - return (new StringCodec())->decode($name); } + public static function fromGuidString($name) + { + return (new GuidStringCodec())->decode($name); + } + /** * Creates a UUID from either the UUID as a 128-bit integer string or a Moontoast\Math\BigNumber object. * diff --git a/src/UuidInterface.php b/src/UuidInterface.php index d268ff2..f82f161 100644 --- a/src/UuidInterface.php +++ b/src/UuidInterface.php @@ -9,6 +9,8 @@ interface UuidInterface public function equals($other); + public function getHex(); + public function getFieldsHex(); public function getClockSeqHiAndReservedHex(); diff --git a/tests/UuidTest.php b/tests/UuidTest.php index fe56804..a601b20 100644 --- a/tests/UuidTest.php +++ b/tests/UuidTest.php @@ -29,7 +29,7 @@ class UuidTest extends TestCase public function testFromLittleEndianString() { $uuid = Uuid::fromString('b08c6fff-7dc5-e111-9b21-0800200c9a66'); - $guid = Uuid::fromString('b08c6fff-7dc5-e111-9b21-0800200c9a66', true); + $guid = Uuid::fromGuidString('b08c6fff-7dc5-e111-9b21-0800200c9a66'); $this->assertInstanceOf('\Rhumsaa\Uuid\Uuid', $guid); // UUID's and GUID's share the same textual representation @@ -1456,18 +1456,16 @@ class UuidTest extends TestCase $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); $bytes = $uuid->getBytes(); - $guid = Uuid::fromBytes($bytes, true); + $guid = Uuid::fromGuidBytes($bytes); // First three fields should be reversed $this->assertEquals('b08c6fff-7dc5-e111-9b21-0800200c9a66', $guid->toString()); - // Except if forcing big endian - $this->assertEquals($uuid->toString(), $guid->toString(true)); // Check that parsing LE bytes as LE preserves fields - $guid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66', true); + $guid = Uuid::fromGuidString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); $bytes = $guid->getBytes(); - $parsedGuid = Uuid::fromBytes($bytes, true); + $parsedGuid = Uuid::fromGuidBytes($bytes); $this->assertEquals($guid->toString(), $parsedGuid->toString()); } From fead6f3223688c087b3e5e0e4c7456172ee5424b Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Thu, 30 Oct 2014 13:16:19 +0100 Subject: [PATCH 06/30] Refactor in the spirit of #1 & #34 --- src/BigNumberConverter.php | 13 + src/Codec.php | 4 +- src/Codec/GuidStringCodec.php | 23 +- src/Codec/StringCodec.php | 17 +- src/Generator/MtRandGenerator.php | 19 + src/Generator/OpenSslGenerator.php | 14 + src/RandomGenerator.php | 8 + src/RandomGeneratorFactory.php | 36 ++ src/SmallIntUuid.php | 151 ++++++++ src/UnsatisfiedNumberConverter.php | 16 + src/Uuid.php | 456 ++--------------------- src/UuidFactory.php | 416 +++++++++++++++++++++ src/UuidInterface.php | 2 + tests/Codec/GuidStringCodecTest.php | 18 - tests/Codec/StringCodecTest.php | 18 - tests/RandomGeneratorFactoryTest.php | 24 ++ tests/UnsatisfiedNumberConverterTest.php | 16 + tests/UuidBcTag1_1_2Test.php | 52 +-- tests/UuidFactoryTest.php | 24 ++ tests/UuidTest.php | 281 +++----------- tests/bootstrap.php | 6 + 21 files changed, 865 insertions(+), 749 deletions(-) create mode 100644 src/BigNumberConverter.php create mode 100644 src/Generator/MtRandGenerator.php create mode 100644 src/Generator/OpenSslGenerator.php create mode 100644 src/RandomGenerator.php create mode 100644 src/RandomGeneratorFactory.php create mode 100644 src/SmallIntUuid.php create mode 100644 src/UnsatisfiedNumberConverter.php create mode 100644 src/UuidFactory.php delete mode 100644 tests/Codec/GuidStringCodecTest.php delete mode 100644 tests/Codec/StringCodecTest.php create mode 100644 tests/RandomGeneratorFactoryTest.php create mode 100644 tests/UnsatisfiedNumberConverterTest.php create mode 100644 tests/UuidFactoryTest.php diff --git a/src/BigNumberConverter.php b/src/BigNumberConverter.php new file mode 100644 index 0000000..349ea33 --- /dev/null +++ b/src/BigNumberConverter.php @@ -0,0 +1,13 @@ +factory = $factory; + } + public function encode(UuidInterface $uuid) { $fields = array_values($uuid->getFieldsHex()); @@ -30,17 +39,17 @@ class GuidStringCodec implements Codec public function encodeBinary(UuidInterface $uuid) { - $reversed = $this->_decode($this->encode($uuid), false); + $reversed = $this->_decode($uuid->getConverter(), $this->encode($uuid), false); return (new StringCodec())->encodeBinary($reversed); } - public function decode($encodedUuid) + public function decode(BigNumberConverter $converter, $encodedUuid) { - return $this->_decode($encodedUuid, true); + return $this->_decode($converter, $encodedUuid, true); } - public function decodeBytes($bytes) + public function decodeBytes(BigNumberConverter $converter, $bytes) { if (strlen($bytes) !== 16) { throw new InvalidArgumentException('$bytes string should contain 16 characters.'); @@ -48,10 +57,10 @@ class GuidStringCodec implements Codec $hexUuid = unpack('H*', $bytes); - return $this->_decode($hexUuid[1], false); + return $this->_decode($converter, $hexUuid[1], false); } - private function _decode($hex, $swap) + private function _decode(BigNumberConverter $converter, $hex, $swap) { $nameParsed = str_replace(array( 'urn:', @@ -96,6 +105,6 @@ class GuidStringCodec implements Codec 'node' => sprintf('%012s', $components[4]) ); - return new Uuid($fields, $this); + return $this->factory->uuid($fields, $this); } } diff --git a/src/Codec/StringCodec.php b/src/Codec/StringCodec.php index b787a6e..5e9fd43 100644 --- a/src/Codec/StringCodec.php +++ b/src/Codec/StringCodec.php @@ -6,10 +6,19 @@ use InvalidArgumentException; use Rhumsaa\Uuid\Codec; use Rhumsaa\Uuid\UuidInterface; use Rhumsaa\Uuid\Uuid; +use Rhumsaa\Uuid\BigNumberConverter; +use Rhumsaa\Uuid\UuidFactory; class StringCodec implements Codec { + private $factory; + + public function __construct(UuidFactory $factory) + { + $this->factory = $factory; + } + public function encode(UuidInterface $uuid) { $fields = array_values($uuid->getFieldsHex()); @@ -31,7 +40,7 @@ class StringCodec implements Codec return $bytes; } - public function decode($encodedUuid) + public function decode(BigNumberConverter $converter, $encodedUuid) { $nameParsed = str_replace(array( 'urn:', @@ -67,10 +76,10 @@ class StringCodec implements Codec 'node' => sprintf('%012s', $components[4]) ); - return new Uuid($fields, $this); + return $this->factory->uuid($fields, $this); } - public function decodeBytes($bytes) + public function decodeBytes(BigNumberConverter $converter, $bytes) { if (strlen($bytes) !== 16) { throw new InvalidArgumentException('$bytes string should contain 16 characters.'); @@ -78,6 +87,6 @@ class StringCodec implements Codec $hexUuid = unpack('H*', $bytes); - return $this->decode($hexUuid[1]); + return $this->decode($converter, $hexUuid[1]); } } diff --git a/src/Generator/MtRandGenerator.php b/src/Generator/MtRandGenerator.php new file mode 100644 index 0000000..af24dcc --- /dev/null +++ b/src/Generator/MtRandGenerator.php @@ -0,0 +1,19 @@ +getVersion() != 1) { + throw new Exception\UnsupportedOperationException('Not a time-based UUID'); + } + + $time = $this->converter->fromHex($this->getTimestampHex()); + + $ts = new \Moontoast\Math\BigNumber($time, 20); + $ts->subtract('122192928000000000'); + $ts->divide('10000000.0'); + $ts->round(); + $unixTime = $ts->getValue(); + + return new \DateTime("@{$unixTime}"); + } + + /** + * Returns an array of the fields of this UUID, with keys named according + * to the RFC 4122 names for the fields. + * + * * **time_low**: The low field of the timestamp, an unsigned 32-bit integer + * * **time_mid**: The middle field of the timestamp, an unsigned 16-bit integer + * * **time_hi_and_version**: The high field of the timestamp multiplexed with + * the version number, an unsigned 16-bit integer + * * **clock_seq_hi_and_reserved**: The high field of the clock sequence + * multiplexed with the variant, an unsigned 8-bit integer + * * **clock_seq_low**: The low field of the clock sequence, an unsigned + * 8-bit integer + * * **node**: The spatially unique node identifier, an unsigned 48-bit + * integer + * + * @return array The UUID fields represented as integer values + * @throws Exception\UnsatisfiedDependencyException if called on a 32-bit system + * @link http://tools.ietf.org/html/rfc4122#section-4.1.2 + */ + public function getFields() + { + throw new Exception\UnsatisfiedDependencyException( + 'Cannot call ' . __METHOD__ . ' on a 32-bit system, since some ' + . 'values overflow the system max integer value' + . '; consider calling getFieldsHex instead' + ); + } + + /** + * Returns the node value associated with this UUID + * + * For UUID version 1, the node field consists of an IEEE 802 MAC + * address, usually the host address. For systems with multiple IEEE + * 802 addresses, any available one can be used. The lowest addressed + * octet (octet number 10) contains the global/local bit and the + * unicast/multicast bit, and is the first octet of the address + * transmitted on an 802.3 LAN. + * + * For systems with no IEEE address, a randomly or pseudo-randomly + * generated value may be used; see RFC 4122, Section 4.5. The + * multicast bit must be set in such addresses, in order that they + * will never conflict with addresses obtained from network cards. + * + * For UUID version 3 or 5, the node field is a 48-bit value constructed + * from a name as described in RFC 4122, Section 4.3. + * + * For UUID version 4, the node field is a randomly or pseudo-randomly + * generated 48-bit value as described in RFC 4122, Section 4.4. + * + * @return int Unsigned 48-bit integer value of node + * @link http://tools.ietf.org/html/rfc4122#section-4.1.6 + * @throws Exception\UnsatisfiedDependencyException if called on a 32-bit system + */ + public function getNode() + { + throw new Exception\UnsatisfiedDependencyException( + 'Cannot call ' . __METHOD__ . ' on a 32-bit system, since node ' + . 'is an unsigned 48-bit integer and can overflow the system ' + . 'max integer value' + . '; consider calling getNodeHex instead' + ); + } + + /** + * Returns the low field of the timestamp (the first 32 bits of the UUID). + * + * @return int Unsigned 32-bit integer value of time_low + * @throws Exception\UnsatisfiedDependencyException if called on a 32-bit system + */ + public function getTimeLow() + { + throw new Exception\UnsatisfiedDependencyException( + 'Cannot call ' . __METHOD__ . ' on a 32-bit system, since time_low ' + . 'is an unsigned 32-bit integer and can overflow the system ' + . 'max integer value' + . '; consider calling getTimeLowHex instead' + ); + } + + /** + * The timestamp value associated with this UUID + * + * The 60 bit timestamp value is constructed from the time_low, + * time_mid, and time_hi fields of this UUID. The resulting + * timestamp is measured in 100-nanosecond units since midnight, + * October 15, 1582 UTC. + * + * The timestamp value is only meaningful in a time-based UUID, which + * has version type 1. If this UUID is not a time-based UUID then + * this method throws UnsupportedOperationException. + * + * @return int Unsigned 60-bit integer value of the timestamp + * @throws Exception\UnsupportedOperationException If this UUID is not a version 1 UUID + * @throws Exception\UnsatisfiedDependencyException if called on a 32-bit system + * @link http://tools.ietf.org/html/rfc4122#section-4.1.4 + */ + public function getTimestamp() + { + if ($this->getVersion() != 1) { + throw new Exception\UnsupportedOperationException('Not a time-based UUID'); + } + + throw new Exception\UnsatisfiedDependencyException( + 'Cannot call ' . __METHOD__ . ' on a 32-bit system, since timestamp ' + . 'is an unsigned 60-bit integer and can overflow the system ' + . 'max integer value' + . '; consider calling getTimestampHex instead' + ); + } +} diff --git a/src/UnsatisfiedNumberConverter.php b/src/UnsatisfiedNumberConverter.php new file mode 100644 index 0000000..e6b7119 --- /dev/null +++ b/src/UnsatisfiedNumberConverter.php @@ -0,0 +1,16 @@ + '000000000000', ); - /** - * String codec - * @var Codec - */ - protected $codec; + protected $converter; /** * Creates a universally unique identifier (UUID) from an array of fields. @@ -168,10 +139,11 @@ final class Uuid implements UuidInterface, \JsonSerializable * @param Codec $codec String codec * @link Rhumsaa.Uuid.Uuid.html#method_getFields */ - public function __construct(array $fields, Codec $codec = null) + public function __construct(array $fields, BigNumberConverter $converter, Codec $codec) { $this->fields = $fields; - $this->codec = $codec ?: new StringCodec(); + $this->codec = $codec; + $this->converter = $converter; } /** @@ -335,6 +307,11 @@ final class Uuid implements UuidInterface, \JsonSerializable return sprintf('%04x', $this->getClockSequence()); } + public function getConverter() + { + return $this->converter; + } + /** * Returns a PHP DateTime object representing the timestamp associated * with this UUID. @@ -353,31 +330,8 @@ final class Uuid implements UuidInterface, \JsonSerializable throw new Exception\UnsupportedOperationException('Not a time-based UUID'); } - - if (self::is64BitSystem()) { - - $unixTime = ($this->getTimestamp() - 0x01b21dd213814000) / 1e7; - $unixTime = number_format($unixTime, 0, '', ''); - - } elseif (self::hasBigNumber()) { - - $time = \Moontoast\Math\BigNumber::baseConvert($this->getTimestampHex(), 16, 10); - - $ts = new \Moontoast\Math\BigNumber($time, 20); - $ts->subtract('122192928000000000'); - $ts->divide('10000000.0'); - $ts->round(); - $unixTime = $ts->getValue(); - - } else { - - throw new Exception\UnsatisfiedDependencyException( - 'When calling ' . __METHOD__ . ' on a 32-bit system, ' - . 'Moontoast\Math\BigNumber must be present in order ' - . 'to extract DateTime from version 1 UUIDs' - ); - - } + $unixTime = ($this->getTimestamp() - 0x01b21dd213814000) / 1e7; + $unixTime = number_format($unixTime, 0, '', ''); return new \DateTime("@{$unixTime}"); } @@ -403,14 +357,6 @@ final class Uuid implements UuidInterface, \JsonSerializable */ public function getFields() { - if (!self::is64BitSystem()) { - throw new Exception\UnsatisfiedDependencyException( - 'Cannot call ' . __METHOD__ . ' on a 32-bit system, since some ' - . 'values overflow the system max integer value' - . '; consider calling getFieldsHex instead' - ); - } - return array( 'time_low' => $this->getTimeLow(), 'time_mid' => $this->getTimeMid(), @@ -461,22 +407,7 @@ final class Uuid implements UuidInterface, \JsonSerializable */ public function getInteger() { - if (!self::hasBigNumber()) { - throw new Exception\UnsatisfiedDependencyException( - 'Cannot call ' . __METHOD__ . ' without support for large ' - . 'integers, since integer is an unsigned ' - . '128-bit integer; Moontoast\Math\BigNumber is required' - . '; consider calling getMostSignificantBitsHex instead' - ); - } - - $number = \Moontoast\Math\BigNumber::baseConvert( - $this->getHex(), - 16, - 10 - ); - - return new \Moontoast\Math\BigNumber($number); + return $this->converter->fromHex($this->getHex()); } /** @@ -487,22 +418,7 @@ final class Uuid implements UuidInterface, \JsonSerializable */ public function getLeastSignificantBits() { - if (!self::hasBigNumber()) { - throw new Exception\UnsatisfiedDependencyException( - 'Cannot call ' . __METHOD__ . ' without support for large ' - . 'integers, since least significant bits is an unsigned ' - . '64-bit integer; Moontoast\Math\BigNumber is required' - . '; consider calling getLeastSignificantBitsHex instead' - ); - } - - $number = \Moontoast\Math\BigNumber::baseConvert( - $this->getLeastSignificantBitsHex(), - 16, - 10 - ); - - return new \Moontoast\Math\BigNumber($number); + return $this->converter->fromHex($this->getLeastSignificantBitsHex()); } /** @@ -528,22 +444,7 @@ final class Uuid implements UuidInterface, \JsonSerializable */ public function getMostSignificantBits() { - if (!self::hasBigNumber()) { - throw new Exception\UnsatisfiedDependencyException( - 'Cannot call ' . __METHOD__ . ' without support for large ' - . 'integers, since most significant bits is an unsigned ' - . '64-bit integer; Moontoast\Math\BigNumber is required' - . '; consider calling getMostSignificantBitsHex instead' - ); - } - - $number = \Moontoast\Math\BigNumber::baseConvert( - $this->getMostSignificantBitsHex(), - 16, - 10 - ); - - return new \Moontoast\Math\BigNumber($number); + return $this->converter->fromHex($this->getMostSignificantBitsHex()); } /** @@ -588,15 +489,6 @@ final class Uuid implements UuidInterface, \JsonSerializable */ public function getNode() { - if (!self::is64BitSystem()) { - throw new Exception\UnsatisfiedDependencyException( - 'Cannot call ' . __METHOD__ . ' on a 32-bit system, since node ' - . 'is an unsigned 48-bit integer and can overflow the system ' - . 'max integer value' - . '; consider calling getNodeHex instead' - ); - } - return hexdec($this->getNodeHex()); } @@ -659,15 +551,6 @@ final class Uuid implements UuidInterface, \JsonSerializable */ public function getTimeLow() { - if (!self::is64BitSystem()) { - throw new Exception\UnsatisfiedDependencyException( - 'Cannot call ' . __METHOD__ . ' on a 32-bit system, since time_low ' - . 'is an unsigned 32-bit integer and can overflow the system ' - . 'max integer value' - . '; consider calling getTimeLowHex instead' - ); - } - return hexdec($this->getTimeLowHex()); } @@ -724,15 +607,6 @@ final class Uuid implements UuidInterface, \JsonSerializable throw new Exception\UnsupportedOperationException('Not a time-based UUID'); } - if (!self::is64BitSystem()) { - throw new Exception\UnsatisfiedDependencyException( - 'Cannot call ' . __METHOD__ . ' on a 32-bit system, since timestamp ' - . 'is an unsigned 60-bit integer and can overflow the system ' - . 'max integer value' - . '; consider calling getTimestampHex instead' - ); - } - return hexdec($this->getTimestampHex()); } @@ -844,6 +718,20 @@ final class Uuid implements UuidInterface, \JsonSerializable return $this->codec->encode($this); } + public static function getFactory() + { + if (! self::$factory) { + self::$factory = new UuidFactory(); + } + + return self::$factory; + } + + public static function setFactory(UuidFactory $factory) + { + self::$factory = $factory; + } + /** * Creates a UUID from a byte string. * @@ -853,12 +741,12 @@ final class Uuid implements UuidInterface, \JsonSerializable */ public static function fromBytes($bytes) { - return (new StringCodec())->decodeBytes($bytes); + return self::getFactory()->fromBytes($bytes); } public static function fromGuidBytes($bytes) { - return (new GuidStringCodec())->decodeBytes($bytes); + return self::getFactory()->fromGuidBytes($bytes); } /** @@ -872,12 +760,12 @@ final class Uuid implements UuidInterface, \JsonSerializable */ public static function fromString($name) { - return (new StringCodec())->decode($name); + return self::getFactory()->fromString($name); } public static function fromGuidString($name) { - return (new GuidStringCodec())->decode($name); + return self::getFactory()->fromGuidString($name); } /** @@ -944,61 +832,7 @@ final class Uuid implements UuidInterface, \JsonSerializable */ public static function uuid1($node = null, $clockSeq = null) { - if ($node === null && !self::$ignoreSystemNode) { - $node = self::getNodeFromSystem(); - } - - // if $node is still null (couldn't get from system), randomly generate - // a node value, according to RFC 4122, Section 4.5 - if ($node === null) { - $node = sprintf('%06x%06x', mt_rand(0, 1 << 24), mt_rand(0, 1 << 24)); - } - - // Convert the node to hex, if it is still an integer - if (is_int($node)) { - $node = sprintf('%012x', $node); - } - - if (ctype_xdigit($node) && strlen($node) <= 12) { - $node = strtolower(sprintf('%012s', $node)); - } else { - throw new InvalidArgumentException('Invalid node value'); - } - - if ($clockSeq === null) { - // Not using "stable storage"; see RFC 4122, Section 4.2.1.1 - $clockSeq = mt_rand(0, 1 << 14); - } - - // Create a 60-bit time value as a count of 100-nanosecond intervals - // since 00:00:00.00, 15 October 1582 - if (self::$timeOfDayTest === null) { - $timeOfDay = gettimeofday(); - } else { - $timeOfDay = self::$timeOfDayTest; - } - $uuidTime = self::calculateUuidTime($timeOfDay['sec'], $timeOfDay['usec']); - - // Set the version number to 1 - $timeHi = hexdec($uuidTime['hi']) & 0x0fff; - $timeHi &= ~(0xf000); - $timeHi |= 1 << 12; - - // Set the variant to RFC 4122 - $clockSeqHi = ($clockSeq >> 8) & 0x3f; - $clockSeqHi &= ~(0xc0); - $clockSeqHi |= 0x80; - - $fields = array( - 'time_low' => $uuidTime['low'], - 'time_mid' => $uuidTime['mid'], - 'time_hi_and_version' => sprintf('%04x', $timeHi), - 'clock_seq_hi_and_reserved' => sprintf('%02x', $clockSeqHi), - 'clock_seq_low' => sprintf('%02x', $clockSeq & 0xff), - 'node' => $node, - ); - - return new self($fields); + return self::getFactory()->uuid1($node, $clockSeq); } /** @@ -1011,13 +845,7 @@ final class Uuid implements UuidInterface, \JsonSerializable */ public static function uuid3($ns, $name) { - if (!($ns instanceof Uuid)) { - $ns = self::fromString($ns); - } - - $hash = md5($ns->getBytes() . $name); - - return self::uuidFromHashedName($hash, 3); + return self::getFactory()->uuid3($ns, $name); } /** @@ -1027,13 +855,7 @@ final class Uuid implements UuidInterface, \JsonSerializable */ public static function uuid4() { - $bytes = self::generateBytes(16); - - // When converting the bytes to hex, it turns into a 32-character - // hexadecimal string that looks a lot like an MD5 hash, so at this - // point, we can just pass it to uuidFromHashedName. - $hex = bin2hex($bytes); - return self::uuidFromHashedName($hex, 4); + return self::getFactory()->uuid4(); } /** @@ -1046,202 +868,6 @@ final class Uuid implements UuidInterface, \JsonSerializable */ public static function uuid5($ns, $name) { - if (!($ns instanceof Uuid)) { - $ns = self::fromString($ns); - } - - $hash = sha1($ns->getBytes() . $name); - - return self::uuidFromHashedName($hash, 5); - } - - /** - * Calculates the UUID time fields from a UNIX timestamp - * - * UUID time is a 60-bit time value as a count of 100-nanosecond intervals - * since 00:00:00.00, 15 October 1582. - * - * @param int $sec Seconds since the Unix Epoch - * @param int $usec Microseconds - * @return array - * @throws Exception\UnsatisfiedDependencyException if called on a 32-bit system and Moontoast\Math\BigNumber is not present - */ - protected static function calculateUuidTime($sec, $usec) - { - if (self::is64BitSystem()) { - - // 0x01b21dd213814000 is the number of 100-ns intervals between the - // UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00. - $uuidTime = ($sec * 10000000) + ($usec * 10) + 0x01b21dd213814000; - - return array( - 'low' => sprintf('%08x', $uuidTime & 0xffffffff), - 'mid' => sprintf('%04x', ($uuidTime >> 32) & 0xffff), - 'hi' => sprintf('%04x', ($uuidTime >> 48) & 0x0fff), - ); - } - - if (self::hasBigNumber()) { - - $uuidTime = new \Moontoast\Math\BigNumber('0'); - - $sec = new \Moontoast\Math\BigNumber($sec); - $sec->multiply('10000000'); - - $usec = new \Moontoast\Math\BigNumber($usec); - $usec->multiply('10'); - - $uuidTime->add($sec) - ->add($usec) - ->add('122192928000000000'); - - $uuidTimeHex = sprintf('%016s', $uuidTime->convertToBase(16)); - - return array( - 'low' => substr($uuidTimeHex, 8), - 'mid' => substr($uuidTimeHex, 4, 4), - 'hi' => substr($uuidTimeHex, 0, 4), - ); - } - - throw new Exception\UnsatisfiedDependencyException( - 'When calling ' . __METHOD__ . ' on a 32-bit system, ' - . 'Moontoast\Math\BigNumber must be present in order ' - . 'to generate version 1 UUIDs' - ); - } - - /** - * Returns the network interface configuration for the system - * - * @todo Needs evaluation and possibly modification to ensure this works - * well across multiple platforms. - * @codeCoverageIgnore - */ - protected static function getIfconfig() - { - switch (strtoupper(substr(php_uname('a'), 0, 3))) { - case 'WIN': - $ifconfig = `ipconfig /all 2>&1`; - break; - case 'DAR': - $ifconfig = `ifconfig 2>&1`; - break; - case 'LIN': - default: - $ifconfig = `netstat -ie 2>&1`; - break; - } - - return $ifconfig; - } - - /** - * Get the hardware address as a 48-bit positive integer. If all attempts to - * obtain the hardware address fail, we choose a random 48-bit number with - * its eighth bit set to 1 as recommended in RFC 4122. "Hardware address" - * means the MAC address of a network interface, and on a machine with - * multiple network interfaces the MAC address of any one of them may be - * returned. - * - * @return string - */ - protected static function getNodeFromSystem() - { - $node = null; - $pattern = '/[^:]([0-9A-Fa-f]{2}([:-])[0-9A-Fa-f]{2}(\2[0-9A-Fa-f]{2}){4})[^:]/'; - $matches = array(); - - // Search the ifconfig output for all MAC addresses and return - // the first one found - if (preg_match_all($pattern, self::getIfconfig(), $matches, PREG_PATTERN_ORDER)) { - $node = $matches[1][0]; - $node = str_replace(':', '', $node); - $node = str_replace('-', '', $node); - } - - return $node; - } - - /** - * Returns true if the system has Moontoast\Math\BigNumber - * - * @return bool - */ - protected static function hasBigNumber() - { - return (class_exists('Moontoast\Math\BigNumber') && !self::$forceNoBigNumber); - } - - /** - * Returns true if the system has openssl_random_pseudo_bytes() - * - * @return bool - */ - protected static function hasOpensslRandomPseudoBytes() - { - return (function_exists('openssl_random_pseudo_bytes') && !self::$forceNoOpensslRandomPseudoBytes); - } - - /** - * Returns true if the system is 64-bit, false otherwise - * - * @return bool - */ - protected static function is64BitSystem() - { - return (PHP_INT_SIZE == 8 && !self::$force32Bit); - } - - /** - * Returns a version 3 or 5 UUID based on the hash (md5 or sha1) of a - * namespace identifier (which is a UUID) and a name (which is a string) - * - * @param string $hash The hash to use when creating the UUID - * @param int $version The UUID version to be generated - * @return Uuid - */ - protected static function uuidFromHashedName($hash, $version) - { - // Set the version number - $timeHi = hexdec(substr($hash, 12, 4)) & 0x0fff; - $timeHi &= ~(0xf000); - $timeHi |= $version << 12; - - // Set the variant to RFC 4122 - $clockSeqHi = hexdec(substr($hash, 16, 2)) & 0x3f; - $clockSeqHi &= ~(0xc0); - $clockSeqHi |= 0x80; - - $fields = array( - 'time_low' => substr($hash, 0, 8), - 'time_mid' => substr($hash, 8, 4), - 'time_hi_and_version' => sprintf('%04x', $timeHi), - 'clock_seq_hi_and_reserved' => sprintf('%02x', $clockSeqHi), - 'clock_seq_low' => substr($hash, 18, 2), - 'node' => substr($hash, 20, 12), - ); - - return new self($fields); - } - - /** - * Generates random bytes for use in version 4 UUIDs - * - * @param int $length - * @return string - */ - private static function generateBytes($length) - { - if (self::hasOpensslRandomPseudoBytes()) { - return openssl_random_pseudo_bytes($length); - } - - $bytes = ''; - for ($i = 1; $i <= $length; $i++) { - $bytes = chr(mt_rand(0, 255)) . $bytes; - } - - return $bytes; + return self::getFactory()->uuid5($ns, $name); } } diff --git a/src/UuidFactory.php b/src/UuidFactory.php new file mode 100644 index 0000000..44dcba4 --- /dev/null +++ b/src/UuidFactory.php @@ -0,0 +1,416 @@ + sprintf('%08x', $uuidTime & 0xffffffff), + 'mid' => sprintf('%04x', ($uuidTime >> 32) & 0xffff), + 'hi' => sprintf('%04x', ($uuidTime >> 48) & 0x0fff), + ); + } + + if (self::hasBigNumber()) { + + $uuidTime = new \Moontoast\Math\BigNumber('0'); + + $sec = new \Moontoast\Math\BigNumber($sec); + $sec->multiply('10000000'); + + $usec = new \Moontoast\Math\BigNumber($usec); + $usec->multiply('10'); + + $uuidTime->add($sec) + ->add($usec) + ->add('122192928000000000'); + + $uuidTimeHex = sprintf('%016s', $uuidTime->convertToBase(16)); + + return array( + 'low' => substr($uuidTimeHex, 8), + 'mid' => substr($uuidTimeHex, 4, 4), + 'hi' => substr($uuidTimeHex, 0, 4), + ); + } + + throw new Exception\UnsatisfiedDependencyException( + 'When calling ' . __METHOD__ . ' on a 32-bit system, ' + . 'Moontoast\Math\BigNumber must be present in order ' + . 'to generate version 1 UUIDs' + ); + } + + /** + * Get the hardware address as a 48-bit positive integer. If all attempts to + * obtain the hardware address fail, we choose a random 48-bit number with + * its eighth bit set to 1 as recommended in RFC 4122. "Hardware address" + * means the MAC address of a network interface, and on a machine with + * multiple network interfaces the MAC address of any one of them may be + * returned. + * + * @return string + */ + protected static function getNodeFromSystem() + { + $node = null; + $pattern = '/[^:]([0-9A-Fa-f]{2}([:-])[0-9A-Fa-f]{2}(\2[0-9A-Fa-f]{2}){4})[^:]/'; + $matches = array(); + + // Search the ifconfig output for all MAC addresses and return + // the first one found + if (preg_match_all($pattern, self::getIfconfig(), $matches, PREG_PATTERN_ORDER)) { + $node = $matches[1][0]; + $node = str_replace(':', '', $node); + $node = str_replace('-', '', $node); + } + + return $node; + } + + /** + * Returns the network interface configuration for the system + * + * @todo Needs evaluation and possibly modification to ensure this works + * well across multiple platforms. + * @codeCoverageIgnore + */ + protected static function getIfconfig() + { + switch (strtoupper(substr(php_uname('a'), 0, 3))) { + case 'WIN': + $ifconfig = `ipconfig /all 2>&1`; + break; + case 'DAR': + $ifconfig = `ifconfig 2>&1`; + break; + case 'LIN': + default: + $ifconfig = `netstat -ie 2>&1`; + break; + } + + return $ifconfig; + } + + /** + * Returns true if the system has Moontoast\Math\BigNumber + * + * @return bool + */ + protected static function hasBigNumber() + { + return (class_exists('Moontoast\Math\BigNumber') && !self::$forceNoBigNumber); + } + + /** + * Returns true if the system is 64-bit, false otherwise + * + * @return bool + */ + protected static function is64BitSystem() + { + return (PHP_INT_SIZE == 8 && !self::$force32Bit); + } + + + /** + * Generates random bytes for use in version 4 UUIDs + * + * @param int $length + * @return string + */ + private static function generateBytes($length) + { + if (! self::$prng) { + self::$prng = (new RandomGeneratorFactory())->getGenerator(); + } + + return self::$prng->generate($length); + } + + private $codec = null; + + public function __construct(Codec $uuidCodec = null, Codec $guidCodec = null) + { + $this->codec = $uuidCodec ?: new StringCodec($this); + $this->guidCodec = $guidCodec ?: new GuidStringCodec($this); + } + + /** + * Creates a UUID from a byte string. + * + * @param string $bytes + * @return Uuid + * @throws InvalidArgumentException If the $bytes string does not contain 16 characters + */ + public function fromBytes($bytes) + { + return $this->codec->decodeBytes($this->getConverter(), $bytes); + } + + public function fromGuidBytes($bytes) + { + return $this->guidCodec->decodeBytes($this->getConverter(), $bytes); + } + + /** + * Creates a UUID from the string standard representation as described + * in the toString() method. + * + * @param string $name A string that specifies a UUID + * @param bool $littleEndian A boolean specifying whether the time_low, time_mid, time_hi_and_version are encoded in little-endian format. + * @return Uuid + * @throws InvalidArgumentException If the $name isn't a valid UUID + */ + public function fromString($name) + { + return $this->codec->decode($this->getConverter(), $name); + } + + public function fromGuidString($name) + { + return $this->guidCodec->decode($this->getConverter(), $name); + } + + public function getConverter() + { + $converter = new BigNumberConverter(); + + if (! self::hasBigNumber()) { + $converter = new UnsatisfiedNumberConverter(); + } + + return $converter; + } + + /** + * Generate a version 1 UUID from a host ID, sequence number, and the current time. + * If $node is not given, we will attempt to obtain the local hardware + * address. If $clockSeq is given, it is used as the sequence number; + * otherwise a random 14-bit sequence number is chosen. + * + * @param int|string $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 + * could arise when the clock is set backwards in time + * or if the node ID changes. + * @return Uuid + * @throws InvalidArgumentException if the $node is invalid + */ + public function uuid1($node = null, $clockSeq = null) + { + if ($node === null && !self::$ignoreSystemNode) { + $node = self::getNodeFromSystem(); + } + + // if $node is still null (couldn't get from system), randomly generate + // a node value, according to RFC 4122, Section 4.5 + if ($node === null) { + $node = sprintf('%06x%06x', mt_rand(0, 1 << 24), mt_rand(0, 1 << 24)); + } + + // Convert the node to hex, if it is still an integer + if (is_int($node)) { + $node = sprintf('%012x', $node); + } + + if (ctype_xdigit($node) && strlen($node) <= 12) { + $node = strtolower(sprintf('%012s', $node)); + } else { + throw new \InvalidArgumentException('Invalid node value'); + } + + if ($clockSeq === null) { + // Not using "stable storage"; see RFC 4122, Section 4.2.1.1 + $clockSeq = mt_rand(0, 1 << 14); + } + + // Create a 60-bit time value as a count of 100-nanosecond intervals + // since 00:00:00.00, 15 October 1582 + if (self::$timeOfDayTest === null) { + $timeOfDay = gettimeofday(); + } else { + $timeOfDay = self::$timeOfDayTest; + } + + $uuidTime = self::calculateUuidTime($timeOfDay['sec'], $timeOfDay['usec']); + + // Set the version number to 1 + $timeHi = hexdec($uuidTime['hi']) & 0x0fff; + $timeHi &= ~(0xf000); + $timeHi |= 1 << 12; + + // Set the variant to RFC 4122 + $clockSeqHi = ($clockSeq >> 8) & 0x3f; + $clockSeqHi &= ~(0xc0); + $clockSeqHi |= 0x80; + + $fields = array( + 'time_low' => $uuidTime['low'], + 'time_mid' => $uuidTime['mid'], + 'time_hi_and_version' => sprintf('%04x', $timeHi), + 'clock_seq_hi_and_reserved' => sprintf('%02x', $clockSeqHi), + 'clock_seq_low' => sprintf('%02x', $clockSeq & 0xff), + 'node' => $node, + ); + + return $this->uuid($fields); + } + + + /** + * Generate a version 3 UUID based on the MD5 hash of a namespace identifier (which + * is a UUID) and a name (which is a string). + * + * @param Uuid|string $ns The UUID namespace in which to create the named UUID + * @param string $name The name to create a UUID for + * @return Uuid + */ + public function uuid3($ns, $name) + { + if (!($ns instanceof UuidInterface)) { + $ns = $this->codec->decode($this->getConverter(), $ns); + } + + $hash = md5($ns->getBytes() . $name); + + return $this->uuidFromHashedName($hash, 3); + } + + /** + * Generate a version 4 (random) UUID. + * + * @return Uuid + */ + public function uuid4() + { + $bytes = self::generateBytes(16); + + // When converting the bytes to hex, it turns into a 32-character + // hexadecimal string that looks a lot like an MD5 hash, so at this + // point, we can just pass it to uuidFromHashedName. + $hex = bin2hex($bytes); + return $this->uuidFromHashedName($hex, 4); + } + + /** + * Generate a version 5 UUID based on the SHA-1 hash of a namespace identifier (which + * is a UUID) and a name (which is a string). + * + * @param Uuid|string $ns The UUID namespace in which to create the named UUID + * @param string $name The name to create a UUID for + * @return Uuid + */ + public function uuid5($ns, $name) + { + if (!($ns instanceof Uuid)) { + $ns = $this->codec->decode($this->getConverter(), $ns); + } + + $hash = sha1($ns->getBytes() . $name); + + return $this->uuidFromHashedName($hash, 5); + } + + public function uuid(array $fields, Codec $codec = null) + { + $codec = $codec ?: $this->codec; + + if (! self::is64BitSystem()) { + return new SmallIntUuid($fields, $this->getConverter(), $codec); + } + + return new Uuid($fields, $this->getConverter(), $codec); + } + + /** + * Returns a version 3 or 5 UUID based on the hash (md5 or sha1) of a + * namespace identifier (which is a UUID) and a name (which is a string) + * + * @param string $hash The hash to use when creating the UUID + * @param int $version The UUID version to be generated + * @return Uuid + */ + protected function uuidFromHashedName($hash, $version) + { + // Set the version number + $timeHi = hexdec(substr($hash, 12, 4)) & 0x0fff; + $timeHi &= ~(0xf000); + $timeHi |= $version << 12; + + // Set the variant to RFC 4122 + $clockSeqHi = hexdec(substr($hash, 16, 2)) & 0x3f; + $clockSeqHi &= ~(0xc0); + $clockSeqHi |= 0x80; + + $fields = array( + 'time_low' => substr($hash, 0, 8), + 'time_mid' => substr($hash, 8, 4), + 'time_hi_and_version' => sprintf('%04x', $timeHi), + 'clock_seq_hi_and_reserved' => sprintf('%02x', $clockSeqHi), + 'clock_seq_low' => substr($hash, 18, 2), + 'node' => substr($hash, 20, 12), + ); + + return $this->uuid($fields); + } +} diff --git a/src/UuidInterface.php b/src/UuidInterface.php index f82f161..7858fee 100644 --- a/src/UuidInterface.php +++ b/src/UuidInterface.php @@ -9,6 +9,8 @@ interface UuidInterface public function equals($other); + public function getConverter(); + public function getHex(); public function getFieldsHex(); diff --git a/tests/Codec/GuidStringCodecTest.php b/tests/Codec/GuidStringCodecTest.php deleted file mode 100644 index 4187f6b..0000000 --- a/tests/Codec/GuidStringCodecTest.php +++ /dev/null @@ -1,18 +0,0 @@ -decode('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); - - $this->assertInstanceOf('\Rhumsaa\Uuid\Uuid', $uuid); - $this->assertEquals('ff6f8cb0-c57d-11e1-9b21-0800200c9a66', $uuid->toString()); - } -} diff --git a/tests/Codec/StringCodecTest.php b/tests/Codec/StringCodecTest.php deleted file mode 100644 index 5426b66..0000000 --- a/tests/Codec/StringCodecTest.php +++ /dev/null @@ -1,18 +0,0 @@ -decode('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); - - $this->assertInstanceOf('\Rhumsaa\Uuid\Uuid', $uuid); - $this->assertEquals('ff6f8cb0-c57d-11e1-9b21-0800200c9a66', $uuid->toString()); - } -} diff --git a/tests/RandomGeneratorFactoryTest.php b/tests/RandomGeneratorFactoryTest.php new file mode 100644 index 0000000..130b7eb --- /dev/null +++ b/tests/RandomGeneratorFactoryTest.php @@ -0,0 +1,24 @@ +assertNotInstanceOf('\Rhumsaa\Uuid\Generator\OpenSslGenerator', $generator); + } + + public function testFactoryReturnsOpenSslGeneratorIfAvailable() + { + RandomGeneratorFactory::$forceNoOpensslRandomPseudoBytes = false; + + $generator = RandomGeneratorFactory::getGenerator(); + + $this->assertInstanceOf('\Rhumsaa\Uuid\Generator\OpenSslGenerator', $generator); + } +} diff --git a/tests/UnsatisfiedNumberConverterTest.php b/tests/UnsatisfiedNumberConverterTest.php new file mode 100644 index 0000000..32f8a52 --- /dev/null +++ b/tests/UnsatisfiedNumberConverterTest.php @@ -0,0 +1,16 @@ +fromHex('ffff'); + } +} diff --git a/tests/UuidBcTag1_1_2Test.php b/tests/UuidBcTag1_1_2Test.php index 1cd789f..fde737c 100644 --- a/tests/UuidBcTag1_1_2Test.php +++ b/tests/UuidBcTag1_1_2Test.php @@ -21,8 +21,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::fromString - * @covers Rhumsaa\Uuid\Uuid::__construct */ public function testFromString() { @@ -32,7 +30,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::fromString */ public function testFromStringWithCurlyBraces() { @@ -42,7 +39,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::fromString * @expectedException InvalidArgumentException * @expectedExceptionMessage Invalid UUID string: */ @@ -52,7 +48,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::fromString */ public function testFromStringWithUrn() { @@ -62,7 +57,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getBytes */ public function testGetBytes() { @@ -71,7 +65,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getClockSeqHiAndReserved */ public function testGetClockSeqHiAndReserved() { @@ -80,7 +73,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getClockSeqLow */ public function testGetClockSeqLow() { @@ -89,7 +81,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getClockSequence */ public function testGetClockSequence() { @@ -98,7 +89,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getDateTime */ public function testGetDateTime() { @@ -114,8 +104,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getDateTime - * @covers Rhumsaa\Uuid\Exception\UnsupportedOperationException * @expectedException Rhumsaa\Uuid\Exception\UnsupportedOperationException * @expectedExceptionMessage Not a time-based UUID */ @@ -127,7 +115,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getFields */ public function testGetFields() { @@ -141,7 +128,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getLeastSignificantBits */ public function testGetLeastSignificantBits() { @@ -158,7 +144,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getMostSignificantBits */ public function testGetMostSignificantBits() { @@ -175,7 +160,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getNode */ public function testGetNode() { @@ -184,7 +168,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getTimeHiAndVersion */ public function testGetTimeHiAndVersion() { @@ -193,7 +176,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getTimeLow */ public function testGetTimeLow() { @@ -202,7 +184,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getTimeMid */ public function testGetTimeMid() { @@ -211,7 +192,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getTimestamp */ public function testGetTimestamp() { @@ -225,8 +205,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getTimestamp - * @covers Rhumsaa\Uuid\Exception\UnsupportedOperationException * @expectedException Rhumsaa\Uuid\Exception\UnsupportedOperationException * @expectedExceptionMessage Not a time-based UUID */ @@ -238,7 +216,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getUrn */ public function testGetUrn() { @@ -247,7 +224,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVariant */ public function testGetVariantForReservedNcs() { @@ -277,7 +253,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVariant */ public function testGetVariantForRfc4122() { @@ -295,7 +270,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVariant */ public function testGetVariantForReservedMicrosoft() { @@ -307,7 +281,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVariant */ public function testGetVariantForReservedFuture() { @@ -319,7 +292,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVersion */ public function testGetVersionForVersion1() { @@ -328,7 +300,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVersion */ public function testGetVersionForVersion2() { @@ -337,7 +308,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVersion */ public function testGetVersionForVersion3() { @@ -346,7 +316,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVersion */ public function testGetVersionForVersion4() { @@ -355,7 +324,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVersion */ public function testGetVersionForVersion5() { @@ -364,8 +332,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::toString - * @covers Rhumsaa\Uuid\Uuid::__toString */ public function testToString() { @@ -381,8 +347,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid1 - * @covers Rhumsaa\Uuid\Uuid::getNodeFromSystem */ public function testUuid1() { @@ -394,7 +358,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid1 */ public function testUuid1WithNodeAndClockSequence() { @@ -409,11 +372,10 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid1 */ public function testUuid1WithRandomNode() { - Uuid::$ignoreSystemNode = true; + UuidFactory::$ignoreSystemNode = true; $uuid = Uuid::uuid1(); $this->assertInstanceOf('\Rhumsaa\Uuid\Uuid', $uuid); @@ -427,8 +389,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase * library generates a matching UUID for the same name. * @see http://docs.python.org/library/uuid.html * - * @covers Rhumsaa\Uuid\Uuid::uuid3 - * @covers Rhumsaa\Uuid\Uuid::uuidFromHashedName */ public function testUuid3WithNamespaceAsUuidObject() { @@ -444,8 +404,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase * library generates a matching UUID for the same name. * @see http://docs.python.org/library/uuid.html * - * @covers Rhumsaa\Uuid\Uuid::uuid3 - * @covers Rhumsaa\Uuid\Uuid::uuidFromHashedName */ public function testUuid3WithNamespaceAsUuidString() { @@ -456,8 +414,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid4 - * @covers Rhumsaa\Uuid\Uuid::uuidFromHashedName */ public function testUuid4() { @@ -472,8 +428,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase * library generates a matching UUID for the same name. * @see http://docs.python.org/library/uuid.html * - * @covers Rhumsaa\Uuid\Uuid::uuid5 - * @covers Rhumsaa\Uuid\Uuid::uuidFromHashedName */ public function testUuid5WithNamespaceAsUuidObject() { @@ -489,8 +443,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase * library generates a matching UUID for the same name. * @see http://docs.python.org/library/uuid.html * - * @covers Rhumsaa\Uuid\Uuid::uuid5 - * @covers Rhumsaa\Uuid\Uuid::uuidFromHashedName */ public function testUuid5WithNamespaceAsUuidString() { @@ -501,7 +453,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::compareTo */ public function testCompareTo() { @@ -530,7 +481,6 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::equals */ public function testEquals() { diff --git a/tests/UuidFactoryTest.php b/tests/UuidFactoryTest.php new file mode 100644 index 0000000..c53d757 --- /dev/null +++ b/tests/UuidFactoryTest.php @@ -0,0 +1,24 @@ +fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); + + $this->assertEquals('ff6f8cb0-c57d-11e1-9b21-0800200c9a66', $uuid->toString()); + } + + public function testParsesGuidCorrectly() + { + $factory = new UuidFactory(); + + $uuid = $factory->fromGuidString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); + + $this->assertEquals('ff6f8cb0-c57d-11e1-9b21-0800200c9a66', $uuid->toString()); + } +} diff --git a/tests/UuidTest.php b/tests/UuidTest.php index a601b20..c7e8f2e 100644 --- a/tests/UuidTest.php +++ b/tests/UuidTest.php @@ -1,20 +1,21 @@ skipIfNoMoontoastMath(); - Uuid::$force32Bit = true; + UuidFactory::$force32Bit = true; // Check a recent date $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); @@ -188,21 +176,22 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getDateTime * @expectedException Rhumsaa\Uuid\Exception\UnsatisfiedDependencyException */ public function testGetDateTimeThrownException() { - Uuid::$force32Bit = true; - Uuid::$forceNoBigNumber = true; + UuidFactory::$force32Bit = true; + UuidFactory::$forceNoBigNumber = true; $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); + + $this->assertInstanceOf('Rhumsaa\Uuid\SmallIntUuid', $uuid); + $this->assertInstanceOf('Rhumsaa\Uuid\UnsatisfiedNumberConverter', $uuid->getConverter()); + $date = $uuid->getDateTime(); } /** - * @covers Rhumsaa\Uuid\Uuid::getDateTime - * @covers Rhumsaa\Uuid\Exception\UnsupportedOperationException * @expectedException Rhumsaa\Uuid\Exception\UnsupportedOperationException * @expectedExceptionMessage Not a time-based UUID */ @@ -214,7 +203,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getFields */ public function testGetFields() { @@ -235,18 +223,16 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getFields * @expectedException Rhumsaa\Uuid\Exception\UnsatisfiedDependencyException */ public function testGetFields32Bit() { - Uuid::$force32Bit = true; + UuidFactory::$force32Bit = true; $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); $fields = $uuid->getFields(); } /** - * @covers Rhumsaa\Uuid\Uuid::getFieldsHex */ public function testGetFieldsHex() { @@ -265,7 +251,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getLeastSignificantBits */ public function testGetLeastSignificantBits() { @@ -277,18 +262,16 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getLeastSignificantBits * @expectedException Rhumsaa\Uuid\Exception\UnsatisfiedDependencyException */ public function testGetLeastSignificantBitsException() { - Uuid::$forceNoBigNumber = true; + UuidFactory::$forceNoBigNumber = true; $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); $bn = $uuid->getLeastSignificantBits(); } /** - * @covers Rhumsaa\Uuid\Uuid::getLeastSignificantBitsHex */ public function testGetLeastSignificantBitsHex() { @@ -297,7 +280,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getMostSignificantBits */ public function testGetMostSignificantBits() { @@ -309,18 +291,16 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getMostSignificantBits * @expectedException Rhumsaa\Uuid\Exception\UnsatisfiedDependencyException */ public function testGetMostSignificantBitsException() { - Uuid::$forceNoBigNumber = true; + UuidFactory::$forceNoBigNumber = true; $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); $bn = $uuid->getMostSignificantBits(); } /** - * @covers Rhumsaa\Uuid\Uuid::getMostSignificantBitsHex */ public function testGetMostSignificantBitsHex() { @@ -329,7 +309,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getNode */ public function testGetNode() { @@ -340,18 +319,16 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getNode * @expectedException Rhumsaa\Uuid\Exception\UnsatisfiedDependencyException */ public function testGetNode32Bit() { - Uuid::$force32Bit = true; + UuidFactory::$force32Bit = true; $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); $node = $uuid->getNode(); } /** - * @covers Rhumsaa\Uuid\Uuid::getNodeHex */ public function testGetNodeHex() { @@ -360,7 +337,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getTimeHiAndVersion */ public function testGetTimeHiAndVersion() { @@ -369,7 +345,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getTimeHiAndVersionHex */ public function testGetTimeHiAndVersionHex() { @@ -378,7 +353,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getTimeLow */ public function testGetTimeLow() { @@ -389,18 +363,16 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getTimeLow * @expectedException Rhumsaa\Uuid\Exception\UnsatisfiedDependencyException */ public function testGetTimeLow32Bit() { - Uuid::$force32Bit = true; + UuidFactory::$force32Bit = true; $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); $timeLow = $uuid->getTimeLow(); } /** - * @covers Rhumsaa\Uuid\Uuid::getTimeLowHex */ public function testGetTimeLowHex() { @@ -409,7 +381,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getTimeMid */ public function testGetTimeMid() { @@ -418,7 +389,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getTimeMidHex */ public function testGetTimeMidHex() { @@ -427,7 +397,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getTimestamp */ public function testGetTimestamp() { @@ -443,7 +412,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getTimestampHex */ public function testGetTimestampHex() { @@ -457,8 +425,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getTimestamp - * @covers Rhumsaa\Uuid\Exception\UnsupportedOperationException * @expectedException Rhumsaa\Uuid\Exception\UnsupportedOperationException * @expectedExceptionMessage Not a time-based UUID */ @@ -470,8 +436,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getTimestampHex - * @covers Rhumsaa\Uuid\Exception\UnsupportedOperationException * @expectedException Rhumsaa\Uuid\Exception\UnsupportedOperationException * @expectedExceptionMessage Not a time-based UUID */ @@ -483,18 +447,16 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getTimestamp * @expectedException Rhumsaa\Uuid\Exception\UnsatisfiedDependencyException */ public function testGetTimestamp32Bit() { - Uuid::$force32Bit = true; + UuidFactory::$force32Bit = true; $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); $ts = $uuid->getTimestamp(); } /** - * @covers Rhumsaa\Uuid\Uuid::getUrn */ public function testGetUrn() { @@ -503,7 +465,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVariant */ public function testGetVariantForReservedNcs() { @@ -533,7 +494,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVariant */ public function testGetVariantForRfc4122() { @@ -551,7 +511,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVariant */ public function testGetVariantForReservedMicrosoft() { @@ -563,7 +522,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVariant */ public function testGetVariantForReservedFuture() { @@ -575,7 +533,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVersion */ public function testGetVersionForVersion1() { @@ -584,7 +541,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVersion */ public function testGetVersionForVersion2() { @@ -593,7 +549,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVersion */ public function testGetVersionForVersion3() { @@ -602,7 +557,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVersion */ public function testGetVersionForVersion4() { @@ -611,7 +565,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getVersion */ public function testGetVersionForVersion5() { @@ -620,8 +573,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::toString - * @covers Rhumsaa\Uuid\Uuid::__toString */ public function testToString() { @@ -637,8 +588,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid1 - * @covers Rhumsaa\Uuid\Uuid::getNodeFromSystem */ public function testUuid1() { @@ -650,7 +599,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid1 */ public function testUuid1WithNodeAndClockSequence() { @@ -667,7 +615,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid1 */ public function testUuid1WithHexadecimalNode() { @@ -685,7 +632,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid1 */ public function testUuid1WithMixedCaseHexadecimalNode() { @@ -703,7 +649,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid1 */ public function testUuid1WithNodeAndClockSequence32Bit() { @@ -722,7 +667,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid1 * @expectedException InvalidArgumentException * @expectedExceptionMessage Invalid node value */ @@ -732,7 +676,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid1 * @expectedException InvalidArgumentException * @expectedExceptionMessage Invalid node value */ @@ -742,7 +685,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid1 * @expectedException InvalidArgumentException * @expectedExceptionMessage Invalid node value */ @@ -751,12 +693,9 @@ class UuidTest extends TestCase $uuid = Uuid::uuid1('db77e160355ef'); } - /** - * @covers Rhumsaa\Uuid\Uuid::uuid1 - */ public function testUuid1WithRandomNode() { - Uuid::$ignoreSystemNode = true; + UuidFactory::$ignoreSystemNode = true; $uuid = Uuid::uuid1(); $this->assertInstanceOf('\Rhumsaa\Uuid\Uuid', $uuid); @@ -770,8 +709,6 @@ class UuidTest extends TestCase * library generates a matching UUID for the same name. * @see http://docs.python.org/library/uuid.html * - * @covers Rhumsaa\Uuid\Uuid::uuid3 - * @covers Rhumsaa\Uuid\Uuid::uuidFromHashedName */ public function testUuid3WithNamespaceAsUuidObject() { @@ -787,8 +724,6 @@ class UuidTest extends TestCase * library generates a matching UUID for the same name. * @see http://docs.python.org/library/uuid.html * - * @covers Rhumsaa\Uuid\Uuid::uuid3 - * @covers Rhumsaa\Uuid\Uuid::uuidFromHashedName */ public function testUuid3WithNamespaceAsUuidString() { @@ -804,7 +739,6 @@ class UuidTest extends TestCase * Taken from the Python UUID tests in * http://hg.python.org/cpython/file/2f4c4db9aee5/Lib/test/test_uuid.py * - * @covers Rhumsaa\Uuid\Uuid::uuid3 */ public function testUuid3WithKnownUuids() { @@ -824,9 +758,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid4 - * @covers Rhumsaa\Uuid\Uuid::generateBytes - * @covers Rhumsaa\Uuid\Uuid::uuidFromHashedName */ public function testUuid4() { @@ -837,13 +768,10 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid4 - * @covers Rhumsaa\Uuid\Uuid::generateBytes - * @covers Rhumsaa\Uuid\Uuid::uuidFromHashedName */ public function testUuid4WithoutOpensslRandomPseudoBytes() { - Uuid::$forceNoOpensslRandomPseudoBytes = true; + RandomGeneratorFactory::$forceNoOpensslRandomPseudoBytes = true; $uuid = Uuid::uuid4(); $this->assertInstanceOf('Rhumsaa\Uuid\Uuid', $uuid); $this->assertEquals(2, $uuid->getVariant()); @@ -855,8 +783,6 @@ class UuidTest extends TestCase * library generates a matching UUID for the same name. * @see http://docs.python.org/library/uuid.html * - * @covers Rhumsaa\Uuid\Uuid::uuid5 - * @covers Rhumsaa\Uuid\Uuid::uuidFromHashedName */ public function testUuid5WithNamespaceAsUuidObject() { @@ -872,8 +798,6 @@ class UuidTest extends TestCase * library generates a matching UUID for the same name. * @see http://docs.python.org/library/uuid.html * - * @covers Rhumsaa\Uuid\Uuid::uuid5 - * @covers Rhumsaa\Uuid\Uuid::uuidFromHashedName */ public function testUuid5WithNamespaceAsUuidString() { @@ -889,7 +813,6 @@ class UuidTest extends TestCase * Taken from the Python UUID tests in * http://hg.python.org/cpython/file/2f4c4db9aee5/Lib/test/test_uuid.py * - * @covers Rhumsaa\Uuid\Uuid::uuid5 */ public function testUuid5WithKnownUuids() { @@ -909,7 +832,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::compareTo */ public function testCompareTo() { @@ -938,7 +860,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::equals */ public function testEquals() { @@ -953,8 +874,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid1 - * @covers Rhumsaa\Uuid\Uuid::calculateUuidTime */ public function testCalculateUuidTime() { @@ -966,7 +885,7 @@ class UuidTest extends TestCase ); // For usec = 277885 - Uuid::$timeOfDayTest = $timeOfDay; + UuidFactory::$timeOfDayTest = $timeOfDay; $uuidA = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('c4dbe7e2-097f-11e2-9669-00007ffffffe', (string) $uuidA); @@ -975,7 +894,7 @@ class UuidTest extends TestCase $this->assertEquals('11e2', $uuidA->getTimeHiAndVersionHex()); // For usec = 0 - Uuid::$timeOfDayTest['usec'] = 0; + UuidFactory::$timeOfDayTest['usec'] = 0; $uuidB = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('c4b18100-097f-11e2-9669-00007ffffffe', (string) $uuidB); @@ -984,7 +903,7 @@ class UuidTest extends TestCase $this->assertEquals('11e2', $uuidB->getTimeHiAndVersionHex()); // For usec = 999999 - Uuid::$timeOfDayTest['usec'] = 999999; + UuidFactory::$timeOfDayTest['usec'] = 999999; $uuidC = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('c54a1776-097f-11e2-9669-00007ffffffe', (string) $uuidC); @@ -994,13 +913,11 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid1 - * @covers Rhumsaa\Uuid\Uuid::calculateUuidTime */ public function testCalculateUuidTimeForce32BitPath() { $this->skipIfNoMoontoastMath(); - Uuid::$force32Bit = true; + UuidFactory::$force32Bit = true; $timeOfDay = array( 'sec' => 1348845514, @@ -1010,7 +927,7 @@ class UuidTest extends TestCase ); // For usec = 277885 - Uuid::$timeOfDayTest = $timeOfDay; + UuidFactory::$timeOfDayTest = $timeOfDay; $uuidA = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('c4dbe7e2-097f-11e2-9669-00007ffffffe', (string) $uuidA); @@ -1019,7 +936,7 @@ class UuidTest extends TestCase $this->assertEquals('11e2', $uuidA->getTimeHiAndVersionHex()); // For usec = 0 - Uuid::$timeOfDayTest['usec'] = 0; + UuidFactory::$timeOfDayTest['usec'] = 0; $uuidB = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('c4b18100-097f-11e2-9669-00007ffffffe', (string) $uuidB); @@ -1028,7 +945,7 @@ class UuidTest extends TestCase $this->assertEquals('11e2', $uuidB->getTimeHiAndVersionHex()); // For usec = 999999 - Uuid::$timeOfDayTest['usec'] = 999999; + UuidFactory::$timeOfDayTest['usec'] = 999999; $uuidC = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('c54a1776-097f-11e2-9669-00007ffffffe', (string) $uuidC); @@ -1038,8 +955,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid1 - * @covers Rhumsaa\Uuid\Uuid::calculateUuidTime */ public function testCalculateUuidTimeUpperLowerBounds64Bit() { @@ -1053,7 +968,7 @@ class UuidTest extends TestCase 'dsttime' => 0, ); - Uuid::$timeOfDayTest = $timeOfDay; + UuidFactory::$timeOfDayTest = $timeOfDay; $uuidA = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('ff9785f6-ffff-1fff-9669-00007ffffffe', (string) $uuidA); @@ -1069,7 +984,7 @@ class UuidTest extends TestCase 'dsttime' => 0, ); - Uuid::$timeOfDayTest = $timeOfDay; + UuidFactory::$timeOfDayTest = $timeOfDay; $uuidB = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('00000000-0000-1000-9669-00007ffffffe', (string) $uuidB); @@ -1082,15 +997,13 @@ class UuidTest extends TestCase * This test ensures that the UUIDs generated by the 32-bit path match * those generated by the 64-bit path, given the same 64-bit time values. * - * @covers Rhumsaa\Uuid\Uuid::uuid1 - * @covers Rhumsaa\Uuid\Uuid::calculateUuidTime */ public function testCalculateUuidTimeUpperLowerBounds64BitThrough32BitPath() { $this->skipIfNoMoontoastMath(); $this->skip64BitTest(); - Uuid::$force32Bit = true; + UuidFactory::$force32Bit = true; // 5235-03-31T21:20:59+00:00 $timeOfDay = array( @@ -1100,7 +1013,7 @@ class UuidTest extends TestCase 'dsttime' => 0, ); - Uuid::$timeOfDayTest = $timeOfDay; + UuidFactory::$timeOfDayTest = $timeOfDay; $uuidA = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('ff9785f6-ffff-1fff-9669-00007ffffffe', (string) $uuidA); @@ -1116,7 +1029,7 @@ class UuidTest extends TestCase 'dsttime' => 0, ); - Uuid::$timeOfDayTest = $timeOfDay; + UuidFactory::$timeOfDayTest = $timeOfDay; $uuidB = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('00000000-0000-1000-9669-00007ffffffe', (string) $uuidB); @@ -1126,13 +1039,11 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::uuid1 - * @covers Rhumsaa\Uuid\Uuid::calculateUuidTime */ public function testCalculateUuidTimeUpperLowerBounds32Bit() { $this->skipIfNoMoontoastMath(); - Uuid::$force32Bit = true; + UuidFactory::$force32Bit = true; // 2038-01-19T03:14:07+00:00 $timeOfDay = array( @@ -1142,7 +1053,7 @@ class UuidTest extends TestCase 'dsttime' => 0, ); - Uuid::$timeOfDayTest = $timeOfDay; + UuidFactory::$timeOfDayTest = $timeOfDay; $uuidA = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('13813ff6-6912-11fe-9669-00007ffffffe', (string) $uuidA); @@ -1158,7 +1069,7 @@ class UuidTest extends TestCase 'dsttime' => 0, ); - Uuid::$timeOfDayTest = $timeOfDay; + UuidFactory::$timeOfDayTest = $timeOfDay; $uuidB = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('1419d680-d292-1165-9669-00007ffffffe', (string) $uuidB); @@ -1171,8 +1082,6 @@ class UuidTest extends TestCase * This test ensures that the UUIDs generated by the 64-bit path match * those generated by the 32-bit path, given the same 32-bit time values. * - * @covers Rhumsaa\Uuid\Uuid::uuid1 - * @covers Rhumsaa\Uuid\Uuid::calculateUuidTime */ public function testCalculateUuidTimeUpperLowerBounds32BitThrough64BitPath() { @@ -1186,7 +1095,7 @@ class UuidTest extends TestCase 'dsttime' => 0, ); - Uuid::$timeOfDayTest = $timeOfDay; + UuidFactory::$timeOfDayTest = $timeOfDay; $uuidA = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('13813ff6-6912-11fe-9669-00007ffffffe', (string) $uuidA); @@ -1202,7 +1111,7 @@ class UuidTest extends TestCase 'dsttime' => 0, ); - Uuid::$timeOfDayTest = $timeOfDay; + UuidFactory::$timeOfDayTest = $timeOfDay; $uuidB = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('1419d680-d292-1165-9669-00007ffffffe', (string) $uuidB); @@ -1234,12 +1143,12 @@ class UuidTest extends TestCase 'dsttime' => 0, ); - Uuid::$timeOfDayTest = $timeOfDay; + UuidFactory::$timeOfDayTest = $timeOfDay; - Uuid::$force32Bit = true; + UuidFactory::$force32Bit = true; $uuid32 = Uuid::uuid1(0x00007ffffffe, 0x1669); - Uuid::$force32Bit = false; + UuidFactory::$force32Bit = false; $uuid64 = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertTrue( @@ -1258,79 +1167,17 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::calculateUuidTime * @expectedException Rhumsaa\Uuid\Exception\UnsatisfiedDependencyException */ public function testCalculateUuidTimeThrownException() { - Uuid::$force32Bit = true; - Uuid::$forceNoBigNumber = true; + UuidFactory::$force32Bit = true; + UuidFactory::$forceNoBigNumber = true; $uuid = Uuid::uuid1(0x00007ffffffe, 0x1669); } /** - * @covers Rhumsaa\Uuid\Uuid::hasBigNumber - */ - public function testHasBigNumber() - { - $this->skipIfNoMoontoastMath(); - - $hasBigNumber = new \ReflectionMethod( - 'Rhumsaa\Uuid\Uuid', 'hasBigNumber' - ); - $hasBigNumber->setAccessible(true); - - $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); - - $this->assertTrue($hasBigNumber->invoke($uuid)); - - Uuid::$forceNoBigNumber = true; - $this->assertFalse($hasBigNumber->invoke($uuid)); - } - - /** - * @covers Rhumsaa\Uuid\Uuid::hasOpensslRandomPseudoBytes - */ - public function testHasOpensslRandomPseudoBytes() - { - $hasOpensslRandomPseudoBytes = new \ReflectionMethod( - 'Rhumsaa\Uuid\Uuid', 'hasOpensslRandomPseudoBytes' - ); - $hasOpensslRandomPseudoBytes->setAccessible(true); - - $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); - - $this->assertTrue($hasOpensslRandomPseudoBytes->invoke($uuid)); - - Uuid::$forceNoOpensslRandomPseudoBytes = true; - $this->assertFalse($hasOpensslRandomPseudoBytes->invoke($uuid)); - } - - /** - * @covers Rhumsaa\Uuid\Uuid::is64BitSystem - */ - public function testIs64BitSystem() - { - $is64BitSystem = new \ReflectionMethod( - 'Rhumsaa\Uuid\Uuid', 'is64BitSystem' - ); - $is64BitSystem->setAccessible(true); - - $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); - - if (PHP_INT_SIZE == 8) { - $this->assertTrue($is64BitSystem->invoke($uuid)); - } else { - $this->assertFalse($is64BitSystem->invoke($uuid)); - } - - Uuid::$force32Bit = true; - $this->assertFalse($is64BitSystem->invoke($uuid)); - } - - /** - * @covers Rhumsaa\Uuid\Uuid::isValid */ public function testIsValidGoodVersion1() { @@ -1339,7 +1186,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::isValid */ public function testIsValidGoodVersion2() { @@ -1348,7 +1194,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::isValid */ public function testIsValidGoodVersion3() { @@ -1357,7 +1202,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::isValid */ public function testIsValidGoodVersion4() { @@ -1366,7 +1210,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::isValid */ public function testIsValidGoodVersion5() { @@ -1375,7 +1218,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::isValid */ public function testIsValidGoodUpperCase() { @@ -1384,7 +1226,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::isValid */ public function testIsValidBadHex() { @@ -1393,7 +1234,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::isValid */ public function testIsValidTooShort1() { @@ -1402,7 +1242,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::isValid */ public function testIsValidTooShort2() { @@ -1411,7 +1250,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::isValid */ public function testIsValidNoDashes() { @@ -1420,7 +1258,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::isValid */ public function testIsValidTooLong() { @@ -1429,7 +1266,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::isValid */ public function testUsingNilAsValidUuid() { @@ -1438,7 +1274,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::fromBytes */ public function testFromBytes() { @@ -1471,7 +1306,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::fromBytes * @expectedException InvalidArgumentException */ public function testFromBytesArgumentTooShort() @@ -1480,7 +1314,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::fromBytes * @expectedException InvalidArgumentException */ public function testFromBytesArgumentTooLong() @@ -1522,25 +1355,6 @@ class UuidTest extends TestCase * Taken from the Python UUID tests in * http://hg.python.org/cpython/file/2f4c4db9aee5/Lib/test/test_uuid.py * - * @covers Rhumsaa\Uuid\Uuid::fromString - * @covers Rhumsaa\Uuid\Uuid::fromBytes - * @covers Rhumsaa\Uuid\Uuid::fromInteger - * @covers Rhumsaa\Uuid\Uuid::toString - * @covers Rhumsaa\Uuid\Uuid::getBytes - * @covers Rhumsaa\Uuid\Uuid::getFieldsHex - * @covers Rhumsaa\Uuid\Uuid::getHex - * @covers Rhumsaa\Uuid\Uuid::getInteger - * @covers Rhumsaa\Uuid\Uuid::getTimeLowHex - * @covers Rhumsaa\Uuid\Uuid::getTimeMidHex - * @covers Rhumsaa\Uuid\Uuid::getTimeHiAndVersionHex - * @covers Rhumsaa\Uuid\Uuid::getClockSeqHiAndReservedHex - * @covers Rhumsaa\Uuid\Uuid::getClockSeqLowHex - * @covers Rhumsaa\Uuid\Uuid::getNodeHex - * @covers Rhumsaa\Uuid\Uuid::getUrn - * @covers Rhumsaa\Uuid\Uuid::getTimestampHex - * @covers Rhumsaa\Uuid\Uuid::getClockSequenceHex - * @covers Rhumsaa\Uuid\Uuid::getVariant - * @covers Rhumsaa\Uuid\Uuid::getVersion */ public function testUuidPassesPythonTests() { @@ -1863,13 +1677,12 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::getInteger * @expectedException Rhumsaa\Uuid\Exception\UnsatisfiedDependencyException - * @expectedExceptionMessage Cannot call Rhumsaa\Uuid\Uuid::getInteger without support for large integers + * @expectedExceptionMessage Cannot call Rhumsaa\Uuid\UnsatisfiedNumberConverter::fromHex without support for large integers */ public function testGetInteger() { - Uuid::$forceNoBigNumber = true; + UuidFactory::$forceNoBigNumber = true; $uuid = Uuid::uuid1(); $uuid->getInteger(); diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 50e981f..7c57d53 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -17,3 +17,9 @@ $loader = include realpath(dirname(__FILE__) . '/../vendor/autoload.php'); $loader->add("Doctrine\Tests\DBAL", __DIR__."/../vendor/doctrine/dbal/tests"); $loader->addPsr4('Rhumsaa\\Uuid\\', __DIR__); + +register_shutdown_function(function() { + if ($error = error_get_last()) { + var_dump($error); + } +}); From 053a25f335f8e2ee0fb3cb0b9a84a631fd1f0047 Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Thu, 30 Oct 2014 13:41:17 +0100 Subject: [PATCH 07/30] Remove 5.3 build & debug info --- tests/bootstrap.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 7c57d53..50e981f 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -17,9 +17,3 @@ $loader = include realpath(dirname(__FILE__) . '/../vendor/autoload.php'); $loader->add("Doctrine\Tests\DBAL", __DIR__."/../vendor/doctrine/dbal/tests"); $loader->addPsr4('Rhumsaa\\Uuid\\', __DIR__); - -register_shutdown_function(function() { - if ($error = error_get_last()) { - var_dump($error); - } -}); From 653349f4907be7b8deb487f45a28f292dc39a5d6 Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Thu, 30 Oct 2014 15:26:30 +0100 Subject: [PATCH 08/30] Remove final keyword (rebase error...) --- src/Uuid.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Uuid.php b/src/Uuid.php index 82abc22..1a56aca 100644 --- a/src/Uuid.php +++ b/src/Uuid.php @@ -32,7 +32,7 @@ use Rhumsaa\Uuid\Codec\StringCodec; * @link http://docs.oracle.com/javase/6/docs/api/java/util/UUID.html */ -final class Uuid implements UuidInterface, \JsonSerializable +class Uuid implements UuidInterface, \JsonSerializable { /** * When this namespace is specified, the name string is a fully-qualified domain name. From cd3e58b1f59d156db318ba9937332473ddb17562 Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Thu, 30 Oct 2014 16:07:48 +0100 Subject: [PATCH 09/30] Refactor fromInteger method to use factory --- src/BigNumberConverter.php | 9 +++++++++ src/UnsatisfiedNumberConverter.php | 9 +++++++++ src/Uuid.php | 17 +---------------- src/UuidFactory.php | 8 ++++++++ tests/UuidTest.php | 3 --- 5 files changed, 27 insertions(+), 19 deletions(-) diff --git a/src/BigNumberConverter.php b/src/BigNumberConverter.php index 349ea33..0e1b3fd 100644 --- a/src/BigNumberConverter.php +++ b/src/BigNumberConverter.php @@ -10,4 +10,13 @@ class BigNumberConverter return new \Moontoast\Math\BigNumber($number); } + + public function toHex($integer) + { + if (!$integer instanceof \Moontoast\Math\BigNumber) { + $integer = new \Moontoast\Math\BigNumber($integer); + } + + return \Moontoast\Math\BigNumber::baseConvert($integer, 10, 16); + } } diff --git a/src/UnsatisfiedNumberConverter.php b/src/UnsatisfiedNumberConverter.php index e6b7119..cc933b3 100644 --- a/src/UnsatisfiedNumberConverter.php +++ b/src/UnsatisfiedNumberConverter.php @@ -13,4 +13,13 @@ class UnsatisfiedNumberConverter extends BigNumberConverter . '; consider calling an hex based method instead' ); } + + public function toHex($integer) + { + throw new Exception\UnsatisfiedDependencyException( + 'Cannot call ' . __METHOD__ . ' without support for large ' + . 'integers, since integer is an unsigned ' + . '128-bit integer; Moontoast\Math\BigNumber is required. ' + ); + } } diff --git a/src/Uuid.php b/src/Uuid.php index 1a56aca..3a0a614 100644 --- a/src/Uuid.php +++ b/src/Uuid.php @@ -777,22 +777,7 @@ class Uuid implements UuidInterface, \JsonSerializable */ public static function fromInteger($integer) { - if (!self::hasBigNumber()) { - throw new Exception\UnsatisfiedDependencyException( - 'Cannot call ' . __METHOD__ . ' without support for large ' - . 'integers, since integer is an unsigned ' - . '128-bit integer; Moontoast\Math\BigNumber is required. ' - ); - } - - if (!$integer instanceof \Moontoast\Math\BigNumber) { - $integer = new \Moontoast\Math\BigNumber($integer); - } - - $hex = \Moontoast\Math\BigNumber::baseConvert($integer, 10, 16); - $hex = str_pad($hex, 32, '0', STR_PAD_LEFT); - - return self::fromString($hex); + return self::getFactory()->fromInteger($integer); } /** diff --git a/src/UuidFactory.php b/src/UuidFactory.php index 44dcba4..f2dd6a5 100644 --- a/src/UuidFactory.php +++ b/src/UuidFactory.php @@ -230,6 +230,14 @@ class UuidFactory return $this->guidCodec->decode($this->getConverter(), $name); } + public function fromInteger($integer) + { + $hex = $this->getConverter()->toHex($integer); + $hex = str_pad($hex, 32, '0', STR_PAD_LEFT); + + return $this->fromString($hex); + } + public function getConverter() { $converter = new BigNumberConverter(); diff --git a/tests/UuidTest.php b/tests/UuidTest.php index c7e8f2e..f330690 100644 --- a/tests/UuidTest.php +++ b/tests/UuidTest.php @@ -1322,7 +1322,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::fromInteger */ public function testFromIntegerBigNumber() { @@ -1335,7 +1334,6 @@ class UuidTest extends TestCase } /** - * @covers Rhumsaa\Uuid\Uuid::fromInteger */ public function testFromIntegerString() { @@ -1347,7 +1345,6 @@ class UuidTest extends TestCase $this->assertTrue($uuid->equals($fromIntegerUuid)); } - /** * This test ensures that Rhumsaa\Uuid passes the same test cases * as the Python UUID library. From f97c9e08f993f8bfbe1f2ef9a870e81fa481172b Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Thu, 6 Nov 2014 10:42:02 +0100 Subject: [PATCH 10/30] Rename degraded feature classes with more consistent names --- ...verter.php => DegradedNumberConverter.php} | 2 +- src/{SmallIntUuid.php => DegradedUuid.php} | 2 +- src/UuidFactory.php | 4 +-- tests/DegradedNumberConverterTest.php | 26 +++++++++++++++++++ tests/UnsatisfiedNumberConverterTest.php | 16 ------------ tests/UuidTest.php | 6 ++--- 6 files changed, 33 insertions(+), 23 deletions(-) rename src/{UnsatisfiedNumberConverter.php => DegradedNumberConverter.php} (92%) rename src/{SmallIntUuid.php => DegradedUuid.php} (99%) create mode 100644 tests/DegradedNumberConverterTest.php delete mode 100644 tests/UnsatisfiedNumberConverterTest.php diff --git a/src/UnsatisfiedNumberConverter.php b/src/DegradedNumberConverter.php similarity index 92% rename from src/UnsatisfiedNumberConverter.php rename to src/DegradedNumberConverter.php index cc933b3..7950cca 100644 --- a/src/UnsatisfiedNumberConverter.php +++ b/src/DegradedNumberConverter.php @@ -2,7 +2,7 @@ namespace Rhumsaa\Uuid; -class UnsatisfiedNumberConverter extends BigNumberConverter +class DegradedNumberConverter extends BigNumberConverter { public function fromHex($hex) { diff --git a/src/SmallIntUuid.php b/src/DegradedUuid.php similarity index 99% rename from src/SmallIntUuid.php rename to src/DegradedUuid.php index 17effc7..7f11acc 100644 --- a/src/SmallIntUuid.php +++ b/src/DegradedUuid.php @@ -2,7 +2,7 @@ namespace Rhumsaa\Uuid; -class SmallIntUuid extends Uuid +class DegradedUuid extends Uuid { public function __construct(array $fields, BigNumberConverter $converter, Codec $codec) diff --git a/src/UuidFactory.php b/src/UuidFactory.php index f2dd6a5..e70d0b2 100644 --- a/src/UuidFactory.php +++ b/src/UuidFactory.php @@ -243,7 +243,7 @@ class UuidFactory $converter = new BigNumberConverter(); if (! self::hasBigNumber()) { - $converter = new UnsatisfiedNumberConverter(); + $converter = new DegradedNumberConverter(); } return $converter; @@ -384,7 +384,7 @@ class UuidFactory $codec = $codec ?: $this->codec; if (! self::is64BitSystem()) { - return new SmallIntUuid($fields, $this->getConverter(), $codec); + return new DegradedUuid($fields, $this->getConverter(), $codec); } return new Uuid($fields, $this->getConverter(), $codec); diff --git a/tests/DegradedNumberConverterTest.php b/tests/DegradedNumberConverterTest.php new file mode 100644 index 0000000..8f14ceb --- /dev/null +++ b/tests/DegradedNumberConverterTest.php @@ -0,0 +1,26 @@ +fromHex('ffff'); + } + + /** + * @expectedException Rhumsaa\Uuid\Exception\UnsatisfiedDependencyException + */ + public function testConvertingToHexThrowsException() + { + $converter = new DegradedNumberConverter(); + + $converter->toHex(0); + } +} diff --git a/tests/UnsatisfiedNumberConverterTest.php b/tests/UnsatisfiedNumberConverterTest.php deleted file mode 100644 index 32f8a52..0000000 --- a/tests/UnsatisfiedNumberConverterTest.php +++ /dev/null @@ -1,16 +0,0 @@ -fromHex('ffff'); - } -} diff --git a/tests/UuidTest.php b/tests/UuidTest.php index f330690..7858abb 100644 --- a/tests/UuidTest.php +++ b/tests/UuidTest.php @@ -185,8 +185,8 @@ class UuidTest extends TestCase $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); - $this->assertInstanceOf('Rhumsaa\Uuid\SmallIntUuid', $uuid); - $this->assertInstanceOf('Rhumsaa\Uuid\UnsatisfiedNumberConverter', $uuid->getConverter()); + $this->assertInstanceOf('Rhumsaa\Uuid\DegradedUuid', $uuid); + $this->assertInstanceOf('Rhumsaa\Uuid\DegradedNumberConverter', $uuid->getConverter()); $date = $uuid->getDateTime(); } @@ -1675,7 +1675,7 @@ class UuidTest extends TestCase /** * @expectedException Rhumsaa\Uuid\Exception\UnsatisfiedDependencyException - * @expectedExceptionMessage Cannot call Rhumsaa\Uuid\UnsatisfiedNumberConverter::fromHex without support for large integers + * @expectedExceptionMessage Cannot call Rhumsaa\Uuid\DegradedNumberConverter::fromHex without support for large integers */ public function testGetInteger() { From 84123b206031ec81cd51317502bb991d3533ba02 Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Sat, 8 Nov 2014 12:41:40 +0100 Subject: [PATCH 11/30] Remove all env related logic from factory Defers all environment related decisions to factory initialization All behavior is customizable through DI, but all deps are initialized to proper default instances Removes static factory configuration --- src/Builder/DefaultUuidBuilder.php | 24 +++ src/Builder/DegradedUuidBuilder.php | 24 +++ src/Codec.php | 4 +- src/Codec/GuidStringCodec.php | 26 +-- src/Codec/StringCodec.php | 15 +- src/FeatureSet.php | 171 ++++++++++++++++++ src/Generator/RandomLibAdapter.php | 27 +++ src/Node/FallbackNodeProvider.php | 26 +++ src/Node/RandomNodeProvider.php | 15 ++ src/Node/SystemNodeProvider.php | 50 ++++++ src/NodeProvider.php | 8 + src/Time/BigNumberTimeConverter.php | 31 ++++ src/Time/DegradedTimeConverter.php | 18 ++ src/Time/FixedTimeProvider.php | 34 ++++ src/Time/PhpTimeConverter.php | 21 +++ src/Time/SystemTimeProvider.php | 13 ++ src/TimeConverter.php | 16 ++ src/TimeProvider.php | 11 ++ src/Uuid.php | 10 -- src/UuidBuilder.php | 8 + src/UuidFactory.php | 260 ++++++++-------------------- tests/UuidBcTag1_1_2Test.php | 4 +- tests/UuidFactoryTest.php | 4 +- tests/UuidTest.php | 143 ++++++++------- 24 files changed, 672 insertions(+), 291 deletions(-) create mode 100644 src/Builder/DefaultUuidBuilder.php create mode 100644 src/Builder/DegradedUuidBuilder.php create mode 100644 src/FeatureSet.php create mode 100644 src/Generator/RandomLibAdapter.php create mode 100644 src/Node/FallbackNodeProvider.php create mode 100644 src/Node/RandomNodeProvider.php create mode 100644 src/Node/SystemNodeProvider.php create mode 100644 src/NodeProvider.php create mode 100644 src/Time/BigNumberTimeConverter.php create mode 100644 src/Time/DegradedTimeConverter.php create mode 100644 src/Time/FixedTimeProvider.php create mode 100644 src/Time/PhpTimeConverter.php create mode 100644 src/Time/SystemTimeProvider.php create mode 100644 src/TimeConverter.php create mode 100644 src/TimeProvider.php create mode 100644 src/UuidBuilder.php diff --git a/src/Builder/DefaultUuidBuilder.php b/src/Builder/DefaultUuidBuilder.php new file mode 100644 index 0000000..449e68b --- /dev/null +++ b/src/Builder/DefaultUuidBuilder.php @@ -0,0 +1,24 @@ +converter = $converter; + } + + public function build(Codec $codec, array $fields) + { + return new Uuid($fields, $this->converter, $codec); + } +} diff --git a/src/Builder/DegradedUuidBuilder.php b/src/Builder/DegradedUuidBuilder.php new file mode 100644 index 0000000..8de0218 --- /dev/null +++ b/src/Builder/DegradedUuidBuilder.php @@ -0,0 +1,24 @@ +converter = $converter; + } + + public function build(Codec $codec, array $fields) + { + return new DegradedUuid($fields, $this->converter, $codec); + } +} diff --git a/src/Codec.php b/src/Codec.php index b88db75..9912851 100644 --- a/src/Codec.php +++ b/src/Codec.php @@ -8,7 +8,7 @@ interface Codec public function encodeBinary(UuidInterface $uuid); - public function decode(BigNumberConverter $converter, $encodedUuid); + public function decode($encodedUuid); - public function decodeBytes(BigNumberConverter $converter, $bytes); + public function decodeBytes($bytes); } diff --git a/src/Codec/GuidStringCodec.php b/src/Codec/GuidStringCodec.php index 9da1b47..e290b03 100644 --- a/src/Codec/GuidStringCodec.php +++ b/src/Codec/GuidStringCodec.php @@ -8,15 +8,19 @@ use Rhumsaa\Uuid\UuidInterface; use Rhumsaa\Uuid\Uuid; use Rhumsaa\Uuid\BigNumberConverter; use Rhumsaa\Uuid\UuidFactory; +use Rhumsaa\Uuid\UuidBuilder; class GuidStringCodec implements Codec { - private $factory; + private $builder; - public function __construct(UuidFactory $factory) + private $uuidCodec; + + public function __construct(UuidBuilder $builder, Codec $uuidCodec) { - $this->factory = $factory; + $this->builder = $builder; + $this->uuidCodec = $uuidCodec; } public function encode(UuidInterface $uuid) @@ -39,17 +43,17 @@ class GuidStringCodec implements Codec public function encodeBinary(UuidInterface $uuid) { - $reversed = $this->_decode($uuid->getConverter(), $this->encode($uuid), false); + $reversed = $this->_decode($this->encode($uuid), false); - return (new StringCodec())->encodeBinary($reversed); + return $this->uuidCodec->encodeBinary($reversed); } - public function decode(BigNumberConverter $converter, $encodedUuid) + public function decode($encodedUuid) { - return $this->_decode($converter, $encodedUuid, true); + return $this->_decode($encodedUuid, true); } - public function decodeBytes(BigNumberConverter $converter, $bytes) + public function decodeBytes($bytes) { if (strlen($bytes) !== 16) { throw new InvalidArgumentException('$bytes string should contain 16 characters.'); @@ -57,10 +61,10 @@ class GuidStringCodec implements Codec $hexUuid = unpack('H*', $bytes); - return $this->_decode($converter, $hexUuid[1], false); + return $this->_decode($hexUuid[1], false); } - private function _decode(BigNumberConverter $converter, $hex, $swap) + private function _decode($hex, $swap) { $nameParsed = str_replace(array( 'urn:', @@ -105,6 +109,6 @@ class GuidStringCodec implements Codec 'node' => sprintf('%012s', $components[4]) ); - return $this->factory->uuid($fields, $this); + return $this->builder->build($this, $fields); } } diff --git a/src/Codec/StringCodec.php b/src/Codec/StringCodec.php index 5e9fd43..ce451de 100644 --- a/src/Codec/StringCodec.php +++ b/src/Codec/StringCodec.php @@ -8,15 +8,16 @@ use Rhumsaa\Uuid\UuidInterface; use Rhumsaa\Uuid\Uuid; use Rhumsaa\Uuid\BigNumberConverter; use Rhumsaa\Uuid\UuidFactory; +use Rhumsaa\Uuid\UuidBuilder; class StringCodec implements Codec { - private $factory; + private $builder; - public function __construct(UuidFactory $factory) + public function __construct(UuidBuilder $builder) { - $this->factory = $factory; + $this->builder = $builder; } public function encode(UuidInterface $uuid) @@ -40,7 +41,7 @@ class StringCodec implements Codec return $bytes; } - public function decode(BigNumberConverter $converter, $encodedUuid) + public function decode($encodedUuid) { $nameParsed = str_replace(array( 'urn:', @@ -76,10 +77,10 @@ class StringCodec implements Codec 'node' => sprintf('%012s', $components[4]) ); - return $this->factory->uuid($fields, $this); + return $this->builder->build($this, $fields); } - public function decodeBytes(BigNumberConverter $converter, $bytes) + public function decodeBytes($bytes) { if (strlen($bytes) !== 16) { throw new InvalidArgumentException('$bytes string should contain 16 characters.'); @@ -87,6 +88,6 @@ class StringCodec implements Codec $hexUuid = unpack('H*', $bytes); - return $this->decode($converter, $hexUuid[1]); + return $this->decode($hexUuid[1]); } } diff --git a/src/FeatureSet.php b/src/FeatureSet.php new file mode 100644 index 0000000..7709ad1 --- /dev/null +++ b/src/FeatureSet.php @@ -0,0 +1,171 @@ +disableBigNumber = $forceNoBigNumber; + $this->disable64Bit = $force32Bit; + $this->ignoreSystemNode = $ignoreSystemNode; + + $this->numberConverter = $this->buildNumberConverter(); + $this->builder = $this->buildUuidBuilder(); + $this->codec = $this->buildCodec($useGuids); + $this->nodeProvider = $this->buildNodeProvider(); + $this->randomGenerator = $this->buildRandomGenerator(); + $this->timeConverter = $this->buildTimeConverter(); + $this->timeProvider = new SystemTimeProvider(); + } + + public function getBuilder() + { + return $this->builder; + } + + public function getCodec() + { + return $this->codec; + } + + public function getNodeProvider() + { + return $this->nodeProvider; + } + + public function getNumberConverter() + { + return $this->numberConverter; + } + + public function getRandomGenerator() + { + return $this->randomGenerator; + } + + public function getTimeConverter() + { + return $this->timeConverter; + } + + public function getTimeProvider() + { + return $this->timeProvider; + } + + protected function buildCodec($useGuids = false) + { + if ($useGuids) { + return new GuidStringCodec($this->builder, $this->buildCodec(false)); + } + + return new StringCodec($this->builder); + } + + protected function buildNodeProvider() + { + if ($this->ignoreSystemNode) { + return new RandomNodeProvider(); + } + + return new FallbackNodeProvider([ + new SystemNodeProvider(), + new RandomNodeProvider() + ]); + } + + protected function buildNumberConverter() + { + if ($this->hasBigNumber()) { + return new BigNumberConverter(); + } + + return new DegradedNumberConverter(); + } + + protected function buildRandomGenerator() + { + return (new RandomGeneratorFactory())->getGenerator(); + } + + protected function buildTimeConverter() + { + if ($this->is64BitSystem()) { + return new PhpTimeConverter(); + } + elseif ($this->hasBigNumber()) { + return new BigNumberTimeConverter(); + } + + return new DegradedTimeConverter(); + } + + protected function buildUuidBuilder() + { + if ($this->is64BitSystem()) { + return new DefaultUuidBuilder($this->numberConverter); + } + + return new DegradedUuidBuilder($this->numberConverter); + } + + /** + * Returns true if the system has Moontoast\Math\BigNumber + * + * @return bool + */ + protected function hasBigNumber() + { + return class_exists('Moontoast\Math\BigNumber') && ! $this->disableBigNumber; + } + + /** + * Returns true if the system is 64-bit, false otherwise + * + * @return bool + */ + protected function is64BitSystem() + { + return PHP_INT_SIZE == 8 && ! $this->disable64Bit; + } +} diff --git a/src/Generator/RandomLibAdapter.php b/src/Generator/RandomLibAdapter.php new file mode 100644 index 0000000..8dac106 --- /dev/null +++ b/src/Generator/RandomLibAdapter.php @@ -0,0 +1,27 @@ +generator = $generator; + + if ($this->generator == null) { + $factory = new Factory(); + + $this->generator = $factory->getLowStrengthGenerator(); + } + } + + public function generate($length) + { + return $this->generator->generate($length); + } +} diff --git a/src/Node/FallbackNodeProvider.php b/src/Node/FallbackNodeProvider.php new file mode 100644 index 0000000..947ca9a --- /dev/null +++ b/src/Node/FallbackNodeProvider.php @@ -0,0 +1,26 @@ +nodeProviders = $providers; + } + + public function getNode() + { + foreach ($this->nodeProviders as $provider) { + if ($node = $provider->getNode()) { + return $node; + } + } + + return null; + } +} diff --git a/src/Node/RandomNodeProvider.php b/src/Node/RandomNodeProvider.php new file mode 100644 index 0000000..1c4195c --- /dev/null +++ b/src/Node/RandomNodeProvider.php @@ -0,0 +1,15 @@ +getIfconfig(), $matches, PREG_PATTERN_ORDER)) { + $node = $matches[1][0]; + $node = str_replace(':', '', $node); + $node = str_replace('-', '', $node); + } + + return $node; + } + + /** + * Returns the network interface configuration for the system + * + * @todo Needs evaluation and possibly modification to ensure this works + * well across multiple platforms. + * @codeCoverageIgnore + */ + protected function getIfconfig() + { + switch (strtoupper(substr(php_uname('a'), 0, 3))) { + case 'WIN': + $ifconfig = `ipconfig /all 2>&1`; + break; + case 'DAR': + $ifconfig = `ifconfig 2>&1`; + break; + case 'LIN': + default: + $ifconfig = `netstat -ie 2>&1`; + break; + } + + return $ifconfig; + } +} diff --git a/src/NodeProvider.php b/src/NodeProvider.php new file mode 100644 index 0000000..70f58d2 --- /dev/null +++ b/src/NodeProvider.php @@ -0,0 +1,8 @@ +multiply('10000000'); + + $usec = new \Moontoast\Math\BigNumber($microSeconds); + $usec->multiply('10'); + + $uuidTime->add($sec) + ->add($usec) + ->add('122192928000000000'); + + $uuidTimeHex = sprintf('%016s', $uuidTime->convertToBase(16)); + + return array( + 'low' => substr($uuidTimeHex, 8), + 'mid' => substr($uuidTimeHex, 4, 4), + 'hi' => substr($uuidTimeHex, 0, 4), + ); + } +} diff --git a/src/Time/DegradedTimeConverter.php b/src/Time/DegradedTimeConverter.php new file mode 100644 index 0000000..f64ee30 --- /dev/null +++ b/src/Time/DegradedTimeConverter.php @@ -0,0 +1,18 @@ +fixedTime = $timestamp; + } + + public function setUsec($value) + { + $this->fixedTime['usec'] = $value; + } + + public function setSec($value) + { + $this->fixedTime['sec'] = $value; + } + + public function currentTime() + { + return $this->fixedTime; + } +} diff --git a/src/Time/PhpTimeConverter.php b/src/Time/PhpTimeConverter.php new file mode 100644 index 0000000..5e40540 --- /dev/null +++ b/src/Time/PhpTimeConverter.php @@ -0,0 +1,21 @@ + sprintf('%08x', $uuidTime & 0xffffffff), + 'mid' => sprintf('%04x', ($uuidTime >> 32) & 0xffff), + 'hi' => sprintf('%04x', ($uuidTime >> 48) & 0x0fff), + ); + } +} diff --git a/src/Time/SystemTimeProvider.php b/src/Time/SystemTimeProvider.php new file mode 100644 index 0000000..068ecc9 --- /dev/null +++ b/src/Time/SystemTimeProvider.php @@ -0,0 +1,13 @@ +fromBytes($bytes); } - public static function fromGuidBytes($bytes) - { - return self::getFactory()->fromGuidBytes($bytes); - } - /** * Creates a UUID from the string standard representation as described * in the toString() method. @@ -763,11 +758,6 @@ class Uuid implements UuidInterface, \JsonSerializable return self::getFactory()->fromString($name); } - public static function fromGuidString($name) - { - return self::getFactory()->fromGuidString($name); - } - /** * Creates a UUID from either the UUID as a 128-bit integer string or a Moontoast\Math\BigNumber object. * diff --git a/src/UuidBuilder.php b/src/UuidBuilder.php new file mode 100644 index 0000000..6f777be --- /dev/null +++ b/src/UuidBuilder.php @@ -0,0 +1,8 @@ + sprintf('%08x', $uuidTime & 0xffffffff), - 'mid' => sprintf('%04x', ($uuidTime >> 32) & 0xffff), - 'hi' => sprintf('%04x', ($uuidTime >> 48) & 0x0fff), - ); - } - - if (self::hasBigNumber()) { - - $uuidTime = new \Moontoast\Math\BigNumber('0'); - - $sec = new \Moontoast\Math\BigNumber($sec); - $sec->multiply('10000000'); - - $usec = new \Moontoast\Math\BigNumber($usec); - $usec->multiply('10'); - - $uuidTime->add($sec) - ->add($usec) - ->add('122192928000000000'); - - $uuidTimeHex = sprintf('%016s', $uuidTime->convertToBase(16)); - - return array( - 'low' => substr($uuidTimeHex, 8), - 'mid' => substr($uuidTimeHex, 4, 4), - 'hi' => substr($uuidTimeHex, 0, 4), - ); - } - - throw new Exception\UnsatisfiedDependencyException( - 'When calling ' . __METHOD__ . ' on a 32-bit system, ' - . 'Moontoast\Math\BigNumber must be present in order ' - . 'to generate version 1 UUIDs' - ); - } + private $timeConverter = null; /** - * Get the hardware address as a 48-bit positive integer. If all attempts to - * obtain the hardware address fail, we choose a random 48-bit number with - * its eighth bit set to 1 as recommended in RFC 4122. "Hardware address" - * means the MAC address of a network interface, and on a machine with - * multiple network interfaces the MAC address of any one of them may be - * returned. * - * @return string + * @var TimeProvider */ - protected static function getNodeFromSystem() - { - $node = null; - $pattern = '/[^:]([0-9A-Fa-f]{2}([:-])[0-9A-Fa-f]{2}(\2[0-9A-Fa-f]{2}){4})[^:]/'; - $matches = array(); - - // Search the ifconfig output for all MAC addresses and return - // the first one found - if (preg_match_all($pattern, self::getIfconfig(), $matches, PREG_PATTERN_ORDER)) { - $node = $matches[1][0]; - $node = str_replace(':', '', $node); - $node = str_replace('-', '', $node); - } - - return $node; - } + private $timeProvider = null; /** - * Returns the network interface configuration for the system * - * @todo Needs evaluation and possibly modification to ensure this works - * well across multiple platforms. - * @codeCoverageIgnore + * @var UuidBuilder */ - protected static function getIfconfig() - { - switch (strtoupper(substr(php_uname('a'), 0, 3))) { - case 'WIN': - $ifconfig = `ipconfig /all 2>&1`; - break; - case 'DAR': - $ifconfig = `ifconfig 2>&1`; - break; - case 'LIN': - default: - $ifconfig = `netstat -ie 2>&1`; - break; - } - - return $ifconfig; - } + private $uuidBuilder = null; /** - * Returns true if the system has Moontoast\Math\BigNumber + * Create a new a instance * - * @return bool */ - protected static function hasBigNumber() + public function __construct(FeatureSet $features = null) { - return (class_exists('Moontoast\Math\BigNumber') && !self::$forceNoBigNumber); + $features = $features ?: new FeatureSet(); + + $this->codec = $features->getCodec(); + $this->nodeProvider = $features->getNodeProvider(); + $this->numberConverter = $features->getNumberConverter(); + $this->randomGenerator = $features->getRandomGenerator(); + $this->timeConverter = $features->getTimeConverter(); + $this->timeProvider = $features->getTimeProvider(); + $this->uuidBuilder = $features->getBuilder(); } - /** - * Returns true if the system is 64-bit, false otherwise - * - * @return bool - */ - protected static function is64BitSystem() + public function setTimeConverter(TimeConverter $converter) { - return (PHP_INT_SIZE == 8 && !self::$force32Bit); + $this->timeConverter = $converter; } - - /** - * Generates random bytes for use in version 4 UUIDs - * - * @param int $length - * @return string - */ - private static function generateBytes($length) + public function setTimeProvider(TimeProvider $provider) { - if (! self::$prng) { - self::$prng = (new RandomGeneratorFactory())->getGenerator(); - } - - return self::$prng->generate($length); + $this->timeProvider = $provider; } - private $codec = null; - - public function __construct(Codec $uuidCodec = null, Codec $guidCodec = null) + public function setRandomGenerator(RandomGenerator $generator) { - $this->codec = $uuidCodec ?: new StringCodec($this); - $this->guidCodec = $guidCodec ?: new GuidStringCodec($this); + $this->randomGenerator = $generator; + } + + public function setNodeProvider(NodeProvider $provider) + { + $this->nodeProvider = $provider; + } + + public function setNumberConverter(BigNumberConverter $converter) + { + $this->numberConverter = $converter; + } + + public function setUuidBuilder(UuidBuilder $builder) + { + $this->uuidBuilder = $builder; } /** @@ -203,12 +118,7 @@ class UuidFactory */ public function fromBytes($bytes) { - return $this->codec->decodeBytes($this->getConverter(), $bytes); - } - - public function fromGuidBytes($bytes) - { - return $this->guidCodec->decodeBytes($this->getConverter(), $bytes); + return $this->codec->decodeBytes($bytes); } /** @@ -222,33 +132,17 @@ class UuidFactory */ public function fromString($name) { - return $this->codec->decode($this->getConverter(), $name); - } - - public function fromGuidString($name) - { - return $this->guidCodec->decode($this->getConverter(), $name); + return $this->codec->decode($name); } public function fromInteger($integer) { - $hex = $this->getConverter()->toHex($integer); + $hex = $this->numberConverter->toHex($integer); $hex = str_pad($hex, 32, '0', STR_PAD_LEFT); return $this->fromString($hex); } - public function getConverter() - { - $converter = new BigNumberConverter(); - - if (! self::hasBigNumber()) { - $converter = new DegradedNumberConverter(); - } - - return $converter; - } - /** * Generate a version 1 UUID from a host ID, sequence number, and the current time. * If $node is not given, we will attempt to obtain the local hardware @@ -266,14 +160,8 @@ class UuidFactory */ public function uuid1($node = null, $clockSeq = null) { - if ($node === null && !self::$ignoreSystemNode) { - $node = self::getNodeFromSystem(); - } - - // if $node is still null (couldn't get from system), randomly generate - // a node value, according to RFC 4122, Section 4.5 if ($node === null) { - $node = sprintf('%06x%06x', mt_rand(0, 1 << 24), mt_rand(0, 1 << 24)); + $node = $this->nodeProvider->getNode(); } // Convert the node to hex, if it is still an integer @@ -281,12 +169,12 @@ class UuidFactory $node = sprintf('%012x', $node); } - if (ctype_xdigit($node) && strlen($node) <= 12) { - $node = strtolower(sprintf('%012s', $node)); - } else { + if (! ctype_xdigit($node) || strlen($node) > 12) { throw new \InvalidArgumentException('Invalid node value'); } + $node = strtolower(sprintf('%012s', $node)); + if ($clockSeq === null) { // Not using "stable storage"; see RFC 4122, Section 4.2.1.1 $clockSeq = mt_rand(0, 1 << 14); @@ -294,13 +182,8 @@ class UuidFactory // Create a 60-bit time value as a count of 100-nanosecond intervals // since 00:00:00.00, 15 October 1582 - if (self::$timeOfDayTest === null) { - $timeOfDay = gettimeofday(); - } else { - $timeOfDay = self::$timeOfDayTest; - } - - $uuidTime = self::calculateUuidTime($timeOfDay['sec'], $timeOfDay['usec']); + $timeOfDay = $this->timeProvider->currentTime(); + $uuidTime = $this->timeConverter->calculateTime($timeOfDay['sec'], $timeOfDay['usec']); // Set the version number to 1 $timeHi = hexdec($uuidTime['hi']) & 0x0fff; @@ -336,7 +219,7 @@ class UuidFactory public function uuid3($ns, $name) { if (!($ns instanceof UuidInterface)) { - $ns = $this->codec->decode($this->getConverter(), $ns); + $ns = $this->codec->decode($ns); } $hash = md5($ns->getBytes() . $name); @@ -351,12 +234,13 @@ class UuidFactory */ public function uuid4() { - $bytes = self::generateBytes(16); + $bytes = $this->randomGenerator->generate(16); // When converting the bytes to hex, it turns into a 32-character // hexadecimal string that looks a lot like an MD5 hash, so at this // point, we can just pass it to uuidFromHashedName. $hex = bin2hex($bytes); + return $this->uuidFromHashedName($hex, 4); } @@ -371,7 +255,7 @@ class UuidFactory public function uuid5($ns, $name) { if (!($ns instanceof Uuid)) { - $ns = $this->codec->decode($this->getConverter(), $ns); + $ns = $this->codec->decode($ns); } $hash = sha1($ns->getBytes() . $name); @@ -379,15 +263,9 @@ class UuidFactory return $this->uuidFromHashedName($hash, 5); } - public function uuid(array $fields, Codec $codec = null) + public function uuid(array $fields) { - $codec = $codec ?: $this->codec; - - if (! self::is64BitSystem()) { - return new DegradedUuid($fields, $this->getConverter(), $codec); - } - - return new Uuid($fields, $this->getConverter(), $codec); + return $this->uuidBuilder->build($this->codec, $fields); } /** diff --git a/tests/UuidBcTag1_1_2Test.php b/tests/UuidBcTag1_1_2Test.php index fde737c..60966f1 100644 --- a/tests/UuidBcTag1_1_2Test.php +++ b/tests/UuidBcTag1_1_2Test.php @@ -12,6 +12,8 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase { protected function setUp() { + Uuid::setFactory(new UuidFactory()); + // Skip these tests if run on a 32-bit build of PHP if (PHP_INT_SIZE == 4) { $this->markTestSkipped( @@ -375,7 +377,7 @@ class UuidBcTag1_1_2Test extends \PHPUnit_Framework_TestCase */ public function testUuid1WithRandomNode() { - UuidFactory::$ignoreSystemNode = true; + Uuid::setFactory(new UuidFactory(new FeatureSet(false, false, false, true))); $uuid = Uuid::uuid1(); $this->assertInstanceOf('\Rhumsaa\Uuid\Uuid', $uuid); diff --git a/tests/UuidFactoryTest.php b/tests/UuidFactoryTest.php index c53d757..b5ca218 100644 --- a/tests/UuidFactoryTest.php +++ b/tests/UuidFactoryTest.php @@ -15,9 +15,9 @@ class UuidFactoryTest extends TestCase public function testParsesGuidCorrectly() { - $factory = new UuidFactory(); + $factory = new UuidFactory(new FeatureSet(true)); - $uuid = $factory->fromGuidString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); + $uuid = $factory->fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); $this->assertEquals('ff6f8cb0-c57d-11e1-9b21-0800200c9a66', $uuid->toString()); } diff --git a/tests/UuidTest.php b/tests/UuidTest.php index 7858abb..c2f0d6d 100644 --- a/tests/UuidTest.php +++ b/tests/UuidTest.php @@ -2,15 +2,14 @@ namespace Rhumsaa\Uuid; +use Rhumsaa\Uuid\Time\SystemTimeProvider; +use Rhumsaa\Uuid\Time\FixedTimeProvider; + class UuidTest extends TestCase { protected function setUp() { - UuidFactory::$forceNoBigNumber = false; - - UuidFactory::$timeOfDayTest = null; - UuidFactory::$force32Bit = false; - UuidFactory::$ignoreSystemNode = false; + Uuid::setFactory(new UuidFactory()); RandomGeneratorFactory::$forceNoOpensslRandomPseudoBytes = false; } @@ -29,7 +28,10 @@ class UuidTest extends TestCase public function testFromLittleEndianString() { $uuid = Uuid::fromString('b08c6fff-7dc5-e111-9b21-0800200c9a66'); - $guid = Uuid::fromGuidString('b08c6fff-7dc5-e111-9b21-0800200c9a66'); + + Uuid::setFactory(new UuidFactory(new FeatureSet(true))); + + $guid = Uuid::fromString('b08c6fff-7dc5-e111-9b21-0800200c9a66'); $this->assertInstanceOf('\Rhumsaa\Uuid\Uuid', $guid); // UUID's and GUID's share the same textual representation @@ -152,7 +154,7 @@ class UuidTest extends TestCase public function testGetDateTime32Bit() { $this->skipIfNoMoontoastMath(); - UuidFactory::$force32Bit = true; + Uuid::setFactory(new UuidFactory(new FeatureSet(false, true))); // Check a recent date $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); @@ -180,8 +182,7 @@ class UuidTest extends TestCase */ public function testGetDateTimeThrownException() { - UuidFactory::$force32Bit = true; - UuidFactory::$forceNoBigNumber = true; + Uuid::setFactory(new UuidFactory(new FeatureSet(false, true, true))); $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); @@ -227,7 +228,8 @@ class UuidTest extends TestCase */ public function testGetFields32Bit() { - UuidFactory::$force32Bit = true; + Uuid::setFactory(new UuidFactory(new FeatureSet(false, true))); + $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); $fields = $uuid->getFields(); } @@ -266,7 +268,8 @@ class UuidTest extends TestCase */ public function testGetLeastSignificantBitsException() { - UuidFactory::$forceNoBigNumber = true; + Uuid::setFactory(new UuidFactory(new FeatureSet(false, false, true))); + $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); $bn = $uuid->getLeastSignificantBits(); } @@ -295,7 +298,8 @@ class UuidTest extends TestCase */ public function testGetMostSignificantBitsException() { - UuidFactory::$forceNoBigNumber = true; + Uuid::setFactory(new UuidFactory(new FeatureSet(false, false, true))); + $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); $bn = $uuid->getMostSignificantBits(); } @@ -323,7 +327,8 @@ class UuidTest extends TestCase */ public function testGetNode32Bit() { - UuidFactory::$force32Bit = true; + Uuid::setFactory(new UuidFactory(new FeatureSet(false, true))); + $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); $node = $uuid->getNode(); } @@ -367,7 +372,8 @@ class UuidTest extends TestCase */ public function testGetTimeLow32Bit() { - UuidFactory::$force32Bit = true; + Uuid::setFactory(new UuidFactory(new FeatureSet(false, true))); + $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); $timeLow = $uuid->getTimeLow(); } @@ -451,7 +457,8 @@ class UuidTest extends TestCase */ public function testGetTimestamp32Bit() { - UuidFactory::$force32Bit = true; + Uuid::setFactory(new UuidFactory(new FeatureSet(false, true))); + $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); $ts = $uuid->getTimestamp(); } @@ -695,7 +702,7 @@ class UuidTest extends TestCase public function testUuid1WithRandomNode() { - UuidFactory::$ignoreSystemNode = true; + Uuid::setFactory(new UuidFactory(new FeatureSet(false, false, false, true))); $uuid = Uuid::uuid1(); $this->assertInstanceOf('\Rhumsaa\Uuid\Uuid', $uuid); @@ -877,15 +884,15 @@ class UuidTest extends TestCase */ public function testCalculateUuidTime() { - $timeOfDay = array( + $timeOfDay = new FixedTimeProvider(array( 'sec' => 1348845514, 'usec' => 277885, 'minuteswest' => 0, 'dsttime' => 0, - ); + )); // For usec = 277885 - UuidFactory::$timeOfDayTest = $timeOfDay; + Uuid::getFactory()->setTimeProvider($timeOfDay); $uuidA = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('c4dbe7e2-097f-11e2-9669-00007ffffffe', (string) $uuidA); @@ -894,7 +901,7 @@ class UuidTest extends TestCase $this->assertEquals('11e2', $uuidA->getTimeHiAndVersionHex()); // For usec = 0 - UuidFactory::$timeOfDayTest['usec'] = 0; + $timeOfDay->setUsec(0); $uuidB = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('c4b18100-097f-11e2-9669-00007ffffffe', (string) $uuidB); @@ -903,7 +910,7 @@ class UuidTest extends TestCase $this->assertEquals('11e2', $uuidB->getTimeHiAndVersionHex()); // For usec = 999999 - UuidFactory::$timeOfDayTest['usec'] = 999999; + $timeOfDay->setUsec(999999); $uuidC = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('c54a1776-097f-11e2-9669-00007ffffffe', (string) $uuidC); @@ -917,17 +924,17 @@ class UuidTest extends TestCase public function testCalculateUuidTimeForce32BitPath() { $this->skipIfNoMoontoastMath(); - UuidFactory::$force32Bit = true; + Uuid::setFactory(new UuidFactory(new FeatureSet(false, true))); - $timeOfDay = array( + $timeOfDay = new FixedTimeProvider(array( 'sec' => 1348845514, 'usec' => 277885, 'minuteswest' => 0, 'dsttime' => 0, - ); + )); // For usec = 277885 - UuidFactory::$timeOfDayTest = $timeOfDay; + Uuid::getFactory()->setTimeProvider($timeOfDay); $uuidA = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('c4dbe7e2-097f-11e2-9669-00007ffffffe', (string) $uuidA); @@ -936,7 +943,7 @@ class UuidTest extends TestCase $this->assertEquals('11e2', $uuidA->getTimeHiAndVersionHex()); // For usec = 0 - UuidFactory::$timeOfDayTest['usec'] = 0; + $timeOfDay->setUsec(0); $uuidB = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('c4b18100-097f-11e2-9669-00007ffffffe', (string) $uuidB); @@ -945,7 +952,7 @@ class UuidTest extends TestCase $this->assertEquals('11e2', $uuidB->getTimeHiAndVersionHex()); // For usec = 999999 - UuidFactory::$timeOfDayTest['usec'] = 999999; + $timeOfDay->setUsec(999999); $uuidC = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('c54a1776-097f-11e2-9669-00007ffffffe', (string) $uuidC); @@ -961,14 +968,14 @@ class UuidTest extends TestCase $this->skip64BitTest(); // 5235-03-31T21:20:59+00:00 - $timeOfDay = array( + $timeOfDay = new FixedTimeProvider(array( 'sec' => 103072857659, 'usec' => 999999, 'minuteswest' => 0, 'dsttime' => 0, - ); + )); - UuidFactory::$timeOfDayTest = $timeOfDay; + Uuid::getFactory()->setTimeProvider($timeOfDay); $uuidA = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('ff9785f6-ffff-1fff-9669-00007ffffffe', (string) $uuidA); @@ -977,14 +984,14 @@ class UuidTest extends TestCase $this->assertEquals('1fff', $uuidA->getTimeHiAndVersionHex()); // 1582-10-15T00:00:00+00:00 - $timeOfDay = array( + $timeOfDay = new FixedTimeProvider(array( 'sec' => -12219292800, 'usec' => 0, 'minuteswest' => 0, 'dsttime' => 0, - ); + )); - UuidFactory::$timeOfDayTest = $timeOfDay; + Uuid::getFactory()->setTimeProvider($timeOfDay); $uuidB = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('00000000-0000-1000-9669-00007ffffffe', (string) $uuidB); @@ -1003,17 +1010,17 @@ class UuidTest extends TestCase $this->skipIfNoMoontoastMath(); $this->skip64BitTest(); - UuidFactory::$force32Bit = true; + Uuid::setFactory(new UuidFactory(new FeatureSet(false, true))); // 5235-03-31T21:20:59+00:00 - $timeOfDay = array( + $timeOfDay = new FixedTimeProvider(array( 'sec' => 103072857659, 'usec' => 999999, 'minuteswest' => 0, 'dsttime' => 0, - ); + )); - UuidFactory::$timeOfDayTest = $timeOfDay; + Uuid::getFactory()->setTimeProvider($timeOfDay); $uuidA = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('ff9785f6-ffff-1fff-9669-00007ffffffe', (string) $uuidA); @@ -1022,14 +1029,14 @@ class UuidTest extends TestCase $this->assertEquals('1fff', $uuidA->getTimeHiAndVersionHex()); // 1582-10-15T00:00:00+00:00 - $timeOfDay = array( + $timeOfDay = new FixedTimeProvider(array( 'sec' => -12219292800, 'usec' => 0, 'minuteswest' => 0, 'dsttime' => 0, - ); + )); - UuidFactory::$timeOfDayTest = $timeOfDay; + Uuid::getFactory()->setTimeProvider($timeOfDay); $uuidB = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('00000000-0000-1000-9669-00007ffffffe', (string) $uuidB); @@ -1043,17 +1050,17 @@ class UuidTest extends TestCase public function testCalculateUuidTimeUpperLowerBounds32Bit() { $this->skipIfNoMoontoastMath(); - UuidFactory::$force32Bit = true; + Uuid::setFactory(new UuidFactory(new FeatureSet(false, true))); // 2038-01-19T03:14:07+00:00 - $timeOfDay = array( + $timeOfDay = new FixedTimeProvider(array( 'sec' => 2147483647, 'usec' => 999999, 'minuteswest' => 0, 'dsttime' => 0, - ); + )); - UuidFactory::$timeOfDayTest = $timeOfDay; + Uuid::getFactory()->setTimeProvider($timeOfDay); $uuidA = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('13813ff6-6912-11fe-9669-00007ffffffe', (string) $uuidA); @@ -1062,14 +1069,14 @@ class UuidTest extends TestCase $this->assertEquals('11fe', $uuidA->getTimeHiAndVersionHex()); // 1901-12-13T20:45:53+00:00 - $timeOfDay = array( + $timeOfDay = new FixedTimeProvider(array( 'sec' => -2147483647, 'usec' => 0, 'minuteswest' => 0, 'dsttime' => 0, - ); + )); - UuidFactory::$timeOfDayTest = $timeOfDay; + Uuid::getFactory()->setTimeProvider($timeOfDay); $uuidB = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('1419d680-d292-1165-9669-00007ffffffe', (string) $uuidB); @@ -1088,14 +1095,14 @@ class UuidTest extends TestCase $this->skip64BitTest(); // 2038-01-19T03:14:07+00:00 - $timeOfDay = array( + $timeOfDay = new FixedTimeProvider(array( 'sec' => 2147483647, 'usec' => 999999, 'minuteswest' => 0, 'dsttime' => 0, - ); + )); - UuidFactory::$timeOfDayTest = $timeOfDay; + Uuid::getFactory()->setTimeProvider($timeOfDay); $uuidA = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('13813ff6-6912-11fe-9669-00007ffffffe', (string) $uuidA); @@ -1104,14 +1111,14 @@ class UuidTest extends TestCase $this->assertEquals('11fe', $uuidA->getTimeHiAndVersionHex()); // 1901-12-13T20:45:53+00:00 - $timeOfDay = array( + $timeOfDay = new FixedTimeProvider(array( 'sec' => -2147483647, 'usec' => 0, 'minuteswest' => 0, 'dsttime' => 0, - ); + )); - UuidFactory::$timeOfDayTest = $timeOfDay; + Uuid::getFactory()->setTimeProvider($timeOfDay); $uuidB = Uuid::uuid1(0x00007ffffffe, 0x1669); $this->assertEquals('1419d680-d292-1165-9669-00007ffffffe', (string) $uuidB); @@ -1132,24 +1139,25 @@ class UuidTest extends TestCase $currentTime = strtotime('2012-12-11T00:00:00+00:00'); $endTime = $currentTime + 3600; + $factory = new UuidFactory(); + $smallIntFactory = new UuidFactory(new FeatureSet(false, true)); + while ($currentTime <= $endTime) { foreach (array(0, 50000, 250000, 500000, 750000, 999999) as $usec) { - $timeOfDay = array( + $timeOfDay = new FixedTimeProvider(array( 'sec' => $currentTime, 'usec' => $usec, 'minuteswest' => 0, 'dsttime' => 0, - ); + )); - UuidFactory::$timeOfDayTest = $timeOfDay; + $factory->setTimeProvider($timeOfDay); + $smallIntFactory->setTimeProvider($timeOfDay); - UuidFactory::$force32Bit = true; - $uuid32 = Uuid::uuid1(0x00007ffffffe, 0x1669); - - UuidFactory::$force32Bit = false; - $uuid64 = Uuid::uuid1(0x00007ffffffe, 0x1669); + $uuid32 = $smallIntFactory->uuid1(0x00007ffffffe, 0x1669); + $uuid64 = $factory->uuid1(0x00007ffffffe, 0x1669); $this->assertTrue( $uuid32->equals($uuid64), @@ -1171,8 +1179,7 @@ class UuidTest extends TestCase */ public function testCalculateUuidTimeThrownException() { - UuidFactory::$force32Bit = true; - UuidFactory::$forceNoBigNumber = true; + Uuid::setFactory(new UuidFactory(new FeatureSet(false, true, true))); $uuid = Uuid::uuid1(0x00007ffffffe, 0x1669); } @@ -1291,16 +1298,18 @@ class UuidTest extends TestCase $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); $bytes = $uuid->getBytes(); - $guid = Uuid::fromGuidBytes($bytes); + Uuid::setFactory(new UuidFactory(new FeatureSet(true))); + + $guid = Uuid::fromBytes($bytes); // First three fields should be reversed $this->assertEquals('b08c6fff-7dc5-e111-9b21-0800200c9a66', $guid->toString()); // Check that parsing LE bytes as LE preserves fields - $guid = Uuid::fromGuidString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); + $guid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); $bytes = $guid->getBytes(); - $parsedGuid = Uuid::fromGuidBytes($bytes); + $parsedGuid = Uuid::fromBytes($bytes); $this->assertEquals($guid->toString(), $parsedGuid->toString()); } @@ -1679,7 +1688,7 @@ class UuidTest extends TestCase */ public function testGetInteger() { - UuidFactory::$forceNoBigNumber = true; + Uuid::setFactory(new UuidFactory(new FeatureSet(false, false, true))); $uuid = Uuid::uuid1(); $uuid->getInteger(); From c07988fe317b41b2328dcdd78cd4be304e948e67 Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Sat, 8 Nov 2014 15:00:58 +0100 Subject: [PATCH 12/30] Refactor codecs to remove duplication --- src/Codec/GuidStringCodec.php | 95 +++++++------------------------ src/Codec/StringCodec.php | 60 +++++++++++-------- src/FeatureSet.php | 2 +- src/Node/FallbackNodeProvider.php | 2 +- src/Uuid.php | 1 + src/UuidFactory.php | 11 ++-- tests/UuidTest.php | 13 +++-- 7 files changed, 70 insertions(+), 114 deletions(-) diff --git a/src/Codec/GuidStringCodec.php b/src/Codec/GuidStringCodec.php index e290b03..ec9e5bd 100644 --- a/src/Codec/GuidStringCodec.php +++ b/src/Codec/GuidStringCodec.php @@ -3,112 +3,57 @@ namespace Rhumsaa\Uuid\Codec; use InvalidArgumentException; -use Rhumsaa\Uuid\Codec; use Rhumsaa\Uuid\UuidInterface; use Rhumsaa\Uuid\Uuid; use Rhumsaa\Uuid\BigNumberConverter; use Rhumsaa\Uuid\UuidFactory; use Rhumsaa\Uuid\UuidBuilder; +use Rhumsaa\Uuid\Codec; -class GuidStringCodec implements Codec +class GuidStringCodec extends StringCodec { - private $builder; - - private $uuidCodec; - - public function __construct(UuidBuilder $builder, Codec $uuidCodec) - { - $this->builder = $builder; - $this->uuidCodec = $uuidCodec; - } - public function encode(UuidInterface $uuid) { - $fields = array_values($uuid->getFieldsHex()); + $components = array_values($uuid->getFieldsHex()); // Swap byte-order on the first three fields - $hex = unpack('H*', pack('V', hexdec($fields[0]))); - $fields[0] = $hex[1]; - $hex = unpack('H*', pack('v', hexdec($fields[1]))); - $fields[1] = $hex[1]; - $hex = unpack('H*', pack('v', hexdec($fields[2]))); - $fields[2] = $hex[1]; + $this->swapFields($components); return vsprintf( '%08s-%04s-%04s-%02s%02s-%012s', - $fields + $components ); } public function encodeBinary(UuidInterface $uuid) { - $reversed = $this->_decode($this->encode($uuid), false); + $components = array_values($uuid->getFieldsHex()); - return $this->uuidCodec->encodeBinary($reversed); + return hex2bin(implode('', $components)); } public function decode($encodedUuid) { - return $this->_decode($encodedUuid, true); + $components = $this->extractComponents($encodedUuid); + + $this->swapFields($components); + + return $this->getBuilder()->build($this, $this->getFields($components)); } public function decodeBytes($bytes) { - if (strlen($bytes) !== 16) { - throw new InvalidArgumentException('$bytes string should contain 16 characters.'); - } - - $hexUuid = unpack('H*', $bytes); - - return $this->_decode($hexUuid[1], false); + return parent::decode(bin2hex($bytes)); } - private function _decode($hex, $swap) + protected function swapFields(array & $components) { - $nameParsed = str_replace(array( - 'urn:', - 'uuid:', - '{', - '}', - '-' - ), '', $hex); - - // We have stripped out the dashes and are breaking up the string using - // substr(). In this way, we can accept a full hex value that doesn't - // contain dashes. - $components = array( - substr($nameParsed, 0, 8), - substr($nameParsed, 8, 4), - substr($nameParsed, 12, 4), - substr($nameParsed, 16, 4), - substr($nameParsed, 20) - ); - - if ($swap) { - $hex = unpack('H*', pack('V', hexdec($components[0]))); - $components[0] = $hex[1]; - $hex = unpack('H*', pack('v', hexdec($components[1]))); - $components[1] = $hex[1]; - $hex = unpack('H*', pack('v', hexdec($components[2]))); - $components[2] = $hex[1]; - } - - $nameParsed = implode('-', $components); - - if (! Uuid::isValid($nameParsed)) { - throw new InvalidArgumentException('Invalid UUID string: ' . $hex); - } - - $fields = array( - 'time_low' => sprintf('%08s', $components[0]), - 'time_mid' => sprintf('%04s', $components[1]), - 'time_hi_and_version' => sprintf('%04s', $components[2]), - 'clock_seq_hi_and_reserved' => sprintf('%02s', substr($components[3], 0, 2)), - 'clock_seq_low' => sprintf('%02s', substr($components[3], 2)), - 'node' => sprintf('%012s', $components[4]) - ); - - return $this->builder->build($this, $fields); + $hex = unpack('H*', pack('V', hexdec($components[0]))); + $components[0] = $hex[1]; + $hex = unpack('H*', pack('v', hexdec($components[1]))); + $components[1] = $hex[1]; + $hex = unpack('H*', pack('v', hexdec($components[2]))); + $components[2] = $hex[1]; } } diff --git a/src/Codec/StringCodec.php b/src/Codec/StringCodec.php index ce451de..3147f81 100644 --- a/src/Codec/StringCodec.php +++ b/src/Codec/StringCodec.php @@ -3,12 +3,12 @@ namespace Rhumsaa\Uuid\Codec; use InvalidArgumentException; -use Rhumsaa\Uuid\Codec; -use Rhumsaa\Uuid\UuidInterface; -use Rhumsaa\Uuid\Uuid; use Rhumsaa\Uuid\BigNumberConverter; -use Rhumsaa\Uuid\UuidFactory; +use Rhumsaa\Uuid\Codec; +use Rhumsaa\Uuid\Uuid; use Rhumsaa\Uuid\UuidBuilder; +use Rhumsaa\Uuid\UuidInterface; +use Rhumsaa\Uuid\UuidFactory; class StringCodec implements Codec { @@ -32,16 +32,34 @@ class StringCodec implements Codec public function encodeBinary(UuidInterface $uuid) { - $bytes = ''; - - foreach (range(-2, -32, 2) as $step) { - $bytes = chr(hexdec(substr($uuid->getHex(), $step, 2))) . $bytes; - } - - return $bytes; + return hex2bin($uuid->getHex()); } public function decode($encodedUuid) + { + $components = $this->extractComponents($encodedUuid); + $fields = $this->getFields($components); + + return $this->builder->build($this, $fields); + } + + public function decodeBytes($bytes) + { + if (strlen($bytes) !== 16) { + throw new InvalidArgumentException('$bytes string should contain 16 characters.'); + } + + $hexUuid = unpack('H*', $bytes); + + return $this->decode($hexUuid[1]); + } + + protected function getBuilder() + { + return $this->builder; + } + + protected function extractComponents($encodedUuid) { $nameParsed = str_replace(array( 'urn:', @@ -68,7 +86,12 @@ class StringCodec implements Codec throw new InvalidArgumentException('Invalid UUID string: ' . $encodedUuid); } - $fields = array( + return $components; + } + + protected function getFields(array $components) + { + return array( 'time_low' => sprintf('%08s', $components[0]), 'time_mid' => sprintf('%04s', $components[1]), 'time_hi_and_version' => sprintf('%04s', $components[2]), @@ -76,18 +99,5 @@ class StringCodec implements Codec 'clock_seq_low' => sprintf('%02s', substr($components[3], 2)), 'node' => sprintf('%012s', $components[4]) ); - - return $this->builder->build($this, $fields); - } - - public function decodeBytes($bytes) - { - if (strlen($bytes) !== 16) { - throw new InvalidArgumentException('$bytes string should contain 16 characters.'); - } - - $hexUuid = unpack('H*', $bytes); - - return $this->decode($hexUuid[1]); } } diff --git a/src/FeatureSet.php b/src/FeatureSet.php index 7709ad1..bd6c31e 100644 --- a/src/FeatureSet.php +++ b/src/FeatureSet.php @@ -96,7 +96,7 @@ class FeatureSet protected function buildCodec($useGuids = false) { if ($useGuids) { - return new GuidStringCodec($this->builder, $this->buildCodec(false)); + return new GuidStringCodec($this->builder); } return new StringCodec($this->builder); diff --git a/src/Node/FallbackNodeProvider.php b/src/Node/FallbackNodeProvider.php index 947ca9a..dbfbe30 100644 --- a/src/Node/FallbackNodeProvider.php +++ b/src/Node/FallbackNodeProvider.php @@ -4,7 +4,7 @@ namespace Rhumsaa\Uuid\Node; use Rhumsaa\Uuid\NodeProvider; -class FallbackNodeProvider +class FallbackNodeProvider implements NodeProvider { private $nodeProviders; diff --git a/src/Uuid.php b/src/Uuid.php index b5bf67b..8332c2d 100644 --- a/src/Uuid.php +++ b/src/Uuid.php @@ -787,6 +787,7 @@ class Uuid implements UuidInterface, \JsonSerializable if (!preg_match('/' . self::VALID_PATTERN . '/', $uuid)) { return false; } + return true; } diff --git a/src/UuidFactory.php b/src/UuidFactory.php index 6138e09..2f66f0c 100644 --- a/src/UuidFactory.php +++ b/src/UuidFactory.php @@ -21,12 +21,6 @@ class UuidFactory */ private $codec = null; - /** - * - * @var Codec - */ - private $guidCodec = null; - /** * * @var NodeProvider @@ -79,6 +73,11 @@ class UuidFactory $this->uuidBuilder = $features->getBuilder(); } + public function getCodec() + { + return $this->codec; + } + public function setTimeConverter(TimeConverter $converter) { $this->timeConverter = $converter; diff --git a/tests/UuidTest.php b/tests/UuidTest.php index c2f0d6d..05f5744 100644 --- a/tests/UuidTest.php +++ b/tests/UuidTest.php @@ -1294,22 +1294,23 @@ class UuidTest extends TestCase public function testFromLittleEndianBytes() { + $uuidFactory = new UuidFactory(new FeatureSet(false)); + $guidFactory = new UuidFactory(new FeatureSet(true)); + // Check that parsing BE bytes as LE reverses fields - $uuid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); + $uuid = $uuidFactory->fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); $bytes = $uuid->getBytes(); - Uuid::setFactory(new UuidFactory(new FeatureSet(true))); - - $guid = Uuid::fromBytes($bytes); + $guid = $guidFactory->fromBytes($bytes); // First three fields should be reversed $this->assertEquals('b08c6fff-7dc5-e111-9b21-0800200c9a66', $guid->toString()); // Check that parsing LE bytes as LE preserves fields - $guid = Uuid::fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); + $guid = $guidFactory->fromString('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); $bytes = $guid->getBytes(); - $parsedGuid = Uuid::fromBytes($bytes); + $parsedGuid = $guidFactory->fromBytes($bytes); $this->assertEquals($guid->toString(), $parsedGuid->toString()); } From 9df122eb0036ae7d09871347a638220fc1335084 Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Sat, 8 Nov 2014 15:08:06 +0100 Subject: [PATCH 13/30] Remove duplication in UuidFactory --- src/UuidFactory.php | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/UuidFactory.php b/src/UuidFactory.php index 2f66f0c..b1ab8b4 100644 --- a/src/UuidFactory.php +++ b/src/UuidFactory.php @@ -217,13 +217,7 @@ class UuidFactory */ public function uuid3($ns, $name) { - if (!($ns instanceof UuidInterface)) { - $ns = $this->codec->decode($ns); - } - - $hash = md5($ns->getBytes() . $name); - - return $this->uuidFromHashedName($hash, 3); + return $this->uuidFromNsAndName($ns, $name, 3, 'md5'); } /** @@ -253,13 +247,7 @@ class UuidFactory */ public function uuid5($ns, $name) { - if (!($ns instanceof Uuid)) { - $ns = $this->codec->decode($ns); - } - - $hash = sha1($ns->getBytes() . $name); - - return $this->uuidFromHashedName($hash, 5); + return $this->uuidFromNsAndName($ns, $name, 5, 'sha1'); } public function uuid(array $fields) @@ -267,6 +255,17 @@ class UuidFactory return $this->uuidBuilder->build($this->codec, $fields); } + protected function uuidFromNsAndName($ns, $name, $version, $hashFunction) + { + if (!($ns instanceof Uuid)) { + $ns = $this->codec->decode($ns); + } + + $hash = call_user_func($hashFunction, ($ns->getBytes() . $name)); + + return $this->uuidFromHashedName($hash, $version); + } + /** * Returns a version 3 or 5 UUID based on the hash (md5 or sha1) of a * namespace identifier (which is a UUID) and a name (which is a string) From 04c64d6f4570f488818bdf330c118408dc7d82da Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Sat, 8 Nov 2014 15:41:53 +0100 Subject: [PATCH 14/30] Refactor duplicate code --- src/UuidFactory.php | 74 +++++++++++++++++++++++++-------------------- tests/UuidTest.php | 22 ++++++++------ 2 files changed, 54 insertions(+), 42 deletions(-) diff --git a/src/UuidFactory.php b/src/UuidFactory.php index b1ab8b4..a66617f 100644 --- a/src/UuidFactory.php +++ b/src/UuidFactory.php @@ -159,20 +159,7 @@ class UuidFactory */ public function uuid1($node = null, $clockSeq = null) { - if ($node === null) { - $node = $this->nodeProvider->getNode(); - } - - // Convert the node to hex, if it is still an integer - if (is_int($node)) { - $node = sprintf('%012x', $node); - } - - if (! ctype_xdigit($node) || strlen($node) > 12) { - throw new \InvalidArgumentException('Invalid node value'); - } - - $node = strtolower(sprintf('%012s', $node)); + $node = $this->getValidNode($node); if ($clockSeq === null) { // Not using "stable storage"; see RFC 4122, Section 4.2.1.1 @@ -184,15 +171,8 @@ class UuidFactory $timeOfDay = $this->timeProvider->currentTime(); $uuidTime = $this->timeConverter->calculateTime($timeOfDay['sec'], $timeOfDay['usec']); - // Set the version number to 1 - $timeHi = hexdec($uuidTime['hi']) & 0x0fff; - $timeHi &= ~(0xf000); - $timeHi |= 1 << 12; - - // Set the variant to RFC 4122 - $clockSeqHi = ($clockSeq >> 8) & 0x3f; - $clockSeqHi &= ~(0xc0); - $clockSeqHi |= 0x80; + $timeHi = $this->applyVersion($uuidTime['hi'], 1); + $clockSeqHi = $this->applyVariant($clockSeq >> 8); $fields = array( 'time_low' => $uuidTime['low'], @@ -255,6 +235,25 @@ class UuidFactory return $this->uuidBuilder->build($this->codec, $fields); } + protected function applyVariant($clockSeqHi) + { + // Set the variant to RFC 4122 + $clockSeqHi = $clockSeqHi & 0x3f; + $clockSeqHi &= ~(0xc0); + $clockSeqHi |= 0x80; + + return $clockSeqHi; + } + + protected function applyVersion($timeHi, $version) + { + $timeHi = hexdec($timeHi) & 0x0fff; + $timeHi &= ~(0xf000); + $timeHi |= $version << 12; + + return $timeHi; + } + protected function uuidFromNsAndName($ns, $name, $version, $hashFunction) { if (!($ns instanceof Uuid)) { @@ -276,15 +275,8 @@ class UuidFactory */ protected function uuidFromHashedName($hash, $version) { - // Set the version number - $timeHi = hexdec(substr($hash, 12, 4)) & 0x0fff; - $timeHi &= ~(0xf000); - $timeHi |= $version << 12; - - // Set the variant to RFC 4122 - $clockSeqHi = hexdec(substr($hash, 16, 2)) & 0x3f; - $clockSeqHi &= ~(0xc0); - $clockSeqHi |= 0x80; + $timeHi = $this->applyVersion(substr($hash, 12, 4), $version); + $clockSeqHi = $this->applyVariant(hexdec(substr($hash, 16, 2))); $fields = array( 'time_low' => substr($hash, 0, 8), @@ -297,4 +289,22 @@ class UuidFactory return $this->uuid($fields); } + + protected function getValidNode($node) + { + if ($node === null) { + $node = $this->nodeProvider->getNode(); + } + + // Convert the node to hex, if it is still an integer + if (is_int($node)) { + $node = sprintf('%012x', $node); + } + + if (! ctype_xdigit($node) || strlen($node) > 12) { + throw new \InvalidArgumentException('Invalid node value'); + } + + return strtolower(sprintf('%012s', $node)); + } } diff --git a/tests/UuidTest.php b/tests/UuidTest.php index 05f5744..2372b2c 100644 --- a/tests/UuidTest.php +++ b/tests/UuidTest.php @@ -1142,19 +1142,21 @@ class UuidTest extends TestCase $factory = new UuidFactory(); $smallIntFactory = new UuidFactory(new FeatureSet(false, true)); + $timeOfDay = new FixedTimeProvider(array( + 'sec' => $currentTime, + 'usec' => $usec, + 'minuteswest' => 0, + 'dsttime' => 0, + )); + + $factory->setTimeProvider($timeOfDay); + $smallIntFactory->setTimeProvider($timeOfDay); + while ($currentTime <= $endTime) { foreach (array(0, 50000, 250000, 500000, 750000, 999999) as $usec) { - - $timeOfDay = new FixedTimeProvider(array( - 'sec' => $currentTime, - 'usec' => $usec, - 'minuteswest' => 0, - 'dsttime' => 0, - )); - - $factory->setTimeProvider($timeOfDay); - $smallIntFactory->setTimeProvider($timeOfDay); + $timeOfDay->setSec($currentTime); + $timeOfDay->setUsec($usec); $uuid32 = $smallIntFactory->uuid1(0x00007ffffffe, 0x1669); $uuid64 = $factory->uuid1(0x00007ffffffe, 0x1669); From b0192fa9b0e28870b69cd3308216c260f3c807ac Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Sat, 8 Nov 2014 15:42:36 +0100 Subject: [PATCH 15/30] Handle unknown versions --- src/Console/Command/DecodeCommand.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Console/Command/DecodeCommand.php b/src/Console/Command/DecodeCommand.php index d0caad1..22c99c3 100644 --- a/src/Console/Command/DecodeCommand.php +++ b/src/Console/Command/DecodeCommand.php @@ -90,6 +90,8 @@ class DecodeCommand extends Command case 5: $version = '5 (name based, SHA-1)'; break; + default: + $version = 'Invalid or unknown UUID version'; } $table->addRows(array( From ed06e0a84e778859abd66293ee6d789cff43ddb0 Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Sat, 8 Nov 2014 15:50:19 +0100 Subject: [PATCH 16/30] Remove unused code --- src/Uuid.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Uuid.php b/src/Uuid.php index 8332c2d..7ed74ca 100644 --- a/src/Uuid.php +++ b/src/Uuid.php @@ -186,7 +186,7 @@ class Uuid implements UuidInterface, \JsonSerializable */ public function compareTo(UuidInterface $uuid) { - $comparison = null; + $comparison = 0; if ($this->getMostSignificantBitsHex() < $uuid->getMostSignificantBitsHex()) { $comparison = -1; @@ -196,8 +196,6 @@ class Uuid implements UuidInterface, \JsonSerializable $comparison = -1; } elseif ($this->getLeastSignificantBitsHex() > $uuid->getLeastSignificantBitsHex()) { $comparison = 1; - } else { - $comparison = 0; } return $comparison; @@ -396,7 +394,7 @@ class Uuid implements UuidInterface, \JsonSerializable */ public function getHex() { - return str_replace('-', '', $this->toString(true)); + return str_replace('-', '', $this->toString()); } /** From cce58a0b8a1ceb5058022cfa1755deca43654ac1 Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Sat, 8 Nov 2014 15:57:30 +0100 Subject: [PATCH 17/30] Fix doc comments and remove unneeded usings --- src/BigNumberConverter.php | 3 ++ src/Codec.php | 12 ++++++ src/Codec/GuidStringCodec.php | 4 -- src/Codec/StringCodec.php | 2 - src/Console/Command/DecodeCommand.php | 1 - src/Node/SystemNodeProvider.php | 1 + src/RandomGenerator.php | 5 +++ src/Uuid.php | 7 +--- src/UuidBuilder.php | 3 ++ src/UuidFactory.php | 20 ++++----- src/UuidInterface.php | 60 +++++++++++++++++++++++++++ 11 files changed, 95 insertions(+), 23 deletions(-) diff --git a/src/BigNumberConverter.php b/src/BigNumberConverter.php index 0e1b3fd..97551cf 100644 --- a/src/BigNumberConverter.php +++ b/src/BigNumberConverter.php @@ -4,6 +4,9 @@ namespace Rhumsaa\Uuid; class BigNumberConverter { + /** + * @param string $hex + */ public function fromHex($hex) { $number = \Moontoast\Math\BigNumber::baseConvert($hex, 16, 10); diff --git a/src/Codec.php b/src/Codec.php index 9912851..f32800e 100644 --- a/src/Codec.php +++ b/src/Codec.php @@ -4,11 +4,23 @@ namespace Rhumsaa\Uuid; interface Codec { + /** + * @return string + */ public function encode(UuidInterface $uuid); + /** + * @return string + */ public function encodeBinary(UuidInterface $uuid); + /** + * @return callable + */ public function decode($encodedUuid); + /** + * @param string $bytes + */ public function decodeBytes($bytes); } diff --git a/src/Codec/GuidStringCodec.php b/src/Codec/GuidStringCodec.php index ec9e5bd..53999fb 100644 --- a/src/Codec/GuidStringCodec.php +++ b/src/Codec/GuidStringCodec.php @@ -2,12 +2,8 @@ namespace Rhumsaa\Uuid\Codec; -use InvalidArgumentException; use Rhumsaa\Uuid\UuidInterface; use Rhumsaa\Uuid\Uuid; -use Rhumsaa\Uuid\BigNumberConverter; -use Rhumsaa\Uuid\UuidFactory; -use Rhumsaa\Uuid\UuidBuilder; use Rhumsaa\Uuid\Codec; class GuidStringCodec extends StringCodec diff --git a/src/Codec/StringCodec.php b/src/Codec/StringCodec.php index 3147f81..852116b 100644 --- a/src/Codec/StringCodec.php +++ b/src/Codec/StringCodec.php @@ -3,12 +3,10 @@ namespace Rhumsaa\Uuid\Codec; use InvalidArgumentException; -use Rhumsaa\Uuid\BigNumberConverter; use Rhumsaa\Uuid\Codec; use Rhumsaa\Uuid\Uuid; use Rhumsaa\Uuid\UuidBuilder; use Rhumsaa\Uuid\UuidInterface; -use Rhumsaa\Uuid\UuidFactory; class StringCodec implements Codec { diff --git a/src/Console/Command/DecodeCommand.php b/src/Console/Command/DecodeCommand.php index 22c99c3..ff44bf6 100644 --- a/src/Console/Command/DecodeCommand.php +++ b/src/Console/Command/DecodeCommand.php @@ -15,7 +15,6 @@ use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Helper\TableHelper; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Rhumsaa\Uuid\Console\Exception; use Rhumsaa\Uuid\Uuid; diff --git a/src/Node/SystemNodeProvider.php b/src/Node/SystemNodeProvider.php index 819ce9b..dde9753 100644 --- a/src/Node/SystemNodeProvider.php +++ b/src/Node/SystemNodeProvider.php @@ -29,6 +29,7 @@ class SystemNodeProvider implements NodeProvider * @todo Needs evaluation and possibly modification to ensure this works * well across multiple platforms. * @codeCoverageIgnore + * @return string */ protected function getIfconfig() { diff --git a/src/RandomGenerator.php b/src/RandomGenerator.php index 9fac8b9..d703d04 100644 --- a/src/RandomGenerator.php +++ b/src/RandomGenerator.php @@ -4,5 +4,10 @@ namespace Rhumsaa\Uuid; interface RandomGenerator { + /** + * @param integer $length + * + * @return string + */ function generate($length); } diff --git a/src/Uuid.php b/src/Uuid.php index 7ed74ca..ab0c5ca 100644 --- a/src/Uuid.php +++ b/src/Uuid.php @@ -12,8 +12,6 @@ namespace Rhumsaa\Uuid; use InvalidArgumentException; -use Rhumsaa\Uuid\Codec\GuidStringCodec; -use Rhumsaa\Uuid\Codec\StringCodec; /** * Represents a universally unique identifier (UUID), according to RFC 4122 @@ -747,7 +745,6 @@ class Uuid implements UuidInterface, \JsonSerializable * in the toString() method. * * @param string $name A string that specifies a UUID - * @param bool $littleEndian A boolean specifying whether the time_low, time_mid, time_hi_and_version are encoded in little-endian format. * @return Uuid * @throws InvalidArgumentException If the $name isn't a valid UUID */ @@ -813,7 +810,7 @@ class Uuid implements UuidInterface, \JsonSerializable * Generate a version 3 UUID based on the MD5 hash of a namespace identifier (which * is a UUID) and a name (which is a string). * - * @param Uuid|string $ns The UUID namespace in which to create the named UUID + * @param string $ns The UUID namespace in which to create the named UUID * @param string $name The name to create a UUID for * @return Uuid */ @@ -836,7 +833,7 @@ class Uuid implements UuidInterface, \JsonSerializable * Generate a version 5 UUID based on the SHA-1 hash of a namespace identifier (which * is a UUID) and a name (which is a string). * - * @param Uuid|string $ns The UUID namespace in which to create the named UUID + * @param string $ns The UUID namespace in which to create the named UUID * @param string $name The name to create a UUID for * @return Uuid */ diff --git a/src/UuidBuilder.php b/src/UuidBuilder.php index 6f777be..b4f490c 100644 --- a/src/UuidBuilder.php +++ b/src/UuidBuilder.php @@ -4,5 +4,8 @@ namespace Rhumsaa\Uuid; interface UuidBuilder { + /** + * @return Uuid + */ public function build(Codec $codec, array $fields); } diff --git a/src/UuidFactory.php b/src/UuidFactory.php index a66617f..5df3116 100644 --- a/src/UuidFactory.php +++ b/src/UuidFactory.php @@ -2,16 +2,6 @@ namespace Rhumsaa\Uuid; -use Rhumsaa\Uuid\Codec\StringCodec; -use Rhumsaa\Uuid\Codec\GuidStringCodec; -use Rhumsaa\Uuid\Time\PhpTimeConverter; -use Rhumsaa\Uuid\Time\BigNumberTimeConverter; -use Rhumsaa\Uuid\Time\DegradedTimeConverter; -use Rhumsaa\Uuid\Time\SystemTimeProvider; -use Rhumsaa\Uuid\Node\FallbackNodeProvider; -use Rhumsaa\Uuid\Node\SystemNodeProvider; -use Rhumsaa\Uuid\Node\RandomNodeProvider; - class UuidFactory { @@ -125,7 +115,6 @@ class UuidFactory * in the toString() method. * * @param string $name A string that specifies a UUID - * @param bool $littleEndian A boolean specifying whether the time_low, time_mid, time_hi_and_version are encoded in little-endian format. * @return Uuid * @throws InvalidArgumentException If the $name isn't a valid UUID */ @@ -245,6 +234,10 @@ class UuidFactory return $clockSeqHi; } + /** + * @param string $timeHi + * @param integer $version + */ protected function applyVersion($timeHi, $version) { $timeHi = hexdec($timeHi) & 0x0fff; @@ -254,6 +247,11 @@ class UuidFactory return $timeHi; } + /** + * @param string $name + * @param integer $version + * @param string $hashFunction + */ protected function uuidFromNsAndName($ns, $name, $version, $hashFunction) { if (!($ns instanceof Uuid)) { diff --git a/src/UuidInterface.php b/src/UuidInterface.php index 7858fee..4e852e2 100644 --- a/src/UuidInterface.php +++ b/src/UuidInterface.php @@ -5,46 +5,106 @@ namespace Rhumsaa\Uuid; interface UuidInterface { + /** + * @return integer + */ public function compareTo(UuidInterface $other); + /** + * @return boolean + */ public function equals($other); + /** + * @return BigNumberConverter + */ public function getConverter(); + /** + * @return string + */ public function getHex(); public function getFieldsHex(); + /** + * @return string + */ public function getClockSeqHiAndReservedHex(); + /** + * @return string + */ public function getClockSeqLowHex(); + /** + * @return string + */ public function getClockSequenceHex(); + /** + * @return \DateTime + */ public function getDateTime(); + /** + * @return \Moontoast\Math\BigNumber + */ public function getInteger(); + /** + * @return string + */ public function getLeastSignificantBitsHex(); + /** + * @return string + */ public function getMostSignificantBitsHex(); + /** + * @return string + */ public function getNodeHex(); + /** + * @return string + */ public function getTimeHiAndVersionHex(); + /** + * @return string + */ public function getTimeLowHex(); + /** + * @return string + */ public function getTimeMidHex(); + /** + * @return string + */ public function getTimestampHex(); + /** + * @return string + */ public function getUrn(); + /** + * @return integer + */ public function getVariant(); + /** + * @return integer|null + */ public function getVersion(); + /** + * @return string + */ public function toString(); } From 260063c1b5593fe6c231fa1d3a68c80ce0c20ca6 Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Sat, 8 Nov 2014 16:01:48 +0100 Subject: [PATCH 18/30] Fix incorrect return type --- src/Codec.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Codec.php b/src/Codec.php index f32800e..7ac628f 100644 --- a/src/Codec.php +++ b/src/Codec.php @@ -15,12 +15,13 @@ interface Codec public function encodeBinary(UuidInterface $uuid); /** - * @return callable + * @return UuidInterface */ public function decode($encodedUuid); /** * @param string $bytes + * @return UuidInterface */ public function decodeBytes($bytes); } From 6ef25d304065da14b153692bdf47763f5d4919db Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Sat, 8 Nov 2014 16:13:49 +0100 Subject: [PATCH 19/30] Refactor long method --- src/Console/Command/DecodeCommand.php | 59 ++++++++++++++------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/src/Console/Command/DecodeCommand.php b/src/Console/Command/DecodeCommand.php index ff44bf6..e52f341 100644 --- a/src/Console/Command/DecodeCommand.php +++ b/src/Console/Command/DecodeCommand.php @@ -63,34 +63,55 @@ class DecodeCommand extends Command )); if ($uuid->getVariant() != Uuid::RFC_4122) { - $table->addRows(array( array('decode:', 'variant:', 'Not an RFC 4122 UUID'), )); - - $table->render($output); - - return; } + else { + $this->dumpUuid($table, $uuid); + } + + $table->render($output); + } + + protected function dumpUuid($table, $uuid) + { + $content = null; + $version = 'Invalid or unknown UUID version'; switch ($uuid->getVersion()) { case 1: $version = '1 (time and node based)'; + $content = array( + array('', 'content:', 'time: ' . $uuid->getDateTime()->format('c')), + array('', '', 'clock: ' . $uuid->getClockSequence() . ' (usually random)'), + array('', '', 'node: ' . substr(chunk_split($uuid->getNodeHex(), 2, ':'), 0, -1)), + ); break; case 2: $version = '2 (DCE security based)'; break; case 3: $version = '3 (name based, MD5)'; + $content = array( + array('', 'content:', substr(chunk_split($uuid->getHex(), 2, ':'), 0, -1)), + array('', '', '(not decipherable: SHA1 message digest only)'), + ); break; case 4: $version = '4 (random data based)'; + $content = array( + array('', 'content:', substr(chunk_split($uuid->getHex(), 2, ':'), 0, -1)), + array('', '', '(no semantics: random data only)'), + ); break; case 5: $version = '5 (name based, SHA-1)'; + $content = array( + array('', 'content:', substr(chunk_split($uuid->getHex(), 2, ':'), 0, -1)), + array('', '', '(not decipherable: SHA1 message digest only)'), + ); break; - default: - $version = 'Invalid or unknown UUID version'; } $table->addRows(array( @@ -98,28 +119,8 @@ class DecodeCommand extends Command array('', 'version:', $version), )); - if ($uuid->getVersion() == 1) { - $table->addRows(array( - array('', 'content:', 'time: ' . $uuid->getDateTime()->format('c')), - array('', '', 'clock: ' . $uuid->getClockSequence() . ' (usually random)'), - array('', '', 'node: ' . substr(chunk_split($uuid->getNodeHex(), 2, ':'), 0, -1)), - )); + if ($content) { + $table->addRows($content); } - - if ($uuid->getVersion() == 4) { - $table->addRows(array( - array('', 'content:', substr(chunk_split($uuid->getHex(), 2, ':'), 0, -1)), - array('', '', '(no semantics: random data only)'), - )); - } - - if ($uuid->getVersion() == 3 || $uuid->getVersion() == 5) { - $table->addRows(array( - array('', 'content:', substr(chunk_split($uuid->getHex(), 2, ':'), 0, -1)), - array('', '', '(not decipherable: MD5 message digest only)'), - )); - } - - $table->render($output); } } From 61ba69785348f0273b0d3b8c44707cf778ce4548 Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Sat, 8 Nov 2014 16:28:19 +0100 Subject: [PATCH 20/30] Fix decode output for v5 (incorrect hash algo name) --- src/Console/Command/DecodeCommand.php | 2 +- tests/console-mocks/testExecuteForVersion5Uuid.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Console/Command/DecodeCommand.php b/src/Console/Command/DecodeCommand.php index e52f341..e557310 100644 --- a/src/Console/Command/DecodeCommand.php +++ b/src/Console/Command/DecodeCommand.php @@ -95,7 +95,7 @@ class DecodeCommand extends Command $version = '3 (name based, MD5)'; $content = array( array('', 'content:', substr(chunk_split($uuid->getHex(), 2, ':'), 0, -1)), - array('', '', '(not decipherable: SHA1 message digest only)'), + array('', '', '(not decipherable: MD5 message digest only)'), ); break; case 4: diff --git a/tests/console-mocks/testExecuteForVersion5Uuid.txt b/tests/console-mocks/testExecuteForVersion5Uuid.txt index e564146..2498622 100644 --- a/tests/console-mocks/testExecuteForVersion5Uuid.txt +++ b/tests/console-mocks/testExecuteForVersion5Uuid.txt @@ -4,5 +4,5 @@ decode: variant: RFC 4122 version: 5 (name based, SHA-1) content: 88:63:13:e1:3b:8a:53:72:9b:90:0c:9a:ee:19:9e:5d - (not decipherable: MD5 message digest only) + (not decipherable: SHA1 message digest only) ========= ========== ================================================= From cd2d09c356841de7a7cb7a91da5c9c48d910502d Mon Sep 17 00:00:00 2001 From: Ben Ramsey Date: Sat, 8 Nov 2014 14:43:09 -0500 Subject: [PATCH 21/30] Introduce Converter namespace and move Number and Time classes into it --- src/Builder/DefaultUuidBuilder.php | 4 ++-- src/Builder/DegradedUuidBuilder.php | 4 ++-- src/{ => Converter/Number}/BigNumberConverter.php | 6 ++++-- .../Number}/DegradedNumberConverter.php | 11 +++++++---- src/Converter/NumberConverterInterface.php | 10 ++++++++++ src/{ => Converter}/Time/BigNumberTimeConverter.php | 6 +++--- src/{ => Converter}/Time/DegradedTimeConverter.php | 6 +++--- src/{ => Converter}/Time/PhpTimeConverter.php | 6 +++--- .../TimeConverterInterface.php} | 4 ++-- src/DegradedUuid.php | 4 +++- src/FeatureSet.php | 8 +++++--- src/Uuid.php | 5 +++-- src/UuidFactory.php | 12 ++++++++---- src/UuidInterface.php | 6 ++++-- .../Number}/DegradedNumberConverterTest.php | 4 +++- tests/UuidTest.php | 4 ++-- 16 files changed, 64 insertions(+), 36 deletions(-) rename src/{ => Converter/Number}/BigNumberConverter.php (75%) rename src/{ => Converter/Number}/DegradedNumberConverter.php (63%) create mode 100644 src/Converter/NumberConverterInterface.php rename src/{ => Converter}/Time/BigNumberTimeConverter.php (81%) rename src/{ => Converter}/Time/DegradedTimeConverter.php (71%) rename src/{ => Converter}/Time/PhpTimeConverter.php (79%) rename src/{TimeConverter.php => Converter/TimeConverterInterface.php} (81%) rename tests/{ => Converter/Number}/DegradedNumberConverterTest.php (89%) diff --git a/src/Builder/DefaultUuidBuilder.php b/src/Builder/DefaultUuidBuilder.php index 449e68b..b8892e7 100644 --- a/src/Builder/DefaultUuidBuilder.php +++ b/src/Builder/DefaultUuidBuilder.php @@ -2,7 +2,7 @@ namespace Rhumsaa\Uuid\Builder; -use Rhumsaa\Uuid\BigNumberConverter; +use Rhumsaa\Uuid\Converter\NumberConverterInterface; use Rhumsaa\Uuid\Codec; use Rhumsaa\Uuid\Uuid; use Rhumsaa\Uuid\UuidBuilder; @@ -12,7 +12,7 @@ class DefaultUuidBuilder implements UuidBuilder private $converter; - public function __construct(BigNumberConverter $converter) + public function __construct(NumberConverterInterface $converter) { $this->converter = $converter; } diff --git a/src/Builder/DegradedUuidBuilder.php b/src/Builder/DegradedUuidBuilder.php index 8de0218..d5a345e 100644 --- a/src/Builder/DegradedUuidBuilder.php +++ b/src/Builder/DegradedUuidBuilder.php @@ -5,14 +5,14 @@ namespace Rhumsaa\Uuid\Builder; use Rhumsaa\Uuid\UuidBuilder; use Rhumsaa\Uuid\Codec; use Rhumsaa\Uuid\DegradedUuid; -use Rhumsaa\Uuid\BigNumberConverter; +use Rhumsaa\Uuid\Converter\NumberConverterInterface; class DegradedUuidBuilder implements UuidBuilder { private $converter; - public function __construct(BigNumberConverter $converter) + public function __construct(NumberConverterInterface $converter) { $this->converter = $converter; } diff --git a/src/BigNumberConverter.php b/src/Converter/Number/BigNumberConverter.php similarity index 75% rename from src/BigNumberConverter.php rename to src/Converter/Number/BigNumberConverter.php index 97551cf..31189be 100644 --- a/src/BigNumberConverter.php +++ b/src/Converter/Number/BigNumberConverter.php @@ -1,8 +1,10 @@ fields = $fields; $this->codec = $codec; @@ -303,7 +304,7 @@ class Uuid implements UuidInterface, \JsonSerializable return sprintf('%04x', $this->getClockSequence()); } - public function getConverter() + public function getNumberConverter() { return $this->converter; } diff --git a/src/UuidFactory.php b/src/UuidFactory.php index 5df3116..511260b 100644 --- a/src/UuidFactory.php +++ b/src/UuidFactory.php @@ -2,6 +2,10 @@ namespace Rhumsaa\Uuid; +use InvalidArgumentException; +use Rhumsaa\Uuid\Converter\NumberConverterInterface; +use Rhumsaa\Uuid\Converter\TimeConverterInterface; + class UuidFactory { @@ -19,7 +23,7 @@ class UuidFactory /** * - * @var BigNumberConverter + * @var NumberConverterInterface */ private $numberConverter = null; @@ -30,7 +34,7 @@ class UuidFactory /** * - * @var TimeConverter + * @var TimeConverterInterface */ private $timeConverter = null; @@ -68,7 +72,7 @@ class UuidFactory return $this->codec; } - public function setTimeConverter(TimeConverter $converter) + public function setTimeConverter(TimeConverterInterface $converter) { $this->timeConverter = $converter; } @@ -88,7 +92,7 @@ class UuidFactory $this->nodeProvider = $provider; } - public function setNumberConverter(BigNumberConverter $converter) + public function setNumberConverter(NumberConverterInterface $converter) { $this->numberConverter = $converter; } diff --git a/src/UuidInterface.php b/src/UuidInterface.php index 4e852e2..20ba807 100644 --- a/src/UuidInterface.php +++ b/src/UuidInterface.php @@ -2,6 +2,8 @@ namespace Rhumsaa\Uuid; +use Rhumsaa\Uuid\Converter\NumberConverterInterface; + interface UuidInterface { @@ -16,9 +18,9 @@ interface UuidInterface public function equals($other); /** - * @return BigNumberConverter + * @return NumberConverterInterface */ - public function getConverter(); + public function getNumberConverter(); /** * @return string diff --git a/tests/DegradedNumberConverterTest.php b/tests/Converter/Number/DegradedNumberConverterTest.php similarity index 89% rename from tests/DegradedNumberConverterTest.php rename to tests/Converter/Number/DegradedNumberConverterTest.php index 8f14ceb..0ebef84 100644 --- a/tests/DegradedNumberConverterTest.php +++ b/tests/Converter/Number/DegradedNumberConverterTest.php @@ -1,6 +1,8 @@ assertInstanceOf('Rhumsaa\Uuid\DegradedUuid', $uuid); - $this->assertInstanceOf('Rhumsaa\Uuid\DegradedNumberConverter', $uuid->getConverter()); + $this->assertInstanceOf('Rhumsaa\Uuid\Converter\Number\DegradedNumberConverter', $uuid->getNumberConverter()); $date = $uuid->getDateTime(); } @@ -1687,7 +1687,7 @@ class UuidTest extends TestCase /** * @expectedException Rhumsaa\Uuid\Exception\UnsatisfiedDependencyException - * @expectedExceptionMessage Cannot call Rhumsaa\Uuid\DegradedNumberConverter::fromHex without support for large integers + * @expectedExceptionMessage Cannot call Rhumsaa\Uuid\Converter\Number\DegradedNumberConverter::fromHex without support for large integers */ public function testGetInteger() { From 90fd1531d00338660f66bebfaa2fd23f39f4a8d8 Mon Sep 17 00:00:00 2001 From: Ben Ramsey Date: Sat, 8 Nov 2014 14:53:12 -0500 Subject: [PATCH 22/30] Fixing PSR2 standards violations reported by PHP_CodeSniffer --- composer.json | 1 + phpcs.xml | 15 +++++++++++++++ src/Console/Command/DecodeCommand.php | 3 +-- src/Console/Command/GenerateCommand.php | 6 ++++-- src/Converter/NumberConverterInterface.php | 2 +- src/DegradedUuid.php | 9 +++++---- src/FeatureSet.php | 11 +++++++---- src/RandomGenerator.php | 2 +- src/Uuid.php | 3 ++- src/UuidInterface.php | 1 - 10 files changed, 37 insertions(+), 16 deletions(-) create mode 100644 phpcs.xml diff --git a/composer.json b/composer.json index 41c32a4..b57eaf8 100644 --- a/composer.json +++ b/composer.json @@ -27,6 +27,7 @@ "symfony/console": "~2.3", "doctrine/dbal": ">=2.3", "phpunit/phpunit": "~4.1", + "squizlabs/php_codesniffer": "2.0.0RC4", "satooshi/php-coveralls": "~0.6" }, "bin": ["bin/uuid"], diff --git a/phpcs.xml b/phpcs.xml new file mode 100644 index 0000000..6aa2b59 --- /dev/null +++ b/phpcs.xml @@ -0,0 +1,15 @@ + + + + Coding standard rules for Rhumsaa\Uuid + + */build/* + */tests/* + */vendor/* + + + + + + + diff --git a/src/Console/Command/DecodeCommand.php b/src/Console/Command/DecodeCommand.php index e557310..f1ed843 100644 --- a/src/Console/Command/DecodeCommand.php +++ b/src/Console/Command/DecodeCommand.php @@ -66,8 +66,7 @@ class DecodeCommand extends Command $table->addRows(array( array('decode:', 'variant:', 'Not an RFC 4122 UUID'), )); - } - else { + } else { $this->dumpUuid($table, $uuid); } diff --git a/src/Console/Command/GenerateCommand.php b/src/Console/Command/GenerateCommand.php index 4dc20a9..78a1669 100644 --- a/src/Console/Command/GenerateCommand.php +++ b/src/Console/Command/GenerateCommand.php @@ -159,9 +159,11 @@ class GenerateCommand extends Command return $namespace; } - throw new Exception('Invalid namespace. ' + throw new Exception( + 'Invalid namespace. ' . 'May be either a UUID in string representation or an identifier ' . 'for internally pre-defined namespace UUIDs (currently known ' - . 'are "ns:DNS", "ns:URL", "ns:OID", and "ns:X500").'); + . 'are "ns:DNS", "ns:URL", "ns:OID", and "ns:X500").' + ); } } diff --git a/src/Converter/NumberConverterInterface.php b/src/Converter/NumberConverterInterface.php index 5a3ae89..b111a8f 100644 --- a/src/Converter/NumberConverterInterface.php +++ b/src/Converter/NumberConverterInterface.php @@ -7,4 +7,4 @@ interface NumberConverterInterface public function fromHex($hex); public function toHex($integer); -} \ No newline at end of file +} diff --git a/src/DegradedUuid.php b/src/DegradedUuid.php index 9c9ff80..df7a841 100644 --- a/src/DegradedUuid.php +++ b/src/DegradedUuid.php @@ -22,7 +22,8 @@ class DegradedUuid extends Uuid * * @return \DateTime A PHP DateTime representation of the date * @throws Exception\UnsupportedOperationException If this UUID is not a version 1 UUID - * @throws Exception\UnsatisfiedDependencyException if called on a 32-bit system and Moontoast\Math\BigNumber is not present + * @throws Exception\UnsatisfiedDependencyException if called on a 32-bit system and + * Moontoast\Math\BigNumber is not present */ public function getDateTime() { @@ -63,9 +64,9 @@ class DegradedUuid extends Uuid public function getFields() { throw new Exception\UnsatisfiedDependencyException( - 'Cannot call ' . __METHOD__ . ' on a 32-bit system, since some ' - . 'values overflow the system max integer value' - . '; consider calling getFieldsHex instead' + 'Cannot call ' . __METHOD__ . ' on a 32-bit system, since some ' + . 'values overflow the system max integer value' + . '; consider calling getFieldsHex instead' ); } diff --git a/src/FeatureSet.php b/src/FeatureSet.php index cfbc8ba..4a29f88 100644 --- a/src/FeatureSet.php +++ b/src/FeatureSet.php @@ -45,8 +45,12 @@ class FeatureSet private $timeProvider; - public function __construct($useGuids = false, $force32Bit = false, $forceNoBigNumber = false, $ignoreSystemNode = false) - { + public function __construct( + $useGuids = false, + $force32Bit = false, + $forceNoBigNumber = false, + $ignoreSystemNode = false + ) { $this->disableBigNumber = $forceNoBigNumber; $this->disable64Bit = $force32Bit; $this->ignoreSystemNode = $ignoreSystemNode; @@ -134,8 +138,7 @@ class FeatureSet { if ($this->is64BitSystem()) { return new PhpTimeConverter(); - } - elseif ($this->hasBigNumber()) { + } elseif ($this->hasBigNumber()) { return new BigNumberTimeConverter(); } diff --git a/src/RandomGenerator.php b/src/RandomGenerator.php index d703d04..5f7521c 100644 --- a/src/RandomGenerator.php +++ b/src/RandomGenerator.php @@ -9,5 +9,5 @@ interface RandomGenerator * * @return string */ - function generate($length); + public function generate($length); } diff --git a/src/Uuid.php b/src/Uuid.php index 75acb84..88b18eb 100644 --- a/src/Uuid.php +++ b/src/Uuid.php @@ -319,7 +319,8 @@ class Uuid implements UuidInterface, \JsonSerializable * * @return \DateTime A PHP DateTime representation of the date * @throws Exception\UnsupportedOperationException If this UUID is not a version 1 UUID - * @throws Exception\UnsatisfiedDependencyException if called on a 32-bit system and Moontoast\Math\BigNumber is not present + * @throws Exception\UnsatisfiedDependencyException if called on a 32-bit system and + * Moontoast\Math\BigNumber is not present */ public function getDateTime() { diff --git a/src/UuidInterface.php b/src/UuidInterface.php index 20ba807..4670e7e 100644 --- a/src/UuidInterface.php +++ b/src/UuidInterface.php @@ -108,5 +108,4 @@ interface UuidInterface * @return string */ public function toString(); - } From 958643e7b654247865390a41de2481107c05c478 Mon Sep 17 00:00:00 2001 From: Ben Ramsey Date: Sat, 8 Nov 2014 16:16:44 -0500 Subject: [PATCH 23/30] Introduce Provider namespace and move Node and Time classes into it --- src/FeatureSet.php | 8 ++++---- src/NodeProvider.php | 8 -------- src/{ => Provider}/Node/FallbackNodeProvider.php | 6 +++--- src/{ => Provider}/Node/RandomNodeProvider.php | 6 +++--- src/{ => Provider}/Node/SystemNodeProvider.php | 6 +++--- src/Provider/NodeProviderInterface.php | 8 ++++++++ src/{ => Provider}/Time/FixedTimeProvider.php | 6 +++--- src/Provider/Time/SystemTimeProvider.php | 13 +++++++++++++ .../TimeProviderInterface.php} | 4 ++-- src/Time/SystemTimeProvider.php | 13 ------------- src/UuidFactory.php | 10 ++++++---- tests/UuidTest.php | 4 ++-- 12 files changed, 47 insertions(+), 45 deletions(-) delete mode 100644 src/NodeProvider.php rename src/{ => Provider}/Node/FallbackNodeProvider.php (71%) rename src/{ => Provider}/Node/RandomNodeProvider.php (65%) rename src/{ => Provider}/Node/SystemNodeProvider.php (89%) create mode 100644 src/Provider/NodeProviderInterface.php rename src/{ => Provider}/Time/FixedTimeProvider.php (80%) create mode 100644 src/Provider/Time/SystemTimeProvider.php rename src/{TimeProvider.php => Provider/TimeProviderInterface.php} (71%) delete mode 100644 src/Time/SystemTimeProvider.php diff --git a/src/FeatureSet.php b/src/FeatureSet.php index 4a29f88..50f855d 100644 --- a/src/FeatureSet.php +++ b/src/FeatureSet.php @@ -2,15 +2,15 @@ namespace Rhumsaa\Uuid; -use Rhumsaa\Uuid\Node\FallbackNodeProvider; -use Rhumsaa\Uuid\Node\RandomNodeProvider; -use Rhumsaa\Uuid\Node\SystemNodeProvider; +use Rhumsaa\Uuid\Provider\Node\FallbackNodeProvider; +use Rhumsaa\Uuid\Provider\Node\RandomNodeProvider; +use Rhumsaa\Uuid\Provider\Node\SystemNodeProvider; use Rhumsaa\Uuid\Converter\Number\BigNumberConverter; use Rhumsaa\Uuid\Converter\Number\DegradedNumberConverter; use Rhumsaa\Uuid\Converter\Time\BigNumberTimeConverter; use Rhumsaa\Uuid\Converter\Time\DegradedTimeConverter; use Rhumsaa\Uuid\Converter\Time\PhpTimeConverter; -use Rhumsaa\Uuid\Time\SystemTimeProvider; +use Rhumsaa\Uuid\Provider\Time\SystemTimeProvider; use Rhumsaa\Uuid\Builder\DefaultUuidBuilder; use Rhumsaa\Uuid\Codec\StringCodec; use Rhumsaa\Uuid\Codec\GuidStringCodec; diff --git a/src/NodeProvider.php b/src/NodeProvider.php deleted file mode 100644 index 70f58d2..0000000 --- a/src/NodeProvider.php +++ /dev/null @@ -1,8 +0,0 @@ -timeConverter = $converter; } - public function setTimeProvider(TimeProvider $provider) + public function setTimeProvider(TimeProviderInterface $provider) { $this->timeProvider = $provider; } @@ -87,7 +89,7 @@ class UuidFactory $this->randomGenerator = $generator; } - public function setNodeProvider(NodeProvider $provider) + public function setNodeProvider(NodeProviderInterface $provider) { $this->nodeProvider = $provider; } diff --git a/tests/UuidTest.php b/tests/UuidTest.php index eb6e410..8d609fe 100644 --- a/tests/UuidTest.php +++ b/tests/UuidTest.php @@ -2,8 +2,8 @@ namespace Rhumsaa\Uuid; -use Rhumsaa\Uuid\Time\SystemTimeProvider; -use Rhumsaa\Uuid\Time\FixedTimeProvider; +use Rhumsaa\Uuid\Provider\Time\SystemTimeProvider; +use Rhumsaa\Uuid\Provider\Time\FixedTimeProvider; class UuidTest extends TestCase { From ebea9b969bc5c761fc199f8f23a566418d293623 Mon Sep 17 00:00:00 2001 From: Ben Ramsey Date: Sat, 8 Nov 2014 16:24:22 -0500 Subject: [PATCH 24/30] Add ircmaxell-RandomLib to the dev dependencies --- composer.json | 2 ++ src/Generator/RandomLibAdapter.php | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index b57eaf8..c8737ec 100644 --- a/composer.json +++ b/composer.json @@ -24,6 +24,7 @@ }, "require-dev": { "moontoast/math": "~1.1", + "ircmaxell/random-lib": "~1.0", "symfony/console": "~2.3", "doctrine/dbal": ">=2.3", "phpunit/phpunit": "~4.1", @@ -33,6 +34,7 @@ "bin": ["bin/uuid"], "suggest": { "moontoast/math": "Support for converting UUID to 128-bit integer (in string form).", + "ircmaxell/random-lib": "Provides RandomLib to use with the RandomLibAdapter", "symfony/console": "Support for use of the bin/uuid command line tool.", "doctrine/dbal": "Allow the use of a UUID as doctrine field type." }, diff --git a/src/Generator/RandomLibAdapter.php b/src/Generator/RandomLibAdapter.php index 8dac106..4bab073 100644 --- a/src/Generator/RandomLibAdapter.php +++ b/src/Generator/RandomLibAdapter.php @@ -1,9 +1,10 @@ Date: Sat, 8 Nov 2014 16:27:20 -0500 Subject: [PATCH 25/30] Interfaces should have the suffix "Interface" in their names --- src/Builder/DefaultUuidBuilder.php | 4 ++-- src/Builder/DegradedUuidBuilder.php | 4 ++-- src/Codec/GuidStringCodec.php | 2 +- src/Codec/StringCodec.php | 4 ++-- src/{Codec.php => CodecInterface.php} | 2 +- src/DegradedUuid.php | 2 +- src/Generator/MtRandGenerator.php | 4 ++-- src/Generator/OpenSslGenerator.php | 4 ++-- src/Generator/RandomLibAdapter.php | 4 ++-- src/{RandomGenerator.php => RandomGeneratorInterface.php} | 2 +- src/Uuid.php | 6 +++--- src/UuidBuilder.php | 2 +- src/UuidFactory.php | 6 +++--- 13 files changed, 23 insertions(+), 23 deletions(-) rename src/{Codec.php => CodecInterface.php} (94%) rename src/{RandomGenerator.php => RandomGeneratorInterface.php} (81%) diff --git a/src/Builder/DefaultUuidBuilder.php b/src/Builder/DefaultUuidBuilder.php index b8892e7..0cf6720 100644 --- a/src/Builder/DefaultUuidBuilder.php +++ b/src/Builder/DefaultUuidBuilder.php @@ -3,7 +3,7 @@ namespace Rhumsaa\Uuid\Builder; use Rhumsaa\Uuid\Converter\NumberConverterInterface; -use Rhumsaa\Uuid\Codec; +use Rhumsaa\Uuid\CodecInterface; use Rhumsaa\Uuid\Uuid; use Rhumsaa\Uuid\UuidBuilder; @@ -17,7 +17,7 @@ class DefaultUuidBuilder implements UuidBuilder $this->converter = $converter; } - public function build(Codec $codec, array $fields) + public function build(CodecInterface $codec, array $fields) { return new Uuid($fields, $this->converter, $codec); } diff --git a/src/Builder/DegradedUuidBuilder.php b/src/Builder/DegradedUuidBuilder.php index d5a345e..21751ab 100644 --- a/src/Builder/DegradedUuidBuilder.php +++ b/src/Builder/DegradedUuidBuilder.php @@ -3,7 +3,7 @@ namespace Rhumsaa\Uuid\Builder; use Rhumsaa\Uuid\UuidBuilder; -use Rhumsaa\Uuid\Codec; +use Rhumsaa\Uuid\CodecInterface; use Rhumsaa\Uuid\DegradedUuid; use Rhumsaa\Uuid\Converter\NumberConverterInterface; @@ -17,7 +17,7 @@ class DegradedUuidBuilder implements UuidBuilder $this->converter = $converter; } - public function build(Codec $codec, array $fields) + public function build(CodecInterface $codec, array $fields) { return new DegradedUuid($fields, $this->converter, $codec); } diff --git a/src/Codec/GuidStringCodec.php b/src/Codec/GuidStringCodec.php index 53999fb..023a896 100644 --- a/src/Codec/GuidStringCodec.php +++ b/src/Codec/GuidStringCodec.php @@ -4,7 +4,7 @@ namespace Rhumsaa\Uuid\Codec; use Rhumsaa\Uuid\UuidInterface; use Rhumsaa\Uuid\Uuid; -use Rhumsaa\Uuid\Codec; +use Rhumsaa\Uuid\CodecInterface; class GuidStringCodec extends StringCodec { diff --git a/src/Codec/StringCodec.php b/src/Codec/StringCodec.php index 852116b..d9eb62d 100644 --- a/src/Codec/StringCodec.php +++ b/src/Codec/StringCodec.php @@ -3,12 +3,12 @@ namespace Rhumsaa\Uuid\Codec; use InvalidArgumentException; -use Rhumsaa\Uuid\Codec; +use Rhumsaa\Uuid\CodecInterface; use Rhumsaa\Uuid\Uuid; use Rhumsaa\Uuid\UuidBuilder; use Rhumsaa\Uuid\UuidInterface; -class StringCodec implements Codec +class StringCodec implements CodecInterface { private $builder; diff --git a/src/Codec.php b/src/CodecInterface.php similarity index 94% rename from src/Codec.php rename to src/CodecInterface.php index 7ac628f..cb934ec 100644 --- a/src/Codec.php +++ b/src/CodecInterface.php @@ -2,7 +2,7 @@ namespace Rhumsaa\Uuid; -interface Codec +interface CodecInterface { /** * @return string diff --git a/src/DegradedUuid.php b/src/DegradedUuid.php index df7a841..e19e57e 100644 --- a/src/DegradedUuid.php +++ b/src/DegradedUuid.php @@ -7,7 +7,7 @@ use Rhumsaa\Uuid\Converter\NumberConverterInterface; class DegradedUuid extends Uuid { - public function __construct(array $fields, NumberConverterInterface $converter, Codec $codec) + public function __construct(array $fields, NumberConverterInterface $converter, CodecInterface $codec) { parent::__construct($fields, $converter, $codec); } diff --git a/src/Generator/MtRandGenerator.php b/src/Generator/MtRandGenerator.php index af24dcc..c5e7c03 100644 --- a/src/Generator/MtRandGenerator.php +++ b/src/Generator/MtRandGenerator.php @@ -2,9 +2,9 @@ namespace Rhumsaa\Uuid\Generator; -use Rhumsaa\Uuid\RandomGenerator; +use Rhumsaa\Uuid\RandomGeneratorInterface; -class MtRandGenerator implements RandomGenerator +class MtRandGenerator implements RandomGeneratorInterface { public function generate($length) { diff --git a/src/Generator/OpenSslGenerator.php b/src/Generator/OpenSslGenerator.php index 200f8c0..8211d6f 100644 --- a/src/Generator/OpenSslGenerator.php +++ b/src/Generator/OpenSslGenerator.php @@ -2,9 +2,9 @@ namespace Rhumsaa\Uuid\Generator; -use Rhumsaa\Uuid\RandomGenerator; +use Rhumsaa\Uuid\RandomGeneratorInterface; -class OpenSslGenerator implements RandomGenerator +class OpenSslGenerator implements RandomGeneratorInterface { public function generate($length) diff --git a/src/Generator/RandomLibAdapter.php b/src/Generator/RandomLibAdapter.php index 4bab073..710a400 100644 --- a/src/Generator/RandomLibAdapter.php +++ b/src/Generator/RandomLibAdapter.php @@ -4,9 +4,9 @@ namespace Rhumsaa\Uuid\Generator; use RandomLib\Generator; use RandomLib\Factory; -use Rhumsaa\Uuid\RandomGenerator; +use Rhumsaa\Uuid\RandomGeneratorInterface; -class RandomLibAdapter implements RandomGenerator +class RandomLibAdapter implements RandomGeneratorInterface { private $generator; diff --git a/src/RandomGenerator.php b/src/RandomGeneratorInterface.php similarity index 81% rename from src/RandomGenerator.php rename to src/RandomGeneratorInterface.php index 5f7521c..3a1e529 100644 --- a/src/RandomGenerator.php +++ b/src/RandomGeneratorInterface.php @@ -2,7 +2,7 @@ namespace Rhumsaa\Uuid; -interface RandomGenerator +interface RandomGeneratorInterface { /** * @param integer $length diff --git a/src/Uuid.php b/src/Uuid.php index 88b18eb..0da5200 100644 --- a/src/Uuid.php +++ b/src/Uuid.php @@ -105,7 +105,7 @@ class Uuid implements UuidInterface, \JsonSerializable /** * String codec - * @var Codec + * @var CodecInterface */ protected $codec; @@ -135,10 +135,10 @@ class Uuid implements UuidInterface, \JsonSerializable * UUIDs. * * @param array $fields - * @param Codec $codec String codec + * @param CodecInterface $codec String codec * @link Rhumsaa.Uuid.Uuid.html#method_getFields */ - public function __construct(array $fields, NumberConverterInterface $converter, Codec $codec) + public function __construct(array $fields, NumberConverterInterface $converter, CodecInterface $codec) { $this->fields = $fields; $this->codec = $codec; diff --git a/src/UuidBuilder.php b/src/UuidBuilder.php index b4f490c..29b253b 100644 --- a/src/UuidBuilder.php +++ b/src/UuidBuilder.php @@ -7,5 +7,5 @@ interface UuidBuilder /** * @return Uuid */ - public function build(Codec $codec, array $fields); + public function build(CodecInterface $codec, array $fields); } diff --git a/src/UuidFactory.php b/src/UuidFactory.php index 74bcc75..5919968 100644 --- a/src/UuidFactory.php +++ b/src/UuidFactory.php @@ -13,7 +13,7 @@ class UuidFactory /** * - * @var Codec + * @var CodecInterface */ private $codec = null; @@ -30,7 +30,7 @@ class UuidFactory private $numberConverter = null; /** - * @var RandomGenerator + * @var RandomGeneratorInterface */ private $randomGenerator = null; @@ -84,7 +84,7 @@ class UuidFactory $this->timeProvider = $provider; } - public function setRandomGenerator(RandomGenerator $generator) + public function setRandomGenerator(RandomGeneratorInterface $generator) { $this->randomGenerator = $generator; } From 39c98bb652a48b91d1b060068df581873b22239c Mon Sep 17 00:00:00 2001 From: Ben Ramsey Date: Sat, 8 Nov 2014 16:50:04 -0500 Subject: [PATCH 26/30] Add phpcs.xml to the .gitattributes ignore list --- .gitattributes | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitattributes b/.gitattributes index bc2c43f..60c2a77 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,4 +3,5 @@ /.travis.yml export-ignore /tests export-ignore /phpunit.xml.dist export-ignore +/phpcs.xml export-ignore /apigen.neon export-ignore From 2069071f667d77a28991d1afc96ff1b3a8df9507 Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Sun, 9 Nov 2014 11:03:09 +0100 Subject: [PATCH 27/30] Remove unneeded parent class --- src/Converter/Number/DegradedNumberConverter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Converter/Number/DegradedNumberConverter.php b/src/Converter/Number/DegradedNumberConverter.php index 9e6da9f..043fc7c 100644 --- a/src/Converter/Number/DegradedNumberConverter.php +++ b/src/Converter/Number/DegradedNumberConverter.php @@ -5,7 +5,7 @@ namespace Rhumsaa\Uuid\Converter\Number; use Rhumsaa\Uuid\Exception\UnsatisfiedDependencyException; use Rhumsaa\Uuid\Converter\NumberConverterInterface; -class DegradedNumberConverter extends BigNumberConverter implements NumberConverterInterface +class DegradedNumberConverter implements NumberConverterInterface { public function fromHex($hex) { From 463aa47338ff749fdfd6c248a6c2658680f6f7a6 Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Sun, 9 Nov 2014 11:31:08 +0100 Subject: [PATCH 28/30] Extract classes for CLI rendering --- src/Console/Command/DecodeCommand.php | 65 +------------- src/Console/Util/Formatter/V1Formatter.php | 19 ++++ src/Console/Util/Formatter/V2Formatter.php | 15 ++++ src/Console/Util/Formatter/V3Formatter.php | 18 ++++ src/Console/Util/Formatter/V4Formatter.php | 18 ++++ src/Console/Util/Formatter/V5Formatter.php | 18 ++++ .../Util/UuidContentFormatterInterface.php | 10 +++ src/Console/Util/UuidFormatter.php | 88 +++++++++++++++++++ 8 files changed, 189 insertions(+), 62 deletions(-) create mode 100644 src/Console/Util/Formatter/V1Formatter.php create mode 100644 src/Console/Util/Formatter/V2Formatter.php create mode 100644 src/Console/Util/Formatter/V3Formatter.php create mode 100644 src/Console/Util/Formatter/V4Formatter.php create mode 100644 src/Console/Util/Formatter/V5Formatter.php create mode 100644 src/Console/Util/UuidContentFormatterInterface.php create mode 100644 src/Console/Util/UuidFormatter.php diff --git a/src/Console/Command/DecodeCommand.php b/src/Console/Command/DecodeCommand.php index f1ed843..3cd0f26 100644 --- a/src/Console/Command/DecodeCommand.php +++ b/src/Console/Command/DecodeCommand.php @@ -18,6 +18,8 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Rhumsaa\Uuid\Console\Exception; use Rhumsaa\Uuid\Uuid; +use Rhumsaa\Uuid\Console\Util\UuidFormatter; +use Symfony\Component\Console\Helper\Table; /** * Provides the console command to decode UUIDs and dump information about them @@ -57,69 +59,8 @@ class DecodeCommand extends Command $table = $this->getHelperSet()->get('table'); $table->setLayout(TableHelper::LAYOUT_BORDERLESS); - $table->addRows(array( - array('encode:', 'STR:', (string) $uuid), - array('', 'INT:', (string) $uuid->getInteger()), - )); - - if ($uuid->getVariant() != Uuid::RFC_4122) { - $table->addRows(array( - array('decode:', 'variant:', 'Not an RFC 4122 UUID'), - )); - } else { - $this->dumpUuid($table, $uuid); - } + (new UuidFormatter())->write($table, $uuid); $table->render($output); } - - protected function dumpUuid($table, $uuid) - { - $content = null; - $version = 'Invalid or unknown UUID version'; - - switch ($uuid->getVersion()) { - case 1: - $version = '1 (time and node based)'; - $content = array( - array('', 'content:', 'time: ' . $uuid->getDateTime()->format('c')), - array('', '', 'clock: ' . $uuid->getClockSequence() . ' (usually random)'), - array('', '', 'node: ' . substr(chunk_split($uuid->getNodeHex(), 2, ':'), 0, -1)), - ); - break; - case 2: - $version = '2 (DCE security based)'; - break; - case 3: - $version = '3 (name based, MD5)'; - $content = array( - array('', 'content:', substr(chunk_split($uuid->getHex(), 2, ':'), 0, -1)), - array('', '', '(not decipherable: MD5 message digest only)'), - ); - break; - case 4: - $version = '4 (random data based)'; - $content = array( - array('', 'content:', substr(chunk_split($uuid->getHex(), 2, ':'), 0, -1)), - array('', '', '(no semantics: random data only)'), - ); - break; - case 5: - $version = '5 (name based, SHA-1)'; - $content = array( - array('', 'content:', substr(chunk_split($uuid->getHex(), 2, ':'), 0, -1)), - array('', '', '(not decipherable: SHA1 message digest only)'), - ); - break; - } - - $table->addRows(array( - array('decode:', 'variant:', 'RFC 4122'), - array('', 'version:', $version), - )); - - if ($content) { - $table->addRows($content); - } - } } diff --git a/src/Console/Util/Formatter/V1Formatter.php b/src/Console/Util/Formatter/V1Formatter.php new file mode 100644 index 0000000..4c27c00 --- /dev/null +++ b/src/Console/Util/Formatter/V1Formatter.php @@ -0,0 +1,19 @@ +getDateTime()->format('c')), + array('', '', 'clock: ' . $uuid->getClockSequence() . ' (usually random)'), + array('', '', 'node: ' . substr(chunk_split($uuid->getNodeHex(), 2, ':'), 0, -1)), + ); + } +} diff --git a/src/Console/Util/Formatter/V2Formatter.php b/src/Console/Util/Formatter/V2Formatter.php new file mode 100644 index 0000000..3362028 --- /dev/null +++ b/src/Console/Util/Formatter/V2Formatter.php @@ -0,0 +1,15 @@ +getHex(), 2, ':'), 0, -1)), + array('', '', '(not decipherable: MD5 message digest only)'), + ); + } +} diff --git a/src/Console/Util/Formatter/V4Formatter.php b/src/Console/Util/Formatter/V4Formatter.php new file mode 100644 index 0000000..4bce8ca --- /dev/null +++ b/src/Console/Util/Formatter/V4Formatter.php @@ -0,0 +1,18 @@ +getHex(), 2, ':'), 0, -1)), + array('', '', '(no semantics: random data only)'), + ); + } +} diff --git a/src/Console/Util/Formatter/V5Formatter.php b/src/Console/Util/Formatter/V5Formatter.php new file mode 100644 index 0000000..bf99c78 --- /dev/null +++ b/src/Console/Util/Formatter/V5Formatter.php @@ -0,0 +1,18 @@ +getHex(), 2, ':'), 0, -1)), + array('', '', '(not decipherable: SHA1 message digest only)'), + ); + } +} diff --git a/src/Console/Util/UuidContentFormatterInterface.php b/src/Console/Util/UuidContentFormatterInterface.php new file mode 100644 index 0000000..ae74ca6 --- /dev/null +++ b/src/Console/Util/UuidContentFormatterInterface.php @@ -0,0 +1,10 @@ + '1 (time and node based)', + 2 => '2 (DCE security based)', + 3 => '3 (name based, MD5)', + 4 => '4 (random data based)', + 5 => '5 (name based, SHA-1)' + ]; + + private static $variantMap = [ + Uuid::RESERVED_NCS => 'Reserved', + Uuid::RFC_4122 => 'RFC 4122', + Uuid::RESERVED_MICROSOFT => 'Reserved for Microsoft use.', + Uuid::RESERVED_FUTURE => 'Reserved for future use.' + ]; + + private static $formatters; + + public function __construct() + { + if (self::$formatters == null) { + self::$formatters = [ + 1 => new V1Formatter(), + 2 => new V2Formatter(), + 3 => new V3Formatter(), + 4 => new V4Formatter(), + 5 => new V5Formatter() + ]; + } + } + + public function write(TableHelper $table, UuidInterface $uuid) + { + $table->addRows(array( + array('encode:', 'STR:', (string) $uuid), + array('', 'INT:', (string) $uuid->getInteger()), + )); + + if ($uuid->getVariant() == Uuid::RFC_4122) { + $table->addRows(array( + array('decode:', 'variant:',$this->getFormattedVariant($uuid)), + array('', 'version:', $this->getFormattedVersion($uuid)), + )); + + $table->addRows($this->getContent($uuid)); + } + else { + $table->addRows(array( + array('decode:', 'variant:', 'Not an RFC 4122 UUID'), + )); + } + } + + public function getFormattedVersion(UuidInterface $uuid) + { + return self::$versionMap[$uuid->getVersion()]; + } + + public function getFormattedVariant(UuidInterface $uuid) + { + return self::$variantMap[$uuid->getVariant()]; + } + + /** + * Returns content as an array of rows, each row being an array containing column values. + */ + public function getContent(UuidInterface $uuid) + { + $formatter = self::$formatters[$uuid->getVersion()]; + + return $formatter->getContent($uuid); + } +} From 3ca7eaa0702fcd68733e6c00a9bbbdbe37571ee1 Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Sun, 9 Nov 2014 11:34:28 +0100 Subject: [PATCH 29/30] Fix PHPCS violation --- src/Console/Util/UuidFormatter.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Console/Util/UuidFormatter.php b/src/Console/Util/UuidFormatter.php index 9a5795a..785e41d 100644 --- a/src/Console/Util/UuidFormatter.php +++ b/src/Console/Util/UuidFormatter.php @@ -58,8 +58,7 @@ class UuidFormatter )); $table->addRows($this->getContent($uuid)); - } - else { + } else { $table->addRows(array( array('decode:', 'variant:', 'Not an RFC 4122 UUID'), )); From 7e036c44021c8c0b15604027d5bafe9837956911 Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Sun, 9 Nov 2014 11:37:50 +0100 Subject: [PATCH 30/30] Add PHPCS to build config --- .travis.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4ec0096..7dba238 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,8 @@ before_script: - composer self-update - composer install --dev --prefer-source -script: ./vendor/bin/phpunit --coverage-text --coverage-clover ./build/logs/clover.xml +script: + - ./vendor/bin/phpunit --coverage-text --coverage-clover ./build/logs/clover.xml + - ./vendor/bin/phpcs --standard=phpcs.xml ./ after_script: php vendor/bin/coveralls