Completed
Push — isLocal ( 981ca0 )
by no
03:13
created

EntityId::isLocal()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
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
	const PATTERN = '/^:?(\w+:)*[^:]+\z/';
20
21
	/**
22
	 * @since 6.2
23
	 *
24
	 * @param string $serialization
25
	 */
26
	public function __construct( $serialization ) {
27
		self::assertValidSerialization( $serialization );
28
		$this->serialization = self::normalizeIdSerialization( $serialization );
29
	}
30
31
	private static function assertValidSerialization( $serialization ) {
32
		if ( !is_string( $serialization ) ) {
33
			throw new InvalidArgumentException( '$serialization must be a string' );
34
		}
35
36
		if ( $serialization === '' ) {
37
			throw new InvalidArgumentException( '$serialization must not be an empty string' );
38
		}
39
40
		if ( !preg_match( self::PATTERN, $serialization ) ) {
41
			throw new InvalidArgumentException( '$serialization must match ' . self::PATTERN );
42
		}
43
	}
44
45
	/**
46
	 * @return string
47
	 */
48
	public abstract function getEntityType();
49
50
	/**
51
	 * @return string
52
	 */
53
	public function getSerialization() {
54
		return $this->serialization;
55
	}
56
57
	/**
58
	 * Returns an array with 3 elements: the foreign repository name as the first element, the local ID as the last
59
	 * element and everything that is in between as the second element.
60
	 *
61
	 * self::joinSerialization can be used to restore the original serialization from the parts
62
	 * returned.
63
	 *
64
	 * @since 6.2
65
	 *
66
	 * @param string $serialization
67
	 * @return string[] Array containing the serialization split into 3 parts.
68
	 */
69
	public static function splitSerialization( $serialization ) {
70
		self::assertValidSerialization( $serialization );
71
72
		$parts = explode( ':', self::normalizeIdSerialization( $serialization ) );
73
		$localPart = array_pop( $parts );
74
		$repoName = array_shift( $parts );
75
		$prefixRemainder = implode( ':', $parts );
76
77
		return [
78
			is_string( $repoName ) ? $repoName : '',
79
			$prefixRemainder,
80
			$localPart
81
		];
82
	}
83
84
	/**
85
	 * Builds an ID serialization from the parts returned by self::splitSerialization.
86
	 *
87
	 * @since 6.2
88
	 *
89
	 * @param string[] $parts
90
	 * @return string
91
	 *
92
	 * @throws InvalidArgumentException
93
	 */
94
	public static function joinSerialization( array $parts ) {
95
		if ( end( $parts ) === '' ) {
96
			throw new InvalidArgumentException( 'The last element of $parts must not be empty.' );
97
		}
98
99
		return implode(
100
			':',
101
			array_filter( $parts, function( $part ) {
102
				return $part !== '';
103
			} )
104
		);
105
	}
106
107
	/**
108
	 * Returns an empty string for IDs that are known to be local, or a repository name for prefixed
109
	 * IDs. For chained prefixes (e.g. foo:bar:Q42) it will return only the first prefix.
110
	 *
111
	 * @since 6.2
112
	 *
113
	 * @return string
114
	 */
115
	public function getRepositoryName() {
116
		$parts = self::splitSerialization( $this->serialization );
117
118
		return $parts[0];
119
	}
120
121
	/**
122
	 * FIXME: This refers to a concept called "local" that includes prefixes!
123
	 *
124
	 * Returns the serialization without the first repository prefix.
125
	 *
126
	 * @since 6.2
127
	 *
128
	 * @return string
129
	 */
130
	public function getLocalPart() {
131
		$parts = self::splitSerialization( $this->serialization );
132
133
		return self::joinSerialization( [ '', $parts[1], $parts[2] ] );
134
	}
135
136
	/**
137
	 * Returns true if the ID does not have any prefix and is therefore guaranteed to be local. This
138
	 * is the same as checking if getRepositoryName() returns a empty string. Note that the inverse
139
	 * is not necessarily true! A prefixed ID may still refer to a local entity when resolved,
140
	 * either when prefixed with the own repository name, or when prefixed with multiple repository
141
	 * names that point back to the own repository.
142
	 *
143
	 * @since 7.0
144
	 *
145
	 * @return bool
146
	 */
147
	public function isLocal() {
148
		// Not actually using getRepositoryName() for performance reasons
149
		return strpos( $this->serialization, ':' ) === false;
150
	}
151
152
	/**
153
	 * @param string $id
154
	 * @return string
155
	 */
156
	private static function normalizeIdSerialization( $id ) {
157
		return ltrim( $id, ':' );
158
	}
159
160
	/**
161
	 * This is a human readable representation of the EntityId.
162
	 * This format is allowed to change and should therefore not
163
	 * be relied upon to be stable.
164
	 *
165
	 * @return string
166
	 */
167
	public function __toString() {
168
		return $this->serialization;
169
	}
170
171
	/**
172
	 * @see Comparable::equals
173
	 *
174
	 * @since 0.5
175
	 *
176
	 * @param mixed $target
177
	 *
178
	 * @return bool
179
	 */
180
	public function equals( $target ) {
181
		if ( $this === $target ) {
182
			return true;
183
		}
184
185
		return $target instanceof self
186
			&& $target->serialization === $this->serialization;
187
	}
188
189
}
190