8000 add GenericDomainId + DomainUuid (#385) · msgphp/msgphp@1231991 · GitHub
[go: up one dir, main page]

Skip to content

Commit 1231991

Browse files
authored
add GenericDomainId + DomainUuid (#385)
1 parent aaeb01f commit 1231991

File tree

8 files changed

+304
-39
lines changed

8 files changed

+304
-39
lines changed

docs/ddd/identifiers.md

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,64 +7,55 @@ identifier value, usually used to identity an entity with.
77

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

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

1413
### `isNil(): bool`
1514

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

18-
---
19-
2017
### `equals($other): bool`
2118

2219
Tells if an identifier strictly equals another identifier.
2320

24-
---
25-
2621
### `toString(): string`
2722

2823
Returns the identifier its primitive string value.
2924

3025
## Implementations
3126

32-
### `MsgPhp\Domain\DomainIdTrait`
27+
### `MsgPhp\Domain\GenericDomainId`
3328

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

3631
#### Basic Example
3732

3833
```php
3934
<?php
4035

41-
use MsgPhp\Domain\DomainId;
42-
use MsgPhp\Domain\DomainIdTrait;
43-
44-
// --- SETUP ---
36+
use MsgPhp\Domain\GenericDomainId;
4537

46-
class MyDomainId implements DomainId
47-
{
48-
use DomainIdTrait;
49-
}
38+
// SETUP
5039

51-
$id = new MyDomainId('1');
52-
$emptyId = new MyDomainId();
40+
$id = new GenericDomainId('1');
41+
$id = GenericDomainId::fromValue(1);
42+
$nilId = new GenericDomainId();
5343

54-
// --- USAGE ---
44+
// USAGE
5545

5646
$id->isNil(); // false
57-
$emptyId->isNil(); // true
47+
$nilId->isNil(); // true
5848

5949
$id->toString(); // "1"
60-
$emptyId->toString(); // ""
50+
$nilId->toString(); // ""
6151

62-
$id->equals(new MyDomainId('1')); // true
52+
$id->equals(new GenericDomainId('1')); // true
6353
$id->equals('1'); // false
64-
$id->equals(new MyDomainId('2')); // false
54+
$id->equals(new GenericDomainId('2')); // false
55+
$id->equals(new GenericDomainId()); // false
6556
```
6657

67-
### `MsgPhp\Domain\Infrastructure\Uuid\DomainIdTrait`
58+
### `MsgPhp\Domain\Infrastructure\Uuid\DomainUuid`
6859

6960
A UUID tailored domain identifier trait.
7061

docs/infrastructure/uuid.md

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,22 @@ An overview of available infrastructural code when working with [UUIDs][uuid].
66

77
## Domain Identifier
88

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

1111
### Basic Example
1212

1313
```php
1414
<?php
1515

16-
use MsgPhp\Domain\DomainId;
17-
use MsgPhp\Domain\Infrastructure\Uuid\DomainIdTrait;
16+
use MsgPhp\Domain\Infrastructure\Uuid\DomainUuid;
1817
use Ramsey\Uuid\Uuid;
1918

2019
// SETUP
2120

22-
class MyDomainUuid implements DomainId
23-
{
24-
use DomainIdTrait;
25-
}
26-
27-
$id = new MyDomainUuid(); // a new UUID version 4 value
28-
$id = new MyDomainUuid(Uuid::uuid1());
29-
$id = new MyDomainUuid(Uuid::fromString('00000000-0000-0000-0000-000000000000'));
21+
$id = new DomainUuid(); // a new UUID version 4 value
22+
$id = new DomainUuid(Uuid::uuid1());
23+
$id = new DomainUuid(Uuid::fromString('00000000-0000-0000-0000-000000000000'));
24+
$id = DomainUuid::fromValue('00000000-0000-0000-0000-000000000000');
3025
```
3126

3227
[uuid]: https://en.wikipedia.org/wiki/Universally_unique_identifier

src/Domain/GenericDomainId.php

Lines changed: 51 additions & 0 deletions
EF5E
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace MsgPhp\Domain;
6+
7+
/**
8+
* @author Roland Franssen <franssen.roland@gmail.com>
9+
*/
10+
final class GenericDomainId implements DomainId
11+
{
12+
/** @var string */
13+
private $id;
14+
15+
public function __construct(?string $id = null)
16+
{
17+
$this->id = $id ?? '';
18+
}
19+
20+
public function __toString(): string
21+
{
22+
return $this->id;
23+
}
24+
25+
public static function fromValue($value): DomainId
26+
{
27+
if (null === $value || \is_string($value)) {
28+
return new self($value);
29+
}
30+
if (is_numeric($value)) {
31+
return new self((string) $value);
32+
}
33+
34+
throw new \LogicException('Raw ID value must be of type string or number, got "'.\gettype($value).'".');
35+
}
36+
37+
public function isNil(): bool
38+
{
39+
return '' === $this->id;
40+
}
41+
42+
public function equals($other): bool
43+
{
44+
return $other instanceof DomainId && $this->id === $other->toString();
45+
}
46+
47+
public function toString(): string
48+
{
49+
return $this->id;
50+
}
51+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace MsgPhp\Domain\Infrastructure\Uuid;
6+
7+
use MsgPhp\Domain\DomainId;
8+
use Ramsey\Uuid\Uuid;
9+
use Ramsey\Uuid\UuidInterface;
10+
11+
/**
12+
* @author Roland Franssen <franssen.roland@gmail.com>
13+
*/
14+
final class DomainUuid implements DomainId
15+
{
16+
/** @var UuidInterface */
17+
private $uuid;
18+
19+
public function __construct(?UuidInterface $uuid = null)
20+
{
21+
$this->uuid = $uuid ?? Uuid::uuid4();
22+
}
23+
24+
public function __toString(): string
25+
{
26+
return $this->uuid->toString();
27+
}
28+
29+
public static function fromValue($value): DomainId
30+
{
31+
if (null === $value || $value instanceof UuidInterface) {
32+
return new self($value);
33+
}
34+
if (\is_string($value)) {
35+
return new self(Uuid::fromString($value));
36+
}
37+
38+
throw new \LogicException('Raw UUID value must be of type string, got "'.\gettype($value).'".');
39+
}
40+
41+
public function isNil(): bool
42+
{
43+
return $this->uuid->equals(Uuid::fromString(Uuid::NIL));
44+
}
45+
46+
public function equals($other): bool
47+
{
48+
return $other instanceof self && $this->uuid->equals($other->uuid);
49+
}
50+
51+
public function toString(): string
52+
{
53+
return $this->uuid->toString();
54+
}
55+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace MsgPhp\Domain\Tests\Fixtures;
6+
7+
interface CountableIterator extends \Iterator, \Countable
8+
{
9+
}

src/Domain/Tests/GenericDomainCollectionTest.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
use MsgPhp\Domain\Exception\EmptyCollection;
99
use MsgPhp\Domain\Exception\UnknownCollectionElement;
1010
use MsgPhp\Domain\GenericDomainCollection;
11-
use PHPUnit\Framework\MockObject\MockObject;
11+
use MsgPhp\Domain\Tests\Fixtures\CountableIterator;
1212

1313
/**
1414
* @internal
@@ -318,8 +318,7 @@ public function testLazyCount(): void
318318

319319
public function testDecoratedCount(): void
320320
{
321-
/** @var \Iterator&\Countable&MockObject $countable */
322-
$countable = $this->createMock([\Iterator::class, \Countable::class]);
321+
$countable = $this->createMock(CountableIterator::class);
323322
$countable->expects(self::once())
324323
->method('count')
325324
->willReturn(0)
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace MsgPhp\Domain\Tests;
6+
7+
use MsgPhp\Domain\DomainId;
8+
use MsgPhp\Domain\GenericDomainId;
9+
use PHPUnit\Framework\TestCase;
10+
11+
/**
12+
* @internal
13+
*/
14+
final class GenericDomainIdTest extends TestCase
15+
{
16+
public function testFromValue(): void
17+
{
18+
self::assertInstanceOf(GenericDomainId::class, GenericDomainId::fromValue(null));
19+
self::assertSame((array) new GenericDomainId(), (array) GenericDomainId::fromValue(null));
20+
self::assertSame((array) new GenericDomainId(null), (array) GenericDomainId::fromValue(null));
21+
self::assertSame((array) new GenericDomainId(''), (array) GenericDomainId::fromValue(null));
22+
self::assertSame((array) new GenericDomainId('foo'), (array) GenericDomainId::fromValue('foo'));
23+
self::assertSame((array) new GenericDomainId('1'), (array) GenericDomainId::fromValue(1));
24+
self::assertSame((array) new GenericDomainId(' '), (array) GenericDomainId::fromValue(' '));
25+
}
26+
27+
public function testFromInvalidValue(): void
28+
{
29+
$this->expectException(\LogicException::class);
30+
31+
GenericDomainId::fromValue(true);
32+
}
33+
34+
public function testIsNil(): void
35+
{
36+
self::assertTrue((new GenericDomainId())->isNil());
37+
self::assertTrue((new GenericDomainId(null))->isNil());
38+
self::assertTrue((new GenericDomainId(''))->isNil());
39+
self::assertFalse((new GenericDomainId(' '))->isNil());
40+
self::assertFalse((new GenericDomainId('foo'))->isNil());
41+
}
42+
43+
public function testEquals(): void
44+
{
45+
$id = new GenericDomainId('foo');
46+
$nilId = new GenericDomainId();
47+
$otherId = $this->createMock(DomainId::class);
48+
$otherId->expects(self::once())
49+
->method('toString')
50+
->willReturn('foo')
51+
;
52+
53+
self::assertTrue($id->equals($id));
54+
self::assertTrue($id->equals(new GenericDomainId('foo')));
55+
self::assertFalse($id->equals(new GenericDomainId()));
56+
self::assertFalse($id->equals('foo'));
57+
self::assertFalse($id->equals(new \stdClass()));
58+
self::assertTrue($nilId->equals($nilId));
59+
self::assertTrue($nilId->equals(new GenericDomainId()));
60+
self::assertFalse($nilId->equals(''));
61+
self::assertFalse($nilId->equals(new \stdClass()));
62+
self::assertTrue($id->equals($otherId));
63+
}
64+
65+
/**
66+
* @dataProvider provideIds
67+
*/
68+
public function testToString(DomainId $id, string $value): void
69+
{
70+
self::assertSame($value, $id->toString());
71+
self::assertSame($value, (string) $id);
72+
}
73+
74+
/**
75+
* @dataProvider provideIds
76+
*/
77+
public function testSerialize(DomainId $id): void
78+
{
79+
self::assertSame((array) $id, (array) unserialize(serialize($id)));
80+
}
81+
82+
public function provideIds(): iterable
83+
{
84+
yield [new GenericDomainId(), ''];
85+
yield [new GenericDomainId(null), ''];
86+
yield [new GenericDomainId('foo'), 'foo'];
87+
yield [new GenericDomainId(' '), ' '];
88+
}
89+
}

0 commit comments

Comments
 (0)
0