Skip to content

Commit

Permalink
concise UUID aggregate identities
Browse files Browse the repository at this point in the history
  • Loading branch information
juliangut committed Jan 31, 2019
1 parent 3a35ab2 commit 03a056f
Show file tree
Hide file tree
Showing 11 changed files with 261 additions and 16 deletions.
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,15 @@ class CustomAggregateIdentity extends AbstractAggregateIdentity
}
```

Most used aggregate identities are UUID values, for that reason there is already a `Gears\Aggregate\UuidAggregateIdentity` identity ready to be used
Most widely used aggregate identities are UUID based, for that reason some UUID aggregate identity classes are provided for you to use or extend from

If you want to expand on aggregate identities head to [gears/identity](https://github.com/phpgears/identity)
* `Gears\Aggregate\UuidAggregateIdentity` Basic plain UUID aggregate identity
* `Gears\Aggregate\ShortUuidAggregateIdentity` Shortened UUID aggregate identity. Requires [pascaldevink/shortuuid](https://github.com/pascaldevink/shortuuid)
* `Gears\Aggregate\HashUuidAggregateIdentity` Hashed UUID aggregate identity. Requires [hashids/hashids](https://github.com/ivanakimov/hashids.php)

Both ShortUuidAggregateIdentity and HashUuidAggregateIdentity allows you to recover original UUID

If you want to expand on UUID aggregate identities head to [gears/identity](https://github.com/phpgears/identity)

### Aggregate root

Expand Down
14 changes: 9 additions & 5 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,28 @@
"require": {
"php": "^7.1",
"phpgears/event": "~0.1",
"phpgears/identity": "~0.1.1"
"phpgears/identity": "~0.1.3"
},
"require-dev": {
"brainmaestro/composer-git-hooks": "^2.1",
"friendsofphp/php-cs-fixer": "^2.0",
"hashids/hashids": "^3.0",
"infection/infection": "^0.9",
"pascaldevink/shortuuid": "^2.1",
"phpmd/phpmd": "^2.0",
"phpstan/phpstan": "^0.10",
"phpstan/phpstan-deprecation-rules": "^0.10",
"phpstan/phpstan-strict-rules": "^0.10",
"phpstan/phpstan": "^0.11",
"phpstan/phpstan-deprecation-rules": "^0.11",
"phpstan/phpstan-strict-rules": "^0.11",
"phpunit/phpunit": "^6.0|^7.0",
"povils/phpmnd": "^2.0",
"roave/security-advisories": "dev-master",
"sebastian/phpcpd": "^3.0|^4.0",
"squizlabs/php_codesniffer": "^2.0",
"thecodingmachine/phpstan-strict-rules": "^0.10.1"
"thecodingmachine/phpstan-strict-rules": "^0.11"
},
"suggest": {
"hashids/hashids": "for hashed UUID based identities",
"pascaldevink/shortuuid": "for short UUID based identities"
},
"autoload": {
"psr-4": {
Expand Down
2 changes: 0 additions & 2 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,4 @@ parameters:
paths:
- src
ignoreErrors:
- '/^Method Gears\\Aggregate\\UuidAggregateIdentity::fromString\(\) has no return typehint specified\.$/'
- '/^Method Gears\\Aggregate\\AbstractAggregateIdentity::isEqualTo\(\) has parameter \$identity with no typehint specified\.$/'
- '/^Call to an undefined method object::getValue\(\)\.$/'
18 changes: 18 additions & 0 deletions src/AbstractAggregateIdentity.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,24 @@ final public function __toString(): string
return $this->value;
}

/**
* {@inheritdoc}
*/
final public function serialize(): string
{
return \serialize($this->value);
}

/**
* {@inheritdoc}
*
* @param mixed $serialized
*/
final public function unserialize($serialized): void
{
$this->value = \unserialize($serialized, [static::class]);
}

/**
* {@inheritdoc}
*/
Expand Down
51 changes: 51 additions & 0 deletions src/HashUuidAggregateIdentity.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

/*
* aggregate (https://github.com/phpgears/aggregate).
* Aggregate base.
*
* @license MIT
* @link https://github.com/phpgears/aggregate
* @author Julián Gutiérrez <juliangut@gmail.com>
*/

declare(strict_types=1);

namespace Gears\Aggregate;

use Gears\Identity\Exception\InvalidIdentityException;
use Hashids\Hashids;
use Ramsey\Uuid\Exception\InvalidUuidStringException;
use Ramsey\Uuid\Uuid;

/**
* Base immutable hashed UUID aggregate identity.
*/
class HashUuidAggregateIdentity extends AbstractAggregateIdentity
{
/**
* {@inheritdoc}
*
* @throws InvalidIdentityException
*/
public static function fromString(string $value)
{
try {
$uuid = Uuid::fromString((new Hashids())->decodeHex($value));
} catch (InvalidUuidStringException $exception) {
throw new InvalidIdentityException(
\sprintf('Provided identity value "%s" is not a valid hashed UUID', $value),
0,
$exception
);
}

if ($uuid->getVariant() !== Uuid::RFC_4122 || !\in_array($uuid->getVersion(), \range(1, 5), true)) {
throw new InvalidIdentityException(
\sprintf('Provided identity value "%s" is not a valid hashed UUID', $value)
);
}

return new static($value);
}
}
41 changes: 41 additions & 0 deletions src/ShortUuidAggregateIdentity.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

/*
* aggregate (https://github.com/phpgears/aggregate).
* Aggregate base.
*
* @license MIT
* @link https://github.com/phpgears/aggregate
* @author Julián Gutiérrez <juliangut@gmail.com>
*/

declare(strict_types=1);

namespace Gears\Aggregate;

use Gears\Identity\Exception\InvalidIdentityException;
use PascalDeVink\ShortUuid\ShortUuid;
use Ramsey\Uuid\Uuid;

/**
* Base immutable short UUID aggregate identity.
*/
class ShortUuidAggregateIdentity extends AbstractAggregateIdentity
{
/**
* {@inheritdoc}
*
* @throws InvalidIdentityException
*/
public static function fromString(string $value)
{
$uuid = (new ShortUuid())->decode($value);
if ($uuid->getVariant() !== Uuid::RFC_4122 || !\in_array($uuid->getVersion(), \range(1, 5), true)) {
throw new InvalidIdentityException(
\sprintf('Provided identity value "%s" is not a valid short UUID', $value)
);
}

return new static($value);
}
}
15 changes: 13 additions & 2 deletions src/UuidAggregateIdentity.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
namespace Gears\Aggregate;

use Gears\Identity\Exception\InvalidIdentityException;
use Ramsey\Uuid\Exception\InvalidUuidStringException;
use Ramsey\Uuid\Uuid;

/**
Expand All @@ -28,9 +29,19 @@ class UuidAggregateIdentity extends AbstractAggregateIdentity
*/
public static function fromString(string $value)
{
if (!Uuid::isValid($value)) {
try {
$uuid = Uuid::fromString($value);
} catch (InvalidUuidStringException $exception) {
throw new InvalidIdentityException(
\sprintf('Provided identifier "%s" is not a valid UUID', $value)
\sprintf('Provided identity value "%s" is not a valid UUID', $value),
0,
$exception
);
}

if ($uuid->getVariant() !== Uuid::RFC_4122 || !\in_array($uuid->getVersion(), \range(1, 5), true)) {
throw new InvalidIdentityException(
\sprintf('Provided identity value "%s" is not a valid UUID', $value)
);
}

Expand Down
9 changes: 9 additions & 0 deletions tests/Aggregate/AbstractAggregateIdentityTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ public function testCreation(): void

$this->assertSame('thisIsMyId', $stub->getValue());
$this->assertSame('thisIsMyId', (string) $stub);
}

public function testSerialization(): void
{
$stub = AbstractAggregateIdentityStub::fromString('thisIsMyId');

$serialized = 'C:56:"Gears\Aggregate\Tests\Stub\AbstractAggregateIdentityStub":18:{s:10:"thisIsMyId";}';
$this->assertSame($serialized, \serialize($stub));
$this->assertSame('thisIsMyId', (\unserialize($serialized))->getValue());
$this->assertSame('"thisIsMyId"', \json_encode($stub));
}

Expand Down
50 changes: 50 additions & 0 deletions tests/Aggregate/HashUuidAggregateIdentityTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

/*
* aggregate (https://github.com/phpgears/aggregate).
* Aggregate base.
*
* @license MIT
* @link https://github.com/phpgears/aggregate
* @author Julián Gutiérrez <juliangut@gmail.com>
*/

declare(strict_types=1);

namespace Gears\Aggregate\Tests;

use Gears\Aggregate\HashUuidAggregateIdentity;
use PHPUnit\Framework\TestCase;

/**
* Hashed UUID aggregate identity test.
*/
class HashUuidAggregateIdentityTest extends TestCase
{
public function testCreation(): void
{
$hashedUuid = 'gqYxv3lMPXSEkGoonzDZtMNwE4Q';
$stub = HashUuidAggregateIdentity::fromString($hashedUuid);

$this->assertSame($hashedUuid, $stub->getValue());
$this->assertSame($hashedUuid, (string) $stub);
}

/**
* @expectedException \Gears\Identity\Exception\InvalidIdentityException
* @expectedExceptionMessage Provided identity value "invalidHashedUUID" is not a valid hashed UUID
*/
public function testInvalidShortUuid(): void
{
HashUuidAggregateIdentity::fromString('invalidHashedUUID');
}

/**
* @expectedException \Gears\Identity\Exception\InvalidIdentityException
* @expectedExceptionMessage Provided identity value "gGJqXEqR7AFZjBkzP9MLtWYP9AA" is not a valid hashed UUID
*/
public function testNonRFC4122Uuid(): void
{
HashUuidAggregateIdentity::fromString('gGJqXEqR7AFZjBkzP9MLtWYP9AA');
}
}
50 changes: 50 additions & 0 deletions tests/Aggregate/ShortUuidAggregateIdentityTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

/*
* aggregate (https://github.com/phpgears/aggregate).
* Aggregate base.
*
* @license MIT
* @link https://github.com/phpgears/aggregate
* @author Julián Gutiérrez <juliangut@gmail.com>
*/

declare(strict_types=1);

namespace Gears\Aggregate\Tests;

use Gears\Aggregate\ShortUuidAggregateIdentity;
use PHPUnit\Framework\TestCase;

/**
* Short UUID aggregate identity test.
*/
class ShortUuidAggregateIdentityTest extends TestCase
{
public function testCreation(): void
{
$shortUuid = 'QuwMZbb9f3ccpacCPmVRaF';
$stub = ShortUuidAggregateIdentity::fromString($shortUuid);

$this->assertSame($shortUuid, $stub->getValue());
$this->assertSame($shortUuid, (string) $stub);
}

/**
* @expectedException \Gears\Identity\Exception\InvalidIdentityException
* @expectedExceptionMessage Provided identity value "invalidShortUUID" is not a valid short UUID
*/
public function testInvalidShortUuid(): void
{
ShortUuidAggregateIdentity::fromString('invalidShortUUID');
}

/**
* @expectedException \Gears\Identity\Exception\InvalidIdentityException
* @expectedExceptionMessage Provided identity value "zaDP55gm3yL9cV2D" is not a valid short UUID
*/
public function testNonRFC4122Uuid(): void
{
ShortUuidAggregateIdentity::fromString('zaDP55gm3yL9cV2D');
}
}
17 changes: 12 additions & 5 deletions tests/Aggregate/UuidAggregateIdentityTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,27 @@ class UuidAggregateIdentityTest extends TestCase
public function testCreation(): void
{
$uuid = '4c4316cb-b48b-44fb-a034-90d789966bac';

$stub = UuidAggregateIdentity::fromString($uuid);

$this->assertSame($uuid, $stub->getValue());
$this->assertSame('4c4316cb-b48b-44fb-a034-90d789966bac', (string) $stub);
$this->assertSame('"4c4316cb-b48b-44fb-a034-90d789966bac"', \json_encode($stub));
$this->assertSame($uuid, (string) $stub);
}

/**
* @expectedException \Gears\Identity\Exception\InvalidIdentityException
* @expectedExceptionMessage Provided identifier "invalidId" is not a valid UUID
* @expectedExceptionMessage Provided identity value "invalidUUID" is not a valid UUID
*/
public function testInvalidUuid(): void
{
UuidAggregateIdentity::fromString('invalidId');
UuidAggregateIdentity::fromString('invalidUUID');
}

/**
* @expectedException \Gears\Identity\Exception\InvalidIdentityException
* @expectedExceptionMessage Provided identity value "00000000-07bf-961b-abd8-c4716f92fcc0" is not a valid UUID
*/
public function testNonRFC4122Uuid(): void
{
UuidAggregateIdentity::fromString('00000000-07bf-961b-abd8-c4716f92fcc0');
}
}

0 comments on commit 03a056f

Please sign in to comment.