diff --git a/src/FeatureSet.php b/src/FeatureSet.php index f74a71d..9b6760f 100644 --- a/src/FeatureSet.php +++ b/src/FeatureSet.php @@ -14,30 +14,31 @@ namespace Ramsey\Uuid; -use Ramsey\Uuid\Converter\TimeConverterInterface; -use Ramsey\Uuid\Generator\PeclUuidTimeGenerator; -use Ramsey\Uuid\Provider\Node\FallbackNodeProvider; -use Ramsey\Uuid\Provider\Node\RandomNodeProvider; -use Ramsey\Uuid\Provider\Node\SystemNodeProvider; +use Ramsey\Uuid\Builder\DefaultUuidBuilder; +use Ramsey\Uuid\Builder\DegradedUuidBuilder; +use Ramsey\Uuid\Builder\UuidBuilderInterface; +use Ramsey\Uuid\Codec\CodecInterface; +use Ramsey\Uuid\Codec\GuidStringCodec; +use Ramsey\Uuid\Codec\StringCodec; use Ramsey\Uuid\Converter\NumberConverterInterface; use Ramsey\Uuid\Converter\Number\BigNumberConverter; use Ramsey\Uuid\Converter\Number\DegradedNumberConverter; use Ramsey\Uuid\Converter\Time\BigNumberTimeConverter; use Ramsey\Uuid\Converter\Time\DegradedTimeConverter; use Ramsey\Uuid\Converter\Time\PhpTimeConverter; -use Ramsey\Uuid\Provider\Time\SystemTimeProvider; -use Ramsey\Uuid\Builder\UuidBuilderInterface; -use Ramsey\Uuid\Builder\DefaultUuidBuilder; -use Ramsey\Uuid\Codec\CodecInterface; -use Ramsey\Uuid\Codec\StringCodec; -use Ramsey\Uuid\Codec\GuidStringCodec; -use Ramsey\Uuid\Builder\DegradedUuidBuilder; +use Ramsey\Uuid\Generator\PeclUuidTimeGenerator; use Ramsey\Uuid\Generator\RandomGeneratorFactory; use Ramsey\Uuid\Generator\RandomGeneratorInterface; use Ramsey\Uuid\Generator\TimeGeneratorFactory; use Ramsey\Uuid\Generator\TimeGeneratorInterface; -use Ramsey\Uuid\Provider\TimeProviderInterface; use Ramsey\Uuid\Provider\NodeProviderInterface; +use Ramsey\Uuid\Provider\Node\FallbackNodeProvider; +use Ramsey\Uuid\Provider\Node\RandomNodeProvider; +use Ramsey\Uuid\Provider\Node\SystemNodeProvider; +use Ramsey\Uuid\Provider\TimeProviderInterface; +use Ramsey\Uuid\Provider\Time\SystemTimeProvider; +use Ramsey\Uuid\Validator\Validator; +use Ramsey\Uuid\Validator\ValidatorInterface; /** * FeatureSet detects and exposes available features in the current environment @@ -95,6 +96,11 @@ class FeatureSet */ private $timeGenerator; + /** + * @var ValidatorInterface + */ + private $validator; + /** * Constructs a `FeatureSet` for use by a `UuidFactory` to determine or set * features available to the environment @@ -127,6 +133,7 @@ class FeatureSet $this->nodeProvider = $this->buildNodeProvider(); $this->randomGenerator = $this->buildRandomGenerator(); $this->setTimeProvider(new SystemTimeProvider()); + $this->validator = new Validator; } /** @@ -189,6 +196,16 @@ class FeatureSet return $this->timeGenerator; } + /** + * Returns the validator to use for this environment + * + * @return ValidatorInterface + */ + public function getValidator() + { + return $this->validator; + } + /** * Sets the time provider for use in this environment * @@ -200,6 +217,17 @@ class FeatureSet $this->timeGenerator = $this->buildTimeGenerator($timeProvider); } + /** + * Set the validator to use in this environment + * + * @param ValidatorInterface $validator + * @return void + */ + public function setValidator(ValidatorInterface $validator) + { + $this->validator = $validator; + } + /** * Determines which UUID coder-decoder to use and returns the configured * codec for this environment diff --git a/src/Uuid.php b/src/Uuid.php index 58699b8..6e3f1bd 100644 --- a/src/Uuid.php +++ b/src/Uuid.php @@ -17,8 +17,8 @@ namespace Ramsey\Uuid; use DateTime; use Exception; use InvalidArgumentException; -use Ramsey\Uuid\Converter\NumberConverterInterface; use Ramsey\Uuid\Codec\CodecInterface; +use Ramsey\Uuid\Converter\NumberConverterInterface; use Ramsey\Uuid\Exception\InvalidUuidStringException; use Ramsey\Uuid\Exception\UnsatisfiedDependencyException; use Ramsey\Uuid\Exception\UnsupportedOperationException; @@ -95,11 +95,6 @@ class Uuid implements UuidInterface */ const RESERVED_FUTURE = 7; - /** - * Regular expression pattern for matching a valid UUID of any variant. - */ - const VALID_PATTERN = '^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$'; - /** * Version 1 (time-based) UUID object constant identifier */ @@ -679,17 +674,7 @@ class Uuid implements UuidInterface */ public static function isValid($uuid) { - $uuid = str_replace(['urn:', 'uuid:', 'URN:', 'UUID:', '{', '}'], '', $uuid); - - if ($uuid == self::NIL) { - return true; - } - - if (!preg_match('/' . self::VALID_PATTERN . '/D', $uuid)) { - return false; - } - - return true; + return self::getFactory()->getValidator()->validate($uuid); } /** diff --git a/src/UuidFactory.php b/src/UuidFactory.php index 0436f6f..f865531 100644 --- a/src/UuidFactory.php +++ b/src/UuidFactory.php @@ -14,13 +14,14 @@ namespace Ramsey\Uuid; +use Ramsey\Uuid\Builder\UuidBuilderInterface; +use Ramsey\Uuid\Codec\CodecInterface; use Ramsey\Uuid\Converter\NumberConverterInterface; use Ramsey\Uuid\Exception\InvalidUuidStringException; -use Ramsey\Uuid\Provider\NodeProviderInterface; use Ramsey\Uuid\Generator\RandomGeneratorInterface; use Ramsey\Uuid\Generator\TimeGeneratorInterface; -use Ramsey\Uuid\Codec\CodecInterface; -use Ramsey\Uuid\Builder\UuidBuilderInterface; +use Ramsey\Uuid\Provider\NodeProviderInterface; +use Ramsey\Uuid\Validator\ValidatorInterface; class UuidFactory implements UuidFactoryInterface { @@ -54,6 +55,11 @@ class UuidFactory implements UuidFactoryInterface */ private $uuidBuilder = null; + /** + * @var ValidatorInterface + */ + private $validator = null; + /** * Constructs a `UuidFactory` for creating `Ramsey\Uuid\UuidInterface` instances * @@ -69,6 +75,7 @@ class UuidFactory implements UuidFactoryInterface $this->randomGenerator = $features->getRandomGenerator(); $this->timeGenerator = $features->getTimeGenerator(); $this->uuidBuilder = $features->getBuilder(); + $this->validator = $features->getValidator(); } /** @@ -187,8 +194,22 @@ class UuidFactory implements UuidFactoryInterface } /** - * @inheritdoc + * @return ValidatorInterface */ + public function getValidator() + { + return $this->validator; + } + + /** + * @param ValidatorInterface $validator + * @return void + */ + public function setValidator(ValidatorInterface $validator) + { + $this->validator = $validator; + } + public function fromBytes($bytes) { return $this->codec->decodeBytes($bytes); diff --git a/src/UuidFactoryInterface.php b/src/UuidFactoryInterface.php index 1c1651d..471ad4b 100644 --- a/src/UuidFactoryInterface.php +++ b/src/UuidFactoryInterface.php @@ -18,6 +18,7 @@ use Exception; use InvalidArgumentException; use Ramsey\Uuid\Exception\InvalidUuidStringException; use Ramsey\Uuid\Exception\UnsatisfiedDependencyException; +use Ramsey\Uuid\Validator\ValidatorInterface; /** * UuidFactoryInterface defines common functionality all `UuidFactory` instances @@ -25,6 +26,11 @@ use Ramsey\Uuid\Exception\UnsatisfiedDependencyException; */ interface UuidFactoryInterface { + /** + * @return ValidatorInterface + */ + public function getValidator(); + /** * Generate a version 1 UUID from a host ID, sequence number, and the current time. * diff --git a/src/Validator/Validator.php b/src/Validator/Validator.php new file mode 100644 index 0000000..7ac5424 --- /dev/null +++ b/src/Validator/Validator.php @@ -0,0 +1,46 @@ + + * @copyright Copyright (c) Ben Ramsey + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Validator; + +use Ramsey\Uuid\Uuid; + +/** + * Default validation behavior + */ +class Validator implements ValidatorInterface +{ + /** + * Regular expression pattern for matching a valid UUID of any variant. + */ + const VALID_PATTERN = '^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$'; + + /** + * Validate that a string represents a UUID + * + * @param string $uuid + * @return bool Returns TRUE if the string was validated as a valid UUID or FALSE on failure + */ + public function validate($uuid) + { + $uuid = str_replace(['urn:', 'uuid:', 'URN:', 'UUID:', '{', '}'], '', $uuid); + + if ($uuid === Uuid::NIL || preg_match('/' . self::VALID_PATTERN . '/D', $uuid)) { + return true; + } + + return false; + } +} diff --git a/src/Validator/ValidatorInterface.php b/src/Validator/ValidatorInterface.php new file mode 100644 index 0000000..6a688e4 --- /dev/null +++ b/src/Validator/ValidatorInterface.php @@ -0,0 +1,30 @@ + + * @copyright Copyright (c) Ben Ramsey + * @license http://opensource.org/licenses/MIT MIT + * @link https://benramsey.com/projects/ramsey-uuid/ Documentation + * @link https://packagist.org/packages/ramsey/uuid Packagist + * @link https://github.com/ramsey/uuid GitHub + */ + +namespace Ramsey\Uuid\Validator; + +/** + * Outlines common behavior of UUID validators + */ +interface ValidatorInterface +{ + /** + * Validate that a string represents a UUID + * + * @param string $uuid + * @return bool Returns TRUE if the string was validated as a valid UUID or FALSE on failure + */ + public function validate($uuid); +} diff --git a/tests/UuidTest.php b/tests/UuidTest.php index 448e529..4371cda 100644 --- a/tests/UuidTest.php +++ b/tests/UuidTest.php @@ -3,6 +3,7 @@ namespace Ramsey\Uuid\Test; use InvalidArgumentException; +use PHPUnit\Framework\MockObject\MockObject; use Ramsey\Uuid\Codec\TimestampFirstCombCodec; use Ramsey\Uuid\Codec\TimestampLastCombCodec; use Ramsey\Uuid\Converter\Number\DegradedNumberConverter; @@ -11,12 +12,14 @@ use Ramsey\Uuid\Exception\InvalidUuidStringException; use Ramsey\Uuid\Exception\UnsatisfiedDependencyException; use Ramsey\Uuid\Exception\UnsupportedOperationException; use Ramsey\Uuid\FeatureSet; -use Ramsey\Uuid\Provider\Time\FixedTimeProvider; use Ramsey\Uuid\Generator\CombGenerator; use Ramsey\Uuid\Generator\RandomGeneratorFactory; use Ramsey\Uuid\Generator\RandomGeneratorInterface; +use Ramsey\Uuid\Provider\Time\FixedTimeProvider; use Ramsey\Uuid\Uuid; use Ramsey\Uuid\UuidFactory; +use Ramsey\Uuid\Validator\Validator; +use Ramsey\Uuid\Validator\ValidatorInterface; use stdClass; class UuidTest extends TestCase @@ -1376,91 +1379,24 @@ class UuidTest extends TestCase } /** + * This method should respond to the result of the factory */ - public function testIsValidGoodVersion1() + public function testIsValid() { - $valid = Uuid::isValid('ff6f8cb0-c57d-11e1-9b21-0800200c9a66'); - $this->assertTrue($valid); - } + $argument = uniqid('passed argument '); - /** - */ - public function testIsValidGoodVersion2() - { - $valid = Uuid::isValid('ff6f8cb0-c57d-21e1-9b21-0800200c9a66'); - $this->assertTrue($valid); - } + /** @var MockObject & ValidatorInterface $validator */ + $validator = $this->getMockBuilder(ValidatorInterface::class)->getMock(); + $validator->expects($this->once())->method('validate')->with($argument)->willReturn(true); - /** - */ - public function testIsValidGoodVersion3() - { - $valid = Uuid::isValid('ff6f8cb0-c57d-31e1-9b21-0800200c9a66'); - $this->assertTrue($valid); - } + /** @var UuidFactory $factory */ + $factory = Uuid::getFactory(); + $factory->setValidator($validator); - /** - */ - public function testIsValidGoodVersion4() - { - $valid = Uuid::isValid('ff6f8cb0-c57d-41e1-9b21-0800200c9a66'); - $this->assertTrue($valid); - } + $this->assertTrue(Uuid::isValid($argument)); - /** - */ - public function testIsValidGoodVersion5() - { - $valid = Uuid::isValid('ff6f8cb0-c57d-51e1-9b21-0800200c9a66'); - $this->assertTrue($valid); - } - - /** - */ - public function testIsValidGoodUpperCase() - { - $valid = Uuid::isValid('FF6F8CB0-C57D-11E1-9B21-0800200C9A66'); - $this->assertTrue($valid); - } - - /** - */ - public function testIsValidBadHex() - { - $valid = Uuid::isValid('zf6f8cb0-c57d-11e1-9b21-0800200c9a66'); - $this->assertFalse($valid); - } - - /** - */ - public function testIsValidTooShort1() - { - $valid = Uuid::isValid('3f6f8cb0-c57d-11e1-9b21-0800200c9a6'); - $this->assertFalse($valid); - } - - /** - */ - public function testIsValidTooShort2() - { - $valid = Uuid::isValid('af6f8cb-c57d-11e1-9b21-0800200c9a66'); - $this->assertFalse($valid); - } - - /** - */ - public function testIsValidNoDashes() - { - $valid = Uuid::isValid('af6f8cb0c57d11e19b210800200c9a66'); - $this->assertFalse($valid); - } - - /** - */ - public function testIsValidTooLong() - { - $valid = Uuid::isValid('ff6f8cb0-c57da-51e1-9b21-0800200c9a66'); - $this->assertFalse($valid); + // reset the static validator + $factory->setValidator(new Validator); } /** diff --git a/tests/Validator/ValidatorTest.php b/tests/Validator/ValidatorTest.php new file mode 100644 index 0000000..e7fcce1 --- /dev/null +++ b/tests/Validator/ValidatorTest.php @@ -0,0 +1,110 @@ +validator = $this->getMockBuilder('Ramsey\Uuid\Validator\Validator') + ->disableOriginalConstructor() + ->setMethods(null) + ->getMock(); + } + + /** + * @covers ::validate + */ + public function testValidateGoodVersion1() + { + $this->assertTrue($this->validator->validate('ff6f8cb0-c57d-11e1-9b21-0800200c9a66')); + } + + /** + * @covers ::validate + */ + public function testValidateGoodVersion2() + { + $this->assertTrue($this->validator->validate('ff6f8cb0-c57d-21e1-9b21-0800200c9a66')); + } + + /** + * @covers ::validate + */ + public function testValidateGoodVersion3() + { + $this->assertTrue($this->validator->validate('ff6f8cb0-c57d-31e1-9b21-0800200c9a66')); + } + + /** + * @covers ::validate + */ + public function testValidateGoodVersion4() + { + $this->assertTrue($this->validator->validate('ff6f8cb0-c57d-41e1-9b21-0800200c9a66')); + } + + /** + * @covers ::validate + */ + public function testValidateGoodVersion5() + { + $this->assertTrue($this->validator->validate('ff6f8cb0-c57d-51e1-9b21-0800200c9a66')); + } + + /** + * @covers ::validate + */ + public function testValidateGoodUpperCase() + { + $this->assertTrue($this->validator->validate('FF6F8CB0-C57D-11E1-9B21-0800200C9A66')); + } + + /** + * @covers ::validate + */ + public function testValidateBadHex() + { + $this->assertFalse($this->validator->validate('zf6f8cb0-c57d-11e1-9b21-0800200c9a66')); + } + + /** + * @covers ::validate + */ + public function testValidateTooShort1() + { + $this->assertFalse($this->validator->validate('3f6f8cb0-c57d-11e1-9b21-0800200c9a6')); + } + + /** + * @covers ::validate + */ + public function testValidateTooShort2() + { + $this->assertFalse($this->validator->validate('af6f8cb-c57d-11e1-9b21-0800200c9a66')); + } + + /** + * @covers ::validate + */ + public function testValidateNoDashes() + { + $this->assertFalse($this->validator->validate('af6f8cb0c57d11e19b210800200c9a66')); + } + + /** + * @covers ::validate + */ + public function testValidateTooLong() + { + $this->assertFalse($this->validator->validate('ff6f8cb0-c57da-51e1-9b21-0800200c9a66')); + } +}