Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
94.00% |
47 / 50 |
|
81.25% |
13 / 16 |
CRAP | |
0.00% |
0 / 1 |
SenseSet | |
94.00% |
47 / 50 |
|
81.25% |
13 / 16 |
28.17 | |
0.00% |
0 / 1 |
__construct | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
3 | |||
toArray | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
toArrayUnordered | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
sortSenses | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
2 | |||
count | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
maxSenseIdNumber | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
3 | |||
add | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
2 | |||
remove | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
put | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getById | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
copy | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
__clone | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
isEmpty | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
equals | |
80.00% |
4 / 5 |
|
0.00% |
0 / 1 |
3.07 | |||
hasSenseWithId | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
sameSenses | |
83.33% |
5 / 6 |
|
0.00% |
0 / 1 |
4.07 |
1 | <?php |
2 | |
3 | declare( strict_types = 1 ); |
4 | |
5 | namespace Wikibase\Lexeme\Domain\Model; |
6 | |
7 | use Countable; |
8 | use InvalidArgumentException; |
9 | use Wikibase\Lexeme\Domain\Model\Exceptions\ConflictException; |
10 | |
11 | /** |
12 | * Set of Senses in which uniqueness of a Sense is controlled by its ID. |
13 | * Supposed to be used only inside the Lexeme class. |
14 | * |
15 | * @license GPL-2.0-or-later |
16 | */ |
17 | class SenseSet implements Countable { |
18 | |
19 | /** |
20 | * @var Sense[] indexed by serialization of SenseId |
21 | */ |
22 | private array $senses = []; |
23 | |
24 | /** |
25 | * @param Sense[] $senses |
26 | */ |
27 | public function __construct( array $senses = [] ) { |
28 | foreach ( $senses as $sense ) { |
29 | if ( !$sense instanceof Sense ) { |
30 | throw new InvalidArgumentException( '$senses must be an array of Senses' ); |
31 | } |
32 | |
33 | $this->add( $sense ); |
34 | } |
35 | } |
36 | |
37 | /** |
38 | * @return Sense[] |
39 | */ |
40 | public function toArray(): array { |
41 | $senses = $this->sortSenses( $this->senses ); |
42 | return array_values( $senses ); |
43 | } |
44 | |
45 | /** |
46 | * Return the individual Senses in arbitrary order. |
47 | * |
48 | * Only use this method if the order is certainly insignificant, |
49 | * e.g. because the Senses will be summarized or reduced in some way. |
50 | * Otherwise, use {@link toArray()}. |
51 | * |
52 | * @return Sense[] |
53 | */ |
54 | public function toArrayUnordered(): array { |
55 | return array_values( $this->senses ); |
56 | } |
57 | |
58 | /** |
59 | * @param Sense[] $senses |
60 | * @return Sense[] sorted array mapping numeric id to the sense |
61 | */ |
62 | private function sortSenses( array $senses ): array { |
63 | $sortedSenses = []; |
64 | foreach ( $senses as $sense ) { |
65 | $senseIdPart = explode( '-', $sense->getId()->getSerialization(), 2 )[1]; |
66 | $senseIdNumber = (int)substr( $senseIdPart, 1 ); |
67 | $sortedSenses[$senseIdNumber] = $sense; |
68 | } |
69 | ksort( $sortedSenses ); |
70 | |
71 | return $sortedSenses; |
72 | } |
73 | |
74 | public function count(): int { |
75 | return count( $this->senses ); |
76 | } |
77 | |
78 | public function maxSenseIdNumber(): int { |
79 | $max = 0; |
80 | |
81 | foreach ( $this->senses as $senseId => $sense ) { |
82 | $senseIdPart = explode( '-', $senseId, 2 )[1]; |
83 | $senseIdNumber = (int)substr( $senseIdPart, 1 ); |
84 | if ( $senseIdNumber > $max ) { |
85 | $max = $senseIdNumber; |
86 | } |
87 | } |
88 | |
89 | return $max; |
90 | } |
91 | |
92 | public function add( Sense $sense ): void { |
93 | $senseId = $sense->getId()->getSerialization(); |
94 | if ( array_key_exists( $senseId, $this->senses ) ) { |
95 | throw new ConflictException( |
96 | 'At least two senses with the same ID were provided: `' . $senseId . '`' |
97 | ); |
98 | } |
99 | |
100 | $this->senses[$senseId] = $sense; |
101 | } |
102 | |
103 | public function remove( SenseId $senseId ): void { |
104 | unset( $this->senses[$senseId->getSerialization()] ); |
105 | } |
106 | |
107 | /** |
108 | * Replace the sense identified by $sense->getId() with the given one or add it. |
109 | */ |
110 | public function put( Sense $sense ): void { |
111 | $this->remove( $sense->getId() ); |
112 | $this->add( $sense ); |
113 | } |
114 | |
115 | public function getById( SenseId $senseId ): ?Sense { |
116 | return $this->senses[$senseId->getSerialization()] ?? null; |
117 | } |
118 | |
119 | public function copy(): self { |
120 | return clone $this; |
121 | } |
122 | |
123 | /** |
124 | * @see http://php.net/manual/en/language.oop5.cloning.php |
125 | */ |
126 | public function __clone() { |
127 | $clonedSenses = []; |
128 | foreach ( $this->senses as $key => $sense ) { |
129 | $clonedSenses[$key] = clone $sense; |
130 | } |
131 | $this->senses = $clonedSenses; |
132 | } |
133 | |
134 | public function isEmpty(): bool { |
135 | return $this->senses === []; |
136 | } |
137 | |
138 | public function equals( $other ): bool { |
139 | if ( $this === $other ) { |
140 | return true; |
141 | } |
142 | |
143 | if ( !( $other instanceof self ) ) { |
144 | return false; |
145 | } |
146 | |
147 | return $this->sameSenses( $other ); |
148 | } |
149 | |
150 | public function hasSenseWithId( SenseId $id ): bool { |
151 | return $this->getById( $id ) !== null; |
152 | } |
153 | |
154 | private function sameSenses( SenseSet $other ): bool { |
155 | if ( $this->count() !== $other->count() ) { |
156 | return false; |
157 | } |
158 | |
159 | foreach ( $this->senses as $sense ) { |
160 | if ( !$sense->equals( $other->getById( $sense->getId() ) ) ) { |
161 | return false; |
162 | } |
163 | } |
164 | |
165 | return true; |
166 | } |
167 | |
168 | } |