EntityId::assertValidSerialization()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 13
ccs 4
cts 4
cp 1
rs 9.8333
c 0
b 0
f 0
cc 4
nc 4
nop 1
crap 4
1
<?php
2
3
namespace Wikibase\DataModel\Entity;
4
5
use InvalidArgumentException;
6
use Serializable;
7
8
/**
9
 * @since 0.5
10
 * Abstract since 2.0
11
 *
12
 * @license GPL-2.0-or-later
13
 */
14
abstract class EntityId implements Serializable {
15
16
	protected $serialization;
17
18
	/**
19
	 * @since 7.3
20
	 *
21
	 * @var string
22
	 */
23
	protected $repositoryName;
24
25
	/**
26
	 * @since 7.3
27
	 *
28 31
	 * @var string
29 31
	 */
30
	protected $localPart;
31
32
	public const PATTERN = '/^:?(\w+:)*[^:]+\z/';
33
34
	/**
35
	 * @since 6.2
36
	 *
37
	 * @param string $serialization
38
	 *
39 5
	 * @throws InvalidArgumentException
40 5
	 */
41
	public function __construct( $serialization ) {
42
		self::assertValidSerialization( $serialization );
43
		$this->serialization = self::normalizeIdSerialization( $serialization );
44
45
		list( $this->repositoryName, $this->localPart ) = self::extractRepositoryNameAndLocalPart( $serialization );
46
	}
47
48
	private static function assertValidSerialization( $serialization ) {
49
		if ( !is_string( $serialization ) ) {
50
			throw new InvalidArgumentException( '$serialization must be a string' );
51
		}
52 5
53 5
		if ( $serialization === '' ) {
54 5
			throw new InvalidArgumentException( '$serialization must not be an empty string' );
55
		}
56
57
		if ( !preg_match( self::PATTERN, $serialization ) ) {
58 5
			throw new InvalidArgumentException( '$serialization must match ' . self::PATTERN );
59
		}
60
	}
61
62
	/**
63
	 * @return string
64
	 */
65
	abstract public function getEntityType();
66
67
	/**
68
	 * @return string
69
	 */
70
	public function getSerialization() {
71
		return $this->serialization;
72
	}
73
74
	/**
75
	 * Returns an array with 3 elements: the foreign repository name as the first element, the local ID as the last
76
	 * element and everything that is in between as the second element.
77
	 *
78
	 * EntityId::joinSerialization can be used to restore the original serialization from the parts returned.
79
	 *
80
	 * @since 6.2
81
	 *
82
	 * @param string $serialization
83
	 *
84
	 * @throws InvalidArgumentException
85
	 * @return string[] Array containing the serialization split into 3 parts.
86
	 */
87
	public static function splitSerialization( $serialization ) {
88
		self::assertValidSerialization( $serialization );
89
90
		return self::extractSerializationParts( self::normalizeIdSerialization( $serialization ) );
91
	}
92
93
	/**
94
	 * Splits the given ID serialization into an array with the following three elements:
95
	 *  - the repository name as the first element (empty string for local repository)
96
	 *  - any parts of the ID serialization but the repository name and the local ID (if any, empty string
97
	 *    if nothing else present)
98
	 *  - the local ID
99
	 * Note: this method does not perform any validation of the given input. Calling code should take
100
	 * care of this!
101
	 *
102
	 * @param string $serialization
103
	 *
104
	 * @return string[]
105
	 */
106
	private static function extractSerializationParts( $serialization ) {
107
		$parts = explode( ':', $serialization );
108
		$localPart = array_pop( $parts );
109
		$repoName = array_shift( $parts );
110
		$prefixRemainder = implode( ':', $parts );
111
112
		return [
113
			is_string( $repoName ) ? $repoName : '',
114
			$prefixRemainder,
115
			$localPart
116
		];
117
	}
118
119
	/**
120
	 * Builds an ID serialization from the parts returned by EntityId::splitSerialization.
121
	 *
122
	 * @since 6.2
123
	 *
124
	 * @param string[] $parts
125
	 *
126
	 * @throws InvalidArgumentException
127
	 * @return string
128
	 */
129
	public static function joinSerialization( array $parts ) {
130
		if ( end( $parts ) === '' ) {
131
			throw new InvalidArgumentException( 'The last element of $parts must not be empty.' );
132
		}
133
134
		return implode(
135
			':',
136
			array_filter( $parts, function( $part ) {
137
				return $part !== '';
138
			} )
139
		);
140
	}
141
142
	/**
143
	 * Returns '' for local IDs and the foreign repository name for foreign IDs. For chained IDs (e.g. foo:bar:Q42) it
144
	 * will return only the first part.
145
	 *
146
	 * @since 6.2
147
	 *
148
	 * @return string
149
	 */
150
	public function getRepositoryName() {
151
		return $this->repositoryName;
152
	}
153
154
	/**
155
	 * Returns the serialization without the first repository prefix.
156
	 *
157
	 * @since 6.2
158
	 *
159
	 * @return string
160
	 */
161
	public function getLocalPart() {
162
		return $this->localPart;
163
	}
164
165
	/**
166
	 * Returns true iff EntityId::getRepositoryName returns a non-empty string.
167
	 *
168
	 * @since 6.2
169
	 *
170
	 * @return bool
171
	 */
172
	public function isForeign() {
173
		return $this->repositoryName !== '';
174
	}
175
176
	/**
177
	 * @param string $id
178
	 *
179
	 * @return string
180
	 */
181
	private static function normalizeIdSerialization( $id ) {
182
		return ltrim( $id, ':' );
183
	}
184
185
	/**
186
	 * This is a human readable representation of the EntityId.
187
	 * This format is allowed to change and should therefore not
188
	 * be relied upon to be stable.
189
	 *
190
	 * @return string
191
	 */
192
	public function __toString() {
193
		return $this->serialization;
194
	}
195
196
	/**
197
	 *
198
	 * @since 0.5
199
	 *
200
	 * @param mixed $target
201
	 *
202
	 * @return bool
203
	 */
204
	public function equals( $target ) {
205
		if ( $this === $target ) {
206
			return true;
207
		}
208
209
		return $target instanceof self
210
			&& $target->serialization === $this->serialization;
211
	}
212
213
	/**
214
	 * Returns a pair (repository name, local part of ID) from the given ID serialization.
215
	 * Note: this does not perform any validation of the given input. Calling code should take
216
	 * care of this!
217
	 *
218
	 * @since 7.3
219
	 *
220
	 * @param string $serialization
221
	 *
222
	 * @return string[] Array of form [ string $repositoryName, string $localPart ]
223
	 */
224
	protected static function extractRepositoryNameAndLocalPart( $serialization ) {
225
		return array_pad( explode( ':', $serialization, 2 ), -2, '' );
226
	}
227
228
}
229