From aaccc850a1cdcfc15e58bd4858bfec4d77e91553 Mon Sep 17 00:00:00 2001 From: Ben Ramsey Date: Sun, 23 Feb 2020 00:50:00 -0600 Subject: [PATCH] Use strict argument validation for collections This resolves #106 --- CHANGELOG.md | 9 +++++ composer.json | 1 + src/Builder/BuilderCollection.php | 40 +++++++++++++++++++ src/Builder/FallbackBuilder.php | 9 +++-- src/FeatureSet.php | 10 +++-- src/Provider/Node/FallbackNodeProvider.php | 7 ++-- src/Provider/Node/NodeProviderCollection.php | 30 ++++++++++++++ src/Provider/Node/RandomNodeProvider.php | 5 ++- src/Provider/Time/FixedTimeProvider.php | 38 ++---------------- src/Provider/TimeProviderInterface.php | 9 ----- tests/Builder/FallbackBuilderTest.php | 3 +- .../Node/FallbackNodeProviderTest.php | 9 +++-- tests/Provider/Time/FixedTimeProviderTest.php | 28 ------------- 13 files changed, 111 insertions(+), 87 deletions(-) create mode 100644 src/Builder/BuilderCollection.php create mode 100644 src/Provider/Node/NodeProviderCollection.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 1da1c65..22f1abb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,8 +10,17 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Added +* Introduce `Builder\BuilderCollection` and `Provider\Node\NodeProviderCollection`. + ### Changed +* `Builder\FallbackBuilder` now accepts only a `Builder\BuilderCollection` as + its constructor parameter. +* `Provider\Node\FallbackNodeProvider` now accepts only a `Provider\Node\NodeProviderCollection` + as its constructor parameter. +* `Provider\Time\FixedTimeProvider` no longer accepts an array but accepts only + `Type\Time` instances. + ### Deprecated ### Removed diff --git a/composer.json b/composer.json index 81c1e66..3d7f234 100644 --- a/composer.json +++ b/composer.json @@ -13,6 +13,7 @@ "php": "^7.2 | ^8", "ext-json": "*", "brick/math": "^0.8", + "ramsey/collection": "^1.0", "symfony/polyfill-ctype": "^1.8" }, "require-dev": { diff --git a/src/Builder/BuilderCollection.php b/src/Builder/BuilderCollection.php new file mode 100644 index 0000000..67b5a50 --- /dev/null +++ b/src/Builder/BuilderCollection.php @@ -0,0 +1,40 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Builder; + +use Ramsey\Collection\AbstractCollection; +use Ramsey\Collection\CollectionInterface; +use Traversable; + +/** + * A collection of UuidBuilderInterface objects + */ +class BuilderCollection extends AbstractCollection implements CollectionInterface +{ + public function getType(): string + { + return UuidBuilderInterface::class; + } + + /** + * @psalm-mutation-free + * @psalm-suppress ImpureMethodCall + * @psalm-suppress InvalidTemplateParam + */ + public function getIterator(): Traversable + { + return parent::getIterator(); + } +} diff --git a/src/Builder/FallbackBuilder.php b/src/Builder/FallbackBuilder.php index 7dca340..c2f7c10 100644 --- a/src/Builder/FallbackBuilder.php +++ b/src/Builder/FallbackBuilder.php @@ -28,14 +28,14 @@ use Ramsey\Uuid\UuidInterface; class FallbackBuilder implements UuidBuilderInterface { /** - * @var UuidBuilderInterface[] + * @var BuilderCollection */ - private $builders = []; + private $builders; /** - * @param UuidBuilderInterface[] $builders An array of UUID builders + * @param BuilderCollection $builders An array of UUID builders */ - public function __construct(array $builders) + public function __construct(BuilderCollection $builders) { $this->builders = $builders; } @@ -53,6 +53,7 @@ class FallbackBuilder implements UuidBuilderInterface { $lastBuilderException = null; + /** @var UuidBuilderInterface $builder */ foreach ($this->builders as $builder) { try { return $builder->build($codec, $bytes); diff --git a/src/FeatureSet.php b/src/FeatureSet.php index c3c887c..c33474e 100644 --- a/src/FeatureSet.php +++ b/src/FeatureSet.php @@ -14,6 +14,7 @@ declare(strict_types=1); namespace Ramsey\Uuid; +use Ramsey\Uuid\Builder\BuilderCollection; use Ramsey\Uuid\Builder\FallbackBuilder; use Ramsey\Uuid\Builder\UuidBuilderInterface; use Ramsey\Uuid\Codec\CodecInterface; @@ -42,6 +43,7 @@ use Ramsey\Uuid\Nonstandard\UuidBuilder as NonstandardUuidBuilder; use Ramsey\Uuid\Provider\Dce\SystemDceSecurityProvider; use Ramsey\Uuid\Provider\DceSecurityProviderInterface; use Ramsey\Uuid\Provider\Node\FallbackNodeProvider; +use Ramsey\Uuid\Provider\Node\NodeProviderCollection; use Ramsey\Uuid\Provider\Node\RandomNodeProvider; use Ramsey\Uuid\Provider\Node\SystemNodeProvider; use Ramsey\Uuid\Provider\NodeProviderInterface; @@ -328,10 +330,10 @@ class FeatureSet return new RandomNodeProvider(); } - return new FallbackNodeProvider([ + return new FallbackNodeProvider(new NodeProviderCollection([ new SystemNodeProvider(), new RandomNodeProvider(), - ]); + ])); } /** @@ -410,10 +412,10 @@ class FeatureSet return new GuidBuilder($this->numberConverter, $this->timeConverter); } - return new FallbackBuilder([ + return new FallbackBuilder(new BuilderCollection([ new Rfc4122UuidBuilder($this->numberConverter, $this->timeConverter), new NonstandardUuidBuilder($this->numberConverter, $this->timeConverter), - ]); + ])); } /** diff --git a/src/Provider/Node/FallbackNodeProvider.php b/src/Provider/Node/FallbackNodeProvider.php index e4e4504..f0437aa 100644 --- a/src/Provider/Node/FallbackNodeProvider.php +++ b/src/Provider/Node/FallbackNodeProvider.php @@ -23,14 +23,14 @@ use Ramsey\Uuid\Provider\NodeProviderInterface; class FallbackNodeProvider implements NodeProviderInterface { /** - * @var NodeProviderInterface[] + * @var NodeProviderCollection */ private $nodeProviders; /** - * @param NodeProviderInterface[] $providers Array of node providers + * @param NodeProviderCollection $providers Array of node providers */ - public function __construct(array $providers) + public function __construct(NodeProviderCollection $providers) { $this->nodeProviders = $providers; } @@ -40,6 +40,7 @@ class FallbackNodeProvider implements NodeProviderInterface */ public function getNode() { + /** @var NodeProviderInterface $provider */ foreach ($this->nodeProviders as $provider) { if ($node = $provider->getNode()) { return $node; diff --git a/src/Provider/Node/NodeProviderCollection.php b/src/Provider/Node/NodeProviderCollection.php new file mode 100644 index 0000000..0037153 --- /dev/null +++ b/src/Provider/Node/NodeProviderCollection.php @@ -0,0 +1,30 @@ + + * @license http://opensource.org/licenses/MIT MIT + */ + +declare(strict_types=1); + +namespace Ramsey\Uuid\Provider\Node; + +use Ramsey\Collection\AbstractCollection; +use Ramsey\Collection\CollectionInterface; +use Ramsey\Uuid\Provider\NodeProviderInterface; + +/** + * A collection of NodeProviderInterface objects + */ +class NodeProviderCollection extends AbstractCollection implements CollectionInterface +{ + public function getType(): string + { + return NodeProviderInterface::class; + } +} diff --git a/src/Provider/Node/RandomNodeProvider.php b/src/Provider/Node/RandomNodeProvider.php index aa3a3d1..ce0d6eb 100644 --- a/src/Provider/Node/RandomNodeProvider.php +++ b/src/Provider/Node/RandomNodeProvider.php @@ -33,7 +33,10 @@ use const STR_PAD_LEFT; */ class RandomNodeProvider implements NodeProviderInterface { - public function getNode(): string + /** + * @inheritDoc + */ + public function getNode() { try { $nodeBytes = random_bytes(6); diff --git a/src/Provider/Time/FixedTimeProvider.php b/src/Provider/Time/FixedTimeProvider.php index dcbee63..1e42ae2 100644 --- a/src/Provider/Time/FixedTimeProvider.php +++ b/src/Provider/Time/FixedTimeProvider.php @@ -14,12 +14,10 @@ declare(strict_types=1); namespace Ramsey\Uuid\Provider\Time; -use Ramsey\Uuid\Exception\InvalidArgumentException; use Ramsey\Uuid\Provider\TimeProviderInterface; +use Ramsey\Uuid\Type\Integer as IntegerObject; use Ramsey\Uuid\Type\Time; -use function array_key_exists; - /** * FixedTimeProvider uses an known time to provide the time * @@ -33,26 +31,15 @@ class FixedTimeProvider implements TimeProviderInterface */ private $fixedTime; - /** - * @param int[]|string[]|Time $time An array containing 'sec' and - * 'usec' keys or a Time object - * - * @throws InvalidArgumentException if the `$time` does not contain - * `sec` or `usec` components - */ - public function __construct($time) + public function __construct(Time $time) { - if (!$time instanceof Time) { - $time = $this->convertToTime($time); - } - $this->fixedTime = $time; } /** * Sets the `usec` component of the time * - * @param int|string|Time $value The `usec` value to set + * @param int|string|IntegerObject $value The `usec` value to set */ public function setUsec($value): void { @@ -62,7 +49,7 @@ class FixedTimeProvider implements TimeProviderInterface /** * Sets the `sec` component of the time * - * @param int|string|Time $value The `sec` value to set + * @param int|string|IntegerObject $value The `sec` value to set */ public function setSec($value): void { @@ -86,21 +73,4 @@ class FixedTimeProvider implements TimeProviderInterface { return $this->fixedTime; } - - /** - * @param int[]|string[] $time - * - * @return Time A time created from the provided array - * - * @throws InvalidArgumentException if the `$time` does not contain - * `sec` or `usec` components - */ - private function convertToTime(array $time): Time - { - if (!array_key_exists('sec', $time) || !array_key_exists('usec', $time)) { - throw new InvalidArgumentException('Array must contain sec and usec keys.'); - } - - return new Time($time['sec'], $time['usec']); - } } diff --git a/src/Provider/TimeProviderInterface.php b/src/Provider/TimeProviderInterface.php index cf4f42f..43588e0 100644 --- a/src/Provider/TimeProviderInterface.php +++ b/src/Provider/TimeProviderInterface.php @@ -21,15 +21,6 @@ use Ramsey\Uuid\Type\Time; */ interface TimeProviderInterface { - /** - * Returns a timestamp array - * - * @deprecated Transition to {@see TimeProviderInterface::getTime()}. - * - * @return int[]|string[] Array containing `sec` and `usec` components of a timestamp - */ - public function currentTime(): array; - /** * Returns a time object */ diff --git a/tests/Builder/FallbackBuilderTest.php b/tests/Builder/FallbackBuilderTest.php index fec5f29..d5d0d82 100644 --- a/tests/Builder/FallbackBuilderTest.php +++ b/tests/Builder/FallbackBuilderTest.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace Ramsey\Uuid\Test\Builder; use Mockery; +use Ramsey\Uuid\Builder\BuilderCollection; use Ramsey\Uuid\Builder\FallbackBuilder; use Ramsey\Uuid\Builder\UuidBuilderInterface; use Ramsey\Uuid\Codec\CodecInterface; @@ -40,7 +41,7 @@ class FallbackBuilderTest extends TestCase ->with($codec, $bytes) ->andThrow(UnableToBuildUuidException::class); - $fallbackBuilder = new FallbackBuilder([$builder1, $builder2, $builder3]); + $fallbackBuilder = new FallbackBuilder(new BuilderCollection([$builder1, $builder2, $builder3])); $this->expectException(BuilderNotFoundException::class); $this->expectExceptionMessage( diff --git a/tests/Provider/Node/FallbackNodeProviderTest.php b/tests/Provider/Node/FallbackNodeProviderTest.php index a1ca3b3..63035e5 100644 --- a/tests/Provider/Node/FallbackNodeProviderTest.php +++ b/tests/Provider/Node/FallbackNodeProviderTest.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace Ramsey\Uuid\Test\Provider\Node; use Ramsey\Uuid\Provider\Node\FallbackNodeProvider; +use Ramsey\Uuid\Provider\Node\NodeProviderCollection; use Ramsey\Uuid\Provider\NodeProviderInterface; use Ramsey\Uuid\Test\TestCase; @@ -21,7 +22,7 @@ class FallbackNodeProviderTest extends TestCase ->method('getNode') ->willReturn(null); - $provider = new FallbackNodeProvider([$providerWithoutNode, $providerWithNode]); + $provider = new FallbackNodeProvider(new NodeProviderCollection([$providerWithoutNode, $providerWithNode])); $provider->getNode(); } @@ -39,7 +40,9 @@ class FallbackNodeProviderTest extends TestCase $anotherProviderWithoutNode->expects($this->never()) ->method('getNode'); - $provider = new FallbackNodeProvider([$providerWithoutNode, $providerWithNode, $anotherProviderWithoutNode]); + $provider = new FallbackNodeProvider(new NodeProviderCollection( + [$providerWithoutNode, $providerWithNode, $anotherProviderWithoutNode] + )); $node = $provider->getNode(); $this->assertEquals('57764a07f756', $node); @@ -51,7 +54,7 @@ class FallbackNodeProviderTest extends TestCase $providerWithoutNode->method('getNode') ->willReturn(null); - $provider = new FallbackNodeProvider([$providerWithoutNode]); + $provider = new FallbackNodeProvider(new NodeProviderCollection([$providerWithoutNode])); $node = $provider->getNode(); $this->assertNull($node); diff --git a/tests/Provider/Time/FixedTimeProviderTest.php b/tests/Provider/Time/FixedTimeProviderTest.php index c494c78..1720848 100644 --- a/tests/Provider/Time/FixedTimeProviderTest.php +++ b/tests/Provider/Time/FixedTimeProviderTest.php @@ -10,34 +10,6 @@ use Ramsey\Uuid\Type\Time; class FixedTimeProviderTest extends TestCase { - public function testConstructorRequiresSecAndUsec(): void - { - $this->expectException(\InvalidArgumentException::class); - $this->expectExceptionMessage('Array must contain sec and usec keys.'); - - new FixedTimeProvider([]); - } - - public function testCurrentTimeReturnsTimestamp(): void - { - $timestamp = ['sec' => 1458844556, 'usec' => 200997]; - $provider = new FixedTimeProvider($timestamp); - - $this->assertEquals($timestamp, $provider->currentTime()); - } - - public function testCurrentTimeReturnsTimestampAfterChange(): void - { - $timestamp = ['sec' => 1458844556, 'usec' => 200997]; - $provider = new FixedTimeProvider($timestamp); - - $newTimestamp = ['sec' => 1050804050, 'usec' => 30192]; - $provider->setSec($newTimestamp['sec']); - $provider->setUsec($newTimestamp['usec']); - - $this->assertEquals($newTimestamp, $provider->currentTime()); - } - public function testGetTimeReturnsTime(): void { $time = new Time(1458844556, 200997);