From c07988fe317b41b2328dcdd78cd4be304e948e67 Mon Sep 17 00:00:00 2001 From: Thibaud Fabre Date: Sat, 8 Nov 2014 15:00:58 +0100 Subject: [PATCH] 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()); }