8000 add GenericDomainId + DomainUuid by ro0NL · Pull Request #385 · msgphp/msgphp · GitHub
[go: up one dir, main page]

Skip to content

add GenericDomainId + DomainUuid #385

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 16 additions & 25 deletions docs/ddd/identifiers.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,64 +7,55 @@ identifier value, usually used to identity an entity with.

### `static fromValue(mixed $value): DomainId`

Returns a factorized identifier from any primitive value. Using `null` might imply an empty identifier.

---
Returns a factorized identifier from any primitive value. Using `null` might either imply an nil/empty identifier or a
self-generated identifier value.

### `isNil(): bool`

Tells if an identifier value is nil, thus is considered empty/unknown.

---

### `equals($other): bool`

Tells if an identifier strictly equals another identifier.

---

### `toString(): string`

Returns the identifier its primitive string value.

## Implementations

### `MsgPhp\Domain\DomainIdTrait`
### `MsgPhp\Domain\GenericDomainId`

A first-class citizen domain identifier trait compatible with any string or numeric value.
A first-class citizen domain identifier compatible with any string or numeric value.

#### Basic Example

```php
<?php

use MsgPhp\Domain\DomainId;
use MsgPhp\Domain\DomainIdTrait;

// --- SETUP ---
use MsgPhp\Domain\GenericDomainId;

class MyDomainId implements DomainId
{
use DomainIdTrait;
}
// SETUP

$id = new MyDomainId('1');
$emptyId = new MyDomainId();
$id = new GenericDomainId('1');
$id = GenericDomainId::fromValue(1);
$nilId = new GenericDomainId();

// --- USAGE ---
// USAGE

$id->isNil(); // false
$emptyId->isNil(); // true
$nilId->isNil(); // true

$id->toString(); // "1"
$emptyId->toString(); // ""
$nilId->toString(); // ""

$id->equals(new MyDomainId('1')); // true
$id->equals(new GenericDomainId('1')); // true
$id->equals('1'); // false
$id->equals(new MyDomainId('2')); // false
$id->equals(new GenericDomainId('2')); // false
$id->equals(new GenericDomainId()); // false
```

### `MsgPhp\Domain\Infrastructure\Uuid\DomainIdTrait`
### `MsgPhp\Domain\Infrastructure\Uuid\DomainUuid`

A UUID tailored domain identifier trait.

Expand Down
17 changes: 6 additions & 11 deletions docs/infrastructure/uuid.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,22 @@ An overview of available infrastructural code when working with [UUIDs][uuid].

## Domain Identifier

A UUID tailored [domain identifier](../ddd/identifiers.md) trait is provided by `MsgPhp\Domain\Infrastructure\Uuid\DomainIdTrait`.
A UUID tailored [domain identifier](../ddd/identifiers.md) is provided by `MsgPhp\Domain\Infrastructure\Uuid\DomainUuid`.

### Basic Example

```php
<?php

use MsgPhp\Domain\DomainId;
use MsgPhp\Domain\Infrastructure\Uuid\DomainIdTrait;
use MsgPhp\Domain\Infrastructure\Uuid\DomainUuid;
use Ramsey\Uuid\Uuid;

// SETUP

class MyDomainUuid implements DomainId
{
use DomainIdTrait;
}

$id = new MyDomainUuid(); // a new UUID version 4 value
$id = new MyDomainUuid(Uuid::uuid1());
$id = new MyDomainUuid(Uuid::fromString('00000000-0000-0000-0000-000000000000'));
$id = new DomainUuid(); // a new UUID version 4 value
$id = new DomainUuid(Uuid::uuid1());
$id = new DomainUuid(Uuid::fromString('00000000-0000-0000-0000-000000000000'));
$id = DomainUuid::fromValue('00000000-0000-0000-0000-000000000000');
```

[uuid]: https://en.wikipedia.org/wiki/Universally_unique_identifier
Expand Down
51 changes: 51 additions & 0 deletions src/Domain/GenericDomainId.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

declare(strict_types=1);

namespace MsgPhp\Domain;

/**
* @author Roland Franssen <franssen.roland@gmail.com>
*/
final class GenericDomainId implements DomainId
{
/** @var string */
private $id;

public function __construct(?string $id = null)
{
$this->id = $id ?? '';
}

public function __toString(): string
{
return $this->id;
}

public static function fromValue($value): DomainId
{
if (null === $value || \is_string($value)) {
return new self($value);
}
if (is_numeric($value)) {
return new self((string) $value);
}

throw new \LogicException('Raw ID value must be of type string or number, got "'.\gettype($value).'".');
}

public function isNil(): bool
{
return '' === $this->id;
}

public function equals($other): bool
{
return $other instanceof DomainId && $this->id === $other->toString();
}

public function toString(): string
{
return $this->id;
}
}
55 changes: 55 additions & 0 deletions src/Domain/Infrastructure/Uuid/DomainUuid.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

declare(strict_types=1);

namespace MsgPhp\Domain\Infrastructure\Uuid;

use MsgPhp\Domain\DomainId;
use Ramsey\Uuid\Uuid;
use Ramsey\Uuid\UuidInterface;

/**
* @author Roland Franssen <franssen.roland@gmail.com>
*/
final class DomainUuid implements DomainId
{
/** @var UuidInterface */
private $uuid;

public function __construct(?UuidInterface $uuid = null)
{
$this->uuid = $uuid ?? Uuid::uuid4();
}

public function __toString(): string
{
return $this->uuid->toString();
}

public static function fromValue($value): DomainId
{
if (null === $value || $value instanceof UuidInterface) {
return new self($value);
}
if (\is_string($value)) {
return new self(Uuid::fromString($value));
}

throw new \LogicException('Raw UUID value must be of type string, got "'.\gettype($value).'".');
}

public function isNil(): bool
{
return $this->uuid->equals(Uuid::fromString(Uuid::NIL));
}

public function equals($other): bool
{
return $other instanceof self && $this->uuid->equals($other->uuid);
}

public function toString(): string
{
return $this->uuid->toString();
}
}
9 changes: 9 additions & 0 deletions src/Domain/Tests/Fixtures/CountableIterator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

declare(strict_types=1);

namespace MsgPhp\Domain\Tests\Fixtures;

interface CountableIterator extends \Iterator, \Countable
{
}
5 changes: 2 additions & 3 deletions src/Domain/Tests/GenericDomainCollectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
use MsgPhp\Domain\Exception\EmptyCollection;
use MsgPhp\Domain\Exception\UnknownCollectionElement;
use MsgPhp\Domain\GenericDomainCollection;
use PHPUnit\Framework\MockObject\MockObject;
use MsgPhp\Domain\Tests\Fixtures\CountableIterator;

/**
* @internal
Expand Down Expand Up @@ -318,8 +318,7 @@ public function testLazyCount(): void

public function testDecoratedCount(): void
{
/** @var \Iterator&\Countable&MockObject $countable */
$countable = $this->createMock([\Iterator::class, \Countable::class]);
$countable = $this->createMock(CountableIterator::class);
$countable->expects(self::once())
->method('count')
->willReturn(0)
Expand Down
89 changes: 89 additions & 0 deletions src/Domain/Tests/GenericDomainIdTest.php
1098F
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<?php

declare(strict_types=1);

namespace MsgPhp\Domain\Tests;

use MsgPhp\Domain\DomainId;
use MsgPhp\Domain\GenericDomainId;
use PHPUnit\Framework\TestCase;

/**
* @internal
*/
final class GenericDomainIdTest extends TestCase
{
public function testFromValue(): void
{
self::assertInstanceOf(GenericDomainId::class, GenericDomainId::fromValue(null));
self::assertSame((array) new GenericDomainId(), (array) GenericDomainId::fromValue(null));
self::assertSame((array) new GenericDomainId(null), (array) GenericDomainId::fromValue(null));
self::assertSame((array) new GenericDomainId(''), (array) GenericDomainId::fromValue(null));
self::assertSame((array) new GenericDomainId('foo'), (array) GenericDomainId::fromValue('foo'));
self::assertSame((array) new GenericDomainId('1'), (array) GenericDomainId::fromValue(1));
self::assertSame((array) new GenericDomainId(' '), (array) GenericDomainId::fromValue(' '));
}

public function testFromInvalidValue(): void
{
$this->expectException(\LogicException::class);

GenericDomainId::fromValue(true);
}

public function testIsNil(): void
{
self::assertTrue((new GenericDomainId())->isNil());
self::assertTrue((new GenericDomainId(null))->isNil());
self::assertTrue((new GenericDomainId(''))->isNil());
self::assertFalse((new GenericDomainId(' '))->isNil());
self::assertFalse((new GenericDomainId('foo'))->isNil());
}

public function testEquals(): void
{
$id = new GenericDomainId('foo');
$nilId = new GenericDomainId();
$otherId = $this->createMock(DomainId::class);
$otherId->expects(self::once())
->method('toString')
->willReturn('foo')
;

self::assertTrue($id->equals($id));
self::assertTrue($id->equals(new GenericDomainId('foo')));
self::assertFalse($id->equals(new GenericDomainId()));
self::assertFalse($id->equals('foo'));
self::assertFalse($id->equals(new \stdClass()));
self::assertTrue($nilId->equals($nilId));
self::assertTrue($nilId->equals(new GenericDomainId()));
self::assertFalse($nilId->equals(''));
self::assertFalse($nilId->equals(new \stdClass()));
self::assertTrue($id->equals($otherId));
}

/**
* @dataProvider provideIds
*/
public function testToString(DomainId $id, string $value): void
{
self::assertSame($value, $id->toString());
self::assertSame($value, (string) $id);
}

/**
* @dataProvider provideIds
*/
public function testSerialize(DomainId $id): void
{
self::assertSame((array) $id, (array) unserialize(serialize($id)));
}

public function provideIds(): iterable
{
yield [new GenericDomainId(), ''];
yield [new GenericDomainId(null), ''];
yield [new GenericDomainId('foo'), 'foo'];
yield [new GenericDomainId(' '), ' '];
}
}
Loading
0