Passed
Push — currentLimits ( af2764...193e29 )
by no
03:56
created

SnakList::equals()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 5
nc 3
nop 1
1
<?php
2
3
namespace Wikibase\DataModel\Snak;
4
5
use Comparable;
6
use Hashable;
7
use InvalidArgumentException;
8
use Traversable;
9
use Wikibase\DataModel\HashArray;
10
use Wikibase\DataModel\Internal\MapValueHasher;
11
12
/**
13
 * List of Snak objects.
14
 * Indexes the snaks by hash and ensures no more the one snak with the same hash are in the list.
15
 *
16
 * @since 0.1
17
 *
18
 * @license GPL-2.0+
19
 * @author Jeroen De Dauw < [email protected] >
20
 * @author Addshore
21
 */
22
class SnakList extends HashArray implements Comparable, Hashable {
23
24
	/**
25
	 * @param Snak[]|Traversable $snaks
26
	 *
27
	 * @throws InvalidArgumentException
28
	 */
29
	public function __construct( $snaks = [] ) {
30
		if ( !is_array( $snaks ) && !( $snaks instanceof Traversable ) ) {
31
			throw new InvalidArgumentException( '$snaks must be an array or an instance of Traversable' );
32
		}
33
34
		foreach ( $snaks as $index => $snak ) {
35
			$this->setElement( $index, $snak );
36
		}
37
	}
38
39
	/**
40
	 * @see GenericArrayObject::getObjectType
41
	 *
42
	 * @since 0.1
43
	 *
44
	 * @return string
45
	 */
46
	public function getObjectType() {
47
		return Snak::class;
48
	}
49
50
	/**
51
	 * @since 0.1
52
	 *
53
	 * @param string $snakHash
54
	 *
55
	 * @return boolean
56
	 */
57
	public function hasSnakHash( $snakHash ) {
58
		return $this->hasElementHash( $snakHash );
59
	}
60
61
	/**
62
	 * @since 0.1
63
	 *
64
	 * @param string $snakHash
65
	 */
66
	public function removeSnakHash( $snakHash ) {
67
		$this->removeByElementHash( $snakHash );
68
	}
69
70
	/**
71
	 * @since 0.1
72
	 *
73
	 * @param Snak $snak
74
	 *
75
	 * @return boolean Indicates if the snak was added or not.
76
	 */
77
	public function addSnak( Snak $snak ) {
78
		return $this->addElement( $snak );
79
	}
80
81
	/**
82
	 * @since 0.1
83
	 *
84
	 * @param Snak $snak
85
	 *
86
	 * @return boolean
87
	 */
88
	public function hasSnak( Snak $snak ) {
89
		return $this->hasElementHash( $snak->getHash() );
90
	}
91
92
	/**
93
	 * @since 0.1
94
	 *
95
	 * @param Snak $snak
96
	 */
97
	public function removeSnak( Snak $snak ) {
98
		$this->removeByElementHash( $snak->getHash() );
99
	}
100
101
	/**
102
	 * @since 0.1
103
	 *
104
	 * @param string $snakHash
105
	 *
106
	 * @return Snak|bool
107
	 */
108
	public function getSnak( $snakHash ) {
109
		return $this->getByElementHash( $snakHash );
110
	}
111
112
	/**
113
	 * @see Comparable::equals
114
	 *
115
	 * The comparison is done purely value based, ignoring the order of the elements in the array.
116
	 *
117
	 * @since 0.3
118
	 *
119
	 * @param mixed $target
120
	 *
121
	 * @return bool
122
	 */
123
	public function equals( $target ) {
124
		if ( $this === $target ) {
125
			return true;
126
		}
127
128
		return $target instanceof self
129
			&& $this->getHash() === $target->getHash();
130
	}
131
132
	/**
133
	 * @see Hashable::getHash
134
	 *
135
	 * The hash is purely value based. Order of the elements in the array is not held into account.
136
	 *
137
	 * @since 0.1
138
	 *
139
	 * @return string
140
	 */
141
	public function getHash() {
142
		$hasher = new MapValueHasher();
143
		return $hasher->hash( $this );
144
	}
145
146
	/**
147
	 * Orders the snaks in the list grouping them by property.
148
	 *
149
	 * @param string[] $order List of serliazed property ids to order by.
150
	 *
151
	 * @since 0.5
152
	 */
153
	public function orderByProperty( array $order = [] ) {
154
		$snaksByProperty = $this->getSnaksByProperty();
155
		$orderedProperties = array_unique( array_merge( $order, array_keys( $snaksByProperty ) ) );
156
157
		foreach ( $orderedProperties as $property ) {
158
			if ( array_key_exists( $property, $snaksByProperty ) ) {
159
				$snaks = $snaksByProperty[$property];
160
				$this->moveSnaksToBottom( $snaks );
161
			}
162
		}
163
	}
164
165
	/**
166
	 * @param Snak[] $snaks to remove and re add
167
	 */
168
	private function moveSnaksToBottom( array $snaks ) {
169
		foreach ( $snaks as $snak ) {
170
			$this->removeSnak( $snak );
171
			$this->addSnak( $snak );
172
		}
173
	}
174
175
	/**
176
	 * Gets the snaks in the current object in an array
177
	 * grouped by property id
178
	 *
179
	 * @return array[]
180
	 */
181
	private function getSnaksByProperty() {
182
		$snaksByProperty = [];
183
184
		foreach ( $this as $snak ) {
185
			/** @var Snak $snak */
186
			$propertyId = $snak->getPropertyId()->getSerialization();
187
			if ( !isset( $snaksByProperty[$propertyId] ) ) {
188
				$snaksByProperty[$propertyId] = [];
189
			}
190
			$snaksByProperty[$propertyId][] = $snak;
191
		}
192
193
		return $snaksByProperty;
194
	}
195
196
}
197