Passed
Push — micro-opti-entityid-stuffz ( 9b6047...d4178e )
by Leszek
02:46
created

EntityId::getEntityType()

Size

Total Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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