|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* This file is part of the daikon-cqrs/entity project. |
|
4
|
|
|
* |
|
5
|
|
|
* For the full copyright and license information, please view the LICENSE |
|
6
|
|
|
* file that was distributed with this source code. |
|
7
|
|
|
*/ |
|
8
|
|
|
|
|
9
|
|
|
declare(strict_types=1); |
|
10
|
|
|
|
|
11
|
|
|
namespace Daikon\Entity\Entity; |
|
12
|
|
|
|
|
13
|
|
|
use Assert\Assertion; |
|
14
|
|
|
use Daikon\Entity\ValueObject\ValueObjectInterface; |
|
15
|
|
|
use Ds\Vector; |
|
16
|
|
|
use Iterator; |
|
17
|
|
|
|
|
18
|
|
|
trait EntityListTrait |
|
19
|
|
|
{ |
|
20
|
|
|
/** |
|
21
|
|
|
* @var Vector internal vector to store items |
|
22
|
|
|
*/ |
|
23
|
|
|
private $compositeVector; |
|
24
|
|
|
|
|
25
|
|
|
public static function makeEmpty(): self |
|
26
|
|
|
{ |
|
27
|
|
|
return new self; |
|
28
|
|
|
} |
|
29
|
|
|
|
|
30
|
10 |
|
public static function wrap($entities): self |
|
31
|
|
|
{ |
|
32
|
10 |
|
return new self($entities); |
|
|
|
|
|
|
33
|
|
|
} |
|
34
|
|
|
|
|
35
|
10 |
|
public static function fromNative($nativeValue): self |
|
36
|
|
|
{ |
|
37
|
10 |
|
Assertion::nullOrIsArray($nativeValue); |
|
38
|
10 |
|
if (is_null($nativeValue)) { |
|
39
|
|
|
return self::makeEmpty(); |
|
40
|
|
|
} |
|
41
|
10 |
|
$entities = []; |
|
42
|
10 |
|
foreach ($nativeValue as $nativeEntityState) { |
|
43
|
10 |
|
Assertion::keyExists($nativeEntityState, EntityInterface::TYPE_KEY); |
|
44
|
10 |
|
$entityFqcn = $nativeEntityState[EntityInterface::TYPE_KEY]; |
|
45
|
10 |
|
$entities[] = call_user_func([ $entityFqcn, 'fromNative' ], $nativeEntityState); |
|
46
|
|
|
} |
|
47
|
10 |
|
return self::wrap($entities); |
|
48
|
|
|
} |
|
49
|
|
|
|
|
50
|
|
|
public function toNative(): array |
|
51
|
|
|
{ |
|
52
|
1 |
|
return $this->compositeVector->map(function (ValueObjectInterface $entity): array { |
|
53
|
1 |
|
return $entity->toNative(); |
|
54
|
1 |
|
})->toArray(); |
|
55
|
|
|
} |
|
56
|
|
|
|
|
57
|
|
|
public function equals(ValueObjectInterface $list): bool |
|
58
|
|
|
{ |
|
59
|
|
|
/** EntityList $list */ |
|
60
|
|
|
if (!$list instanceof self || $this->count() !== $list->count()) { |
|
61
|
|
|
return false; |
|
62
|
|
|
} |
|
63
|
|
|
/** @var EntityInterface $entity */ |
|
64
|
|
|
foreach ($this as $pos => $entity) { |
|
|
|
|
|
|
65
|
|
|
if (!$entity->equals($list->get($pos))) { |
|
66
|
|
|
return false; |
|
67
|
|
|
} |
|
68
|
|
|
} |
|
69
|
|
|
return true; |
|
70
|
|
|
} |
|
71
|
|
|
|
|
72
|
|
|
public function __toString(): string |
|
73
|
|
|
{ |
|
74
|
|
|
$parts = []; |
|
75
|
|
|
foreach ($this as $entity) { |
|
|
|
|
|
|
76
|
|
|
$parts[] = (string)$entity; |
|
77
|
|
|
} |
|
78
|
|
|
return implode(', ', $parts); |
|
79
|
|
|
} |
|
80
|
|
|
|
|
81
|
|
|
public function diff(EntityListInterface $list): EntityListInterface |
|
82
|
|
|
{ |
|
83
|
|
|
$differingEntities = []; |
|
84
|
|
|
foreach ($this as $pos => $entity) { |
|
|
|
|
|
|
85
|
|
|
if (!$list->has($pos) || !(new EntityDiff)($entity, $list->get($pos))->isEmpty()) { |
|
86
|
|
|
$differingEntities[] = $entity; |
|
87
|
|
|
} |
|
88
|
|
|
} |
|
89
|
|
|
return new self($differingEntities); |
|
|
|
|
|
|
90
|
|
|
} |
|
91
|
|
|
|
|
92
|
|
|
public function has(int $index): bool |
|
93
|
|
|
{ |
|
94
|
|
|
return $this->compositeVector->offsetExists($index); |
|
95
|
|
|
} |
|
96
|
|
|
|
|
97
|
1 |
|
public function get(int $index): EntityInterface |
|
98
|
|
|
{ |
|
99
|
1 |
|
return $this->compositeVector->get($index); |
|
100
|
|
|
} |
|
101
|
|
|
|
|
102
|
|
|
public function push(EntityInterface $item): self |
|
103
|
|
|
{ |
|
104
|
|
|
$copy = clone $this; |
|
105
|
|
|
$copy->compositeVector->push($item); |
|
106
|
|
|
return $copy; |
|
107
|
|
|
} |
|
108
|
|
|
|
|
109
|
|
|
public function prepend(EntityInterface $item): self |
|
110
|
|
|
{ |
|
111
|
|
|
$copy = clone $this; |
|
112
|
|
|
$copy->compositeVector->unshift($item); |
|
113
|
|
|
return $copy; |
|
114
|
|
|
} |
|
115
|
|
|
|
|
116
|
|
|
public function remove(EntityInterface $item): self |
|
117
|
|
|
{ |
|
118
|
|
|
$idx = $this->indexOf($item); |
|
119
|
|
|
$copy = clone $this; |
|
120
|
|
|
$copy->compositeVector->remove($idx); |
|
121
|
|
|
return $copy; |
|
122
|
|
|
} |
|
123
|
|
|
|
|
124
|
|
|
public function reverse(): self |
|
125
|
|
|
{ |
|
126
|
|
|
$copy = clone $this; |
|
127
|
|
|
$copy->compositeVector->reverse(); |
|
128
|
|
|
return $copy; |
|
129
|
|
|
} |
|
130
|
|
|
|
|
131
|
|
|
public function count(): int |
|
132
|
|
|
{ |
|
133
|
|
|
return $this->compositeVector->count(); |
|
134
|
|
|
} |
|
135
|
|
|
|
|
136
|
|
|
public function isEmpty(): bool |
|
137
|
|
|
{ |
|
138
|
|
|
return $this->compositeVector->isEmpty(); |
|
139
|
|
|
} |
|
140
|
|
|
|
|
141
|
|
|
public function indexOf(EntityInterface $item): int |
|
142
|
|
|
{ |
|
143
|
|
|
return $this->compositeVector->find($item); |
|
144
|
|
|
} |
|
145
|
|
|
|
|
146
|
|
|
public function getFirst() |
|
147
|
|
|
{ |
|
148
|
|
|
return $this->compositeVector->first(); |
|
149
|
|
|
} |
|
150
|
|
|
|
|
151
|
|
|
public function getLast() |
|
152
|
|
|
{ |
|
153
|
|
|
return $this->compositeVector->last(); |
|
154
|
|
|
} |
|
155
|
|
|
|
|
156
|
|
|
public function toArray(): array |
|
157
|
|
|
{ |
|
158
|
|
|
return $this->compositeVector->toArray(); |
|
159
|
|
|
} |
|
160
|
|
|
|
|
161
|
|
|
public function getIterator(): Iterator |
|
162
|
|
|
{ |
|
163
|
|
|
return $this->compositeVector->getIterator(); |
|
164
|
|
|
} |
|
165
|
|
|
} |
|
166
|
|
|
|
This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.
In this case you can add the
@ignorePhpDoc annotation to the duplicate definition and it will be ignored.