Test Failed
Push — master ( 4c6731...e27b5b )
by Sam
03:04 queued 17s
created
examples/custom_entity_types.php 1 patch
Indentation   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -13,29 +13,29 @@  discard block
 block discarded – undo
13 13
  * @link https://www.wikidata.org/wiki/Wikidata:WikiProject_Railways
14 14
  */
15 15
 class RailwayStation extends \Samwilson\SimpleWikidata\Item {
16
-	// @codingStandardsIgnoreEnd
17
-	/**
18
-	 * Every subclass of Item should define its 'instance of' ID.
19
-	 */
20
-	const INSTANCE_OF = 'Q55488';
21
-	/**
22
-	 * It can then contain any type-specific methods that are required.
23
-	 * @return RailwayStation[]
24
-	 */
25
-	public function hasAdjacentStations() {
26
-		return $this->getPropertyOfTypeItem( 'P197' );
27
-	}
28
-	/**
29
-	 * Including queries.
30
-	 * @return RailwayStation[]
31
-	 */
32
-	public function isAdjacentTo() {
33
-		$sparql = "SELECT ?item WHERE { ?item wdt:P197 wd:" . $this->getId() . " }";
34
-		$query = new \Samwilson\SimpleWikidata\Query( $sparql, $this->lang, $this->cache );
35
-		// Each query result will also be a RailwayStation
36
-		// (if they're correctly recorded as such on Wikidata).
37
-		return $query->getItems();
38
-	}
16
+    // @codingStandardsIgnoreEnd
17
+    /**
18
+     * Every subclass of Item should define its 'instance of' ID.
19
+     */
20
+    const INSTANCE_OF = 'Q55488';
21
+    /**
22
+     * It can then contain any type-specific methods that are required.
23
+     * @return RailwayStation[]
24
+     */
25
+    public function hasAdjacentStations() {
26
+        return $this->getPropertyOfTypeItem( 'P197' );
27
+    }
28
+    /**
29
+     * Including queries.
30
+     * @return RailwayStation[]
31
+     */
32
+    public function isAdjacentTo() {
33
+        $sparql = "SELECT ?item WHERE { ?item wdt:P197 wd:" . $this->getId() . " }";
34
+        $query = new \Samwilson\SimpleWikidata\Query( $sparql, $this->lang, $this->cache );
35
+        // Each query result will also be a RailwayStation
36
+        // (if they're correctly recorded as such on Wikidata).
37
+        return $query->getItems();
38
+    }
39 39
 }
40 40
 
41 41
 // Then the class must register itself.
@@ -45,5 +45,5 @@  discard block
 block discarded – undo
45 45
 /** @var RailwayStation $eustonStation */
46 46
 $eustonStation = \Samwilson\SimpleWikidata\Item::factory( 'Q800751', 'en', $cache );
47 47
 echo $eustonStation->getLabel()
48
-	. " has " . count( $eustonStation->hasAdjacentStations() ) . " adjacent stations"
49
-	. " and is adjacent to " . count( $eustonStation->isAdjacentTo() ) . " stations.\n";
48
+    . " has " . count( $eustonStation->hasAdjacentStations() ) . " adjacent stations"
49
+    . " and is adjacent to " . count( $eustonStation->isAdjacentTo() ) . " stations.\n";
Please login to merge, or discard this patch.
src/Item.php 1 patch
Indentation   +445 added lines, -445 removed lines patch added patch discarded remove patch
@@ -12,179 +12,179 @@  discard block
 block discarded – undo
12 12
 
13 13
 class Item {
14 14
 
15
-	/** @var string|bool */
16
-	const INSTANCE_OF = false;
17
-
18
-	const PROP_INSTANCE_OF = 'P31';
19
-	const PROP_TITLE = 'P1476';
20
-	const PROP_IMAGE = 'P18';
21
-	const PROP_AUTHOR = 'P50';
22
-
23
-	/** @var string[] List of Q-numbers of registered classes. */
24
-	protected static $registeredClasses = [];
25
-
26
-	/** @var string */
27
-	protected $id;
28
-
29
-	/** @var MediawikiApi */
30
-	protected $wdApi;
31
-
32
-	/** @var string */
33
-	protected $lang;
34
-
35
-	/** @var CacheItemPoolInterface */
36
-	protected $cache;
37
-
38
-	/** @var string The base URL of Wikidata, with trailing slash. */
39
-	protected $wikidataUrlBase = 'https://www.wikidata.org/wiki/';
40
-
41
-	private function __construct( $id, $lang, CacheItemPoolInterface $cache ) {
42
-		if ( !is_string( $id ) || preg_match( '/[QP][0-9]*/i', $id ) !== 1 ) {
43
-			throw new Exception( "Not a valid ID: " . var_export( $id, true ) );
44
-		}
45
-		$this->id = $id;
46
-		$this->wdApi = new MediawikiApi( 'https://www.wikidata.org/w/api.php' );
47
-		$this->entities = [];
48
-		$this->lang = $lang;
49
-		$this->cache = $cache;
50
-	}
51
-
52
-	/**
53
-	 * Create a new Item object with class based on the item's 'instance of' statement.
54
-	 *
55
-	 * @param string $id The item ID (Q-number).
56
-	 * @param string $lang The language code.
57
-	 * @param CacheItemPoolInterface $cache The cache to use.
58
-	 * @return Item
59
-	 */
60
-	public static function factory( $id, $lang, CacheItemPoolInterface $cache ) {
61
-		$item = new Item( $id, $lang, $cache );
62
-		foreach ( $item->getPropertyOfTypeItem( self::PROP_INSTANCE_OF ) as $instanceOf ) {
63
-			// Try to find a class matching the registered 'instance of'.
64
-			foreach ( static::$registeredClasses as $classId => $className ) {
65
-				// If this 'instance of' is registered, use it.
66
-				if ( $classId === $instanceOf->getItem()->getId() ) {
67
-					// This won't re-request the metadata, because that's cached.
68
-					return new $className( $id, $lang, $cache );
69
-				}
70
-			}
71
-		}
72
-
73
-		// If we're here, just leave it as a basic Item.
74
-		$item->setCache( $cache );
75
-		return $item;
76
-	}
77
-
78
-	/**
79
-	 * Register this class as a candidate for being created by Item::factory.
80
-	 * Should only be called on subclasses of Item.
81
-	 * @throws Exception if called on Item or the registering class does not have INSTANCE_OF set.
82
-	 */
83
-	public static function register() {
84
-		if ( static::class === self::class ) {
85
-			throw new Exception( __METHOD__ . ' should only be called on subclasses of Item' );
86
-		}
87
-		if ( !static::INSTANCE_OF ) {
88
-			throw new Exception( 'Please set INSTANCE_OF for ' . static::class );
89
-		}
90
-		static::$registeredClasses[ static::INSTANCE_OF ] = static::class;
91
-	}
92
-
93
-	/**
94
-	 * @param CacheItemPoolInterface $cache The cache to use.
95
-	 */
96
-	public function setCache( CacheItemPoolInterface $cache ) {
97
-		$this->cache = $cache;
98
-	}
99
-
100
-	/**
101
-	 * Get the ID (Q-number) of this item.
102
-	 * @return string|bool The ID or false if it couldn't be determined.
103
-	 */
104
-	public function getId() {
105
-		$entity = $this->getEntity( $this->id );
106
-		return isset( $entity['id'] ) ? $entity['id'] : false;
107
-	}
108
-
109
-	/**
110
-	 * Get this item's label.
111
-	 * @return string
112
-	 */
113
-	public function getLabel() {
114
-		$entity = $this->getEntity( $this->id );
115
-		if ( ! empty( $entity['labels'][ $this->lang ]['value'] ) ) {
116
-			// Use the label if there is one.
117
-			return $entity['labels'][ $this->lang ]['value'];
118
-		}
119
-		// Or just use the ID.
120
-		return $entity['id'];
121
-	}
122
-
123
-	/**
124
-	 * @return string The Wikidata.org URL for this item.
125
-	 */
126
-	public function getWikidataUrl() {
127
-		return $this->wikidataUrlBase.$this->id;
128
-	}
129
-
130
-	/**
131
-	 * Wikiprojects list their properties like this:
132
-	 *
133
-	 *     {{List of properties/Header}}
134
-	 *     {{List of properties/Row|id=31|example-subject=Q923767|example-object=Q3331189}}
135
-	 *     </table>
136
-	 *
137
-	 * @param string $wikiProject The name of the WikiProject (must exist as a Wikidata page e.g.
138
-	 * [[Wikidata:$wikiProject]]).
139
-	 * @param string $type
140
-	 * @return array
141
-	 */
142
-	public function getStandardProperties( $wikiProject = 'WikiProject_Books', $type = 'work' ) {
143
-		if ( $type !== 'work' ) {
144
-			$type = 'edition';
145
-		}
146
-		$cacheKey = $type . '_item_property_IDs';
147
-		if ( $this->cache->hasItem( $cacheKey ) ) {
148
-			$propIds = $this->cache->getItem( $cacheKey )->get();
149
-		} else {
150
-			$domCrawler = new Crawler();
151
-			$wikiProjectUrl = 'https://www.wikidata.org/wiki/Wikidata:' . $wikiProject;
152
-			$domCrawler->addHtmlContent( file_get_contents( $wikiProjectUrl ) );
153
-			$propAncors = "//h3/span[@id='" . ucfirst( $type ) . "_item_properties']/../following-sibling::table[1]//td[2]/a";
154
-			$propCells = $domCrawler->filterXPath( $propAncors );
155
-			$propIds = [];
156
-			$propCells->each( function ( Crawler $node, $i ) use ( &$propIds ) {
157
-				$propId = $node->text();
158
-				$propIds[] = $propId;
159
-			} );
160
-			$cacheItem = $this->cache->getItem( $cacheKey )
161
-				->expiresAfter( new DateInterval( 'PT1H' ) )
162
-				->set( $propIds );
163
-			$this->cache->save( $cacheItem );
164
-		}
165
-		$workProperties = [];
166
-		foreach ( $propIds as $propId ) {
167
-			$workProperties[] = self::factory( $propId, $this->lang, $this->cache );
168
-		}
169
-
170
-		return $workProperties;
171
-	}
172
-
173
-	/**
174
-	 * @param string $propertyId
175
-	 * @return bool|Time[]
176
-	 */
177
-	public function getPropertyOfTypeTime( $propertyId ) {
178
-		$times = [];
179
-		$entity = $this->getEntity();
180
-		if ( !isset( $entity['claims'][$propertyId] ) ) {
181
-			// No statements for this property.
182
-			return $times;
183
-		}
184
-		// print_r($entity['claims'][$propertyId]);exit();
185
-		foreach ( $entity['claims'][$propertyId] as $claim ) {
186
-			// print_r($claim);
187
-			$times[] = new Time( $claim, $this->lang, $this->cache );
15
+    /** @var string|bool */
16
+    const INSTANCE_OF = false;
17
+
18
+    const PROP_INSTANCE_OF = 'P31';
19
+    const PROP_TITLE = 'P1476';
20
+    const PROP_IMAGE = 'P18';
21
+    const PROP_AUTHOR = 'P50';
22
+
23
+    /** @var string[] List of Q-numbers of registered classes. */
24
+    protected static $registeredClasses = [];
25
+
26
+    /** @var string */
27
+    protected $id;
28
+
29
+    /** @var MediawikiApi */
30
+    protected $wdApi;
31
+
32
+    /** @var string */
33
+    protected $lang;
34
+
35
+    /** @var CacheItemPoolInterface */
36
+    protected $cache;
37
+
38
+    /** @var string The base URL of Wikidata, with trailing slash. */
39
+    protected $wikidataUrlBase = 'https://www.wikidata.org/wiki/';
40
+
41
+    private function __construct( $id, $lang, CacheItemPoolInterface $cache ) {
42
+        if ( !is_string( $id ) || preg_match( '/[QP][0-9]*/i', $id ) !== 1 ) {
43
+            throw new Exception( "Not a valid ID: " . var_export( $id, true ) );
44
+        }
45
+        $this->id = $id;
46
+        $this->wdApi = new MediawikiApi( 'https://www.wikidata.org/w/api.php' );
47
+        $this->entities = [];
48
+        $this->lang = $lang;
49
+        $this->cache = $cache;
50
+    }
51
+
52
+    /**
53
+     * Create a new Item object with class based on the item's 'instance of' statement.
54
+     *
55
+     * @param string $id The item ID (Q-number).
56
+     * @param string $lang The language code.
57
+     * @param CacheItemPoolInterface $cache The cache to use.
58
+     * @return Item
59
+     */
60
+    public static function factory( $id, $lang, CacheItemPoolInterface $cache ) {
61
+        $item = new Item( $id, $lang, $cache );
62
+        foreach ( $item->getPropertyOfTypeItem( self::PROP_INSTANCE_OF ) as $instanceOf ) {
63
+            // Try to find a class matching the registered 'instance of'.
64
+            foreach ( static::$registeredClasses as $classId => $className ) {
65
+                // If this 'instance of' is registered, use it.
66
+                if ( $classId === $instanceOf->getItem()->getId() ) {
67
+                    // This won't re-request the metadata, because that's cached.
68
+                    return new $className( $id, $lang, $cache );
69
+                }
70
+            }
71
+        }
72
+
73
+        // If we're here, just leave it as a basic Item.
74
+        $item->setCache( $cache );
75
+        return $item;
76
+    }
77
+
78
+    /**
79
+     * Register this class as a candidate for being created by Item::factory.
80
+     * Should only be called on subclasses of Item.
81
+     * @throws Exception if called on Item or the registering class does not have INSTANCE_OF set.
82
+     */
83
+    public static function register() {
84
+        if ( static::class === self::class ) {
85
+            throw new Exception( __METHOD__ . ' should only be called on subclasses of Item' );
86
+        }
87
+        if ( !static::INSTANCE_OF ) {
88
+            throw new Exception( 'Please set INSTANCE_OF for ' . static::class );
89
+        }
90
+        static::$registeredClasses[ static::INSTANCE_OF ] = static::class;
91
+    }
92
+
93
+    /**
94
+     * @param CacheItemPoolInterface $cache The cache to use.
95
+     */
96
+    public function setCache( CacheItemPoolInterface $cache ) {
97
+        $this->cache = $cache;
98
+    }
99
+
100
+    /**
101
+     * Get the ID (Q-number) of this item.
102
+     * @return string|bool The ID or false if it couldn't be determined.
103
+     */
104
+    public function getId() {
105
+        $entity = $this->getEntity( $this->id );
106
+        return isset( $entity['id'] ) ? $entity['id'] : false;
107
+    }
108
+
109
+    /**
110
+     * Get this item's label.
111
+     * @return string
112
+     */
113
+    public function getLabel() {
114
+        $entity = $this->getEntity( $this->id );
115
+        if ( ! empty( $entity['labels'][ $this->lang ]['value'] ) ) {
116
+            // Use the label if there is one.
117
+            return $entity['labels'][ $this->lang ]['value'];
118
+        }
119
+        // Or just use the ID.
120
+        return $entity['id'];
121
+    }
122
+
123
+    /**
124
+     * @return string The Wikidata.org URL for this item.
125
+     */
126
+    public function getWikidataUrl() {
127
+        return $this->wikidataUrlBase.$this->id;
128
+    }
129
+
130
+    /**
131
+     * Wikiprojects list their properties like this:
132
+     *
133
+     *     {{List of properties/Header}}
134
+     *     {{List of properties/Row|id=31|example-subject=Q923767|example-object=Q3331189}}
135
+     *     </table>
136
+     *
137
+     * @param string $wikiProject The name of the WikiProject (must exist as a Wikidata page e.g.
138
+     * [[Wikidata:$wikiProject]]).
139
+     * @param string $type
140
+     * @return array
141
+     */
142
+    public function getStandardProperties( $wikiProject = 'WikiProject_Books', $type = 'work' ) {
143
+        if ( $type !== 'work' ) {
144
+            $type = 'edition';
145
+        }
146
+        $cacheKey = $type . '_item_property_IDs';
147
+        if ( $this->cache->hasItem( $cacheKey ) ) {
148
+            $propIds = $this->cache->getItem( $cacheKey )->get();
149
+        } else {
150
+            $domCrawler = new Crawler();
151
+            $wikiProjectUrl = 'https://www.wikidata.org/wiki/Wikidata:' . $wikiProject;
152
+            $domCrawler->addHtmlContent( file_get_contents( $wikiProjectUrl ) );
153
+            $propAncors = "//h3/span[@id='" . ucfirst( $type ) . "_item_properties']/../following-sibling::table[1]//td[2]/a";
154
+            $propCells = $domCrawler->filterXPath( $propAncors );
155
+            $propIds = [];
156
+            $propCells->each( function ( Crawler $node, $i ) use ( &$propIds ) {
157
+                $propId = $node->text();
158
+                $propIds[] = $propId;
159
+            } );
160
+            $cacheItem = $this->cache->getItem( $cacheKey )
161
+                ->expiresAfter( new DateInterval( 'PT1H' ) )
162
+                ->set( $propIds );
163
+            $this->cache->save( $cacheItem );
164
+        }
165
+        $workProperties = [];
166
+        foreach ( $propIds as $propId ) {
167
+            $workProperties[] = self::factory( $propId, $this->lang, $this->cache );
168
+        }
169
+
170
+        return $workProperties;
171
+    }
172
+
173
+    /**
174
+     * @param string $propertyId
175
+     * @return bool|Time[]
176
+     */
177
+    public function getPropertyOfTypeTime( $propertyId ) {
178
+        $times = [];
179
+        $entity = $this->getEntity();
180
+        if ( !isset( $entity['claims'][$propertyId] ) ) {
181
+            // No statements for this property.
182
+            return $times;
183
+        }
184
+        // print_r($entity['claims'][$propertyId]);exit();
185
+        foreach ( $entity['claims'][$propertyId] as $claim ) {
186
+            // print_r($claim);
187
+            $times[] = new Time( $claim, $this->lang, $this->cache );
188 188
 //
189 189
 // $timeValue = $claim['datavalue']['value']['time'];
190 190
 // // Ugly workaround for imprecise dates. :-(
@@ -194,276 +194,276 @@  discard block
 block discarded – undo
194 194
 // }
195 195
 // $time = strtotime($timeValue);
196 196
 // return date($dateFormat, $time);
197
-			// }
198
-		}
199
-		return $times;
200
-	}
201
-
202
-	/**
203
-	 * Get the Item that is referred to by the specified item's property.
204
-	 *
205
-	 * @param string $propertyId
206
-	 *
207
-	 * @return \Samwilson\SimpleWikidata\Properties\Item[]
208
-	 */
209
-	public function getPropertyOfTypeItem( $propertyId ) {
210
-		$entity = $this->getEntity( $this->id );
211
-		if ( !isset( $entity['claims'][$propertyId] ) ) {
212
-			return [];
213
-		}
214
-		$items = [];
215
-		foreach ( $entity['claims'][$propertyId] as $claim ) {
216
-			$items[] = new Properties\Item( $claim, $this->lang, $this->cache );
217
-		}
218
-
219
-		return $items;
220
-	}
221
-
222
-	public function setPropertyOfTypeItem( $property, $itemId ) {
223
-		$itemIdNumeric = substr( $itemId, 1 );
224
-
225
-		// First see if this property already exists, and that it is different from what's being set.
226
-		$entity = $this->getEntity( $this->id );
227
-		if ( !empty( $entity['claims'][$property] ) ) {
228
-			// Get the first claim, and update it if necessary.
229
-			$claim = array_shift( $entity['claims'][$property] );
230
-			if ( $claim['mainsnak']['datavalue']['value']['id'] == $itemId ) {
231
-				// Already is the required value, no need to change.
232
-				return;
233
-			}
234
-			$claim['mainsnak']['datavalue']['value']['id'] = $itemId;
235
-			$claim['mainsnak']['datavalue']['value']['numeric-id'] = $itemIdNumeric;
236
-			$apiParams = [
237
-				'action' => 'wbsetclaim',
238
-				'claim' => json_encode( $claim ),
239
-			];
240
-		}
241
-
242
-		// If no claim was found (and modified) above, create a new claim.
243
-		if ( !isset( $apiParams ) ) {
244
-			$apiParams = [
245
-				'action' => 'wbcreateclaim',
246
-				'entity' => $this->getId(),
247
-				'property' => $property,
248
-				'snaktype' => 'value',
249
-				'value' => json_encode( [ 'entity-type' => 'item', 'numeric-id' => $itemIdNumeric ] ),
250
-			];
251
-		}
252
-
253
-		// @TODO Save the property.
254
-
255
-		// Clear the cache.
256
-		$this->cache->deleteItem( $this->getEntityCacheKey( $this->id ) );
257
-	}
258
-
259
-	public function getPropertyOfTypeUrl( $entityId, $propertyId ) {
260
-		$entity = $this->getEntity( $entityId );
261
-		if ( !isset( $entity['claims'][$propertyId] ) ) {
262
-			return false;
263
-		}
264
-		$urls = [];
265
-		foreach ( $entity['claims'][$propertyId] as $claim ) {
266
-			$urls[] = $claim['mainsnak']['datavalue']['value'];
267
-		}
268
-
269
-		return $urls;
270
-	}
271
-
272
-	public function getPropertyOfTypeExternalIdentifier( $entityId, $propertyId ) {
273
-		$entity = $this->getEntity( $entityId );
274
-		if ( !isset( $entity['claims'][$propertyId] ) ) {
275
-			return false;
276
-		}
277
-		$idents = [];
278
-		foreach ( $entity['claims'][$propertyId] as $claim ) {
279
-			$qualifiers = [];
280
-			if ( !isset( $claim['qualifiers'] ) ) {
281
-				continue;
282
-			}
283
-			foreach ( $claim['qualifiers'] as $qualsInfo ) {
284
-				foreach ( $qualsInfo as $qualInfo ) {
285
-					$qualProp = self::factory( $qualInfo['property'], $this->lang, $this->cache );
286
-					$propLabel = $qualProp->getLabel();
287
-					if ( !isset( $qualifiers[$propLabel] ) ) {
288
-						$qualifiers[$propLabel] = [];
289
-					}
290
-					$qualifiers[$propLabel][] = $qualInfo['datavalue']['value'];
291
-				}
292
-			}
293
-			$idents[] = [
294
-				'qualifiers' => $qualifiers,
295
-				'value' => $claim['mainsnak']['datavalue']['value'],
296
-			];
297
-		}
298
-
299
-		return $idents;
300
-	}
301
-
302
-	/**
303
-	 * Get a single-valued text property.
304
-	 * @param string $property One of the PROP_* constants.
305
-	 * @return string|bool The value, or false if it can't be found.
306
-	 */
307
-	public function getPropertyOfTypeText( $property ) {
308
-		$entity = $this->getEntity( $this->id );
309
-		if ( isset( $entity['claims'][$property] ) ) {
310
-			// Use the first title.
311
-			foreach ( $entity['claims'][$property] as $t ) {
312
-				if ( !isset( $t['mainsnak']['datavalue']['value']['language'] ) ) {
313
-					var_dump( $t['mainsnak']['datavalue']['value'] );
314
-					exit();
315
-				}
316
-				if ( $t['mainsnak']['datavalue']['value']['language'] == $this->lang
317
-					&& !empty( $t['mainsnak']['datavalue']['value']['text'] )
318
-				) {
319
-					return $t['mainsnak']['datavalue']['value']['text'];
320
-				}
321
-			}
322
-		}
323
-		return false;
324
-	}
325
-
326
-	/**
327
-	 * Literal data field for a quantity that relates to some kind of well-defined unit. The actual unit goes in the data values that is entered.
328
-	 *   - amount – implicit part of the string (mapping of unit prefix is unclear)
329
-	 *   - unit – implicit part of the string that defaults to "1" (mapping to standardizing body is unclear)
330
-	 *   - upperbound - quantity's upper bound
331
-	 *   - lowerbound - quantity's lower bound
332
-	 * @param $property
333
-	 * @return mixed[]|bool If it's not false it's an array with 'amount', 'unit', etc.
334
-	 */
335
-	public function getPropertyOfTypeQuantity( $property ) {
336
-		$quantities = [];
337
-		$entity = $this->getEntity( $this->id );
338
-		if ( !isset( $entity['claims'][$property] ) ) {
339
-			return false;
340
-		}
341
-		foreach ( $entity['claims'][$property] as $t ) {
342
-			$quantity = $t['mainsnak']['datavalue']['value'];
343
-			$unitId = substr( $quantity['unit'], strlen( $this->wikidataUrlBase ) + 1 );
344
-			$quantity['unit'] = self::factory( $unitId, $this->lang, $this->cache );
345
-			$quantities[] = $quantity;
346
-		}
347
-		return $quantities;
348
-	}
349
-
350
-	/**
351
-	 * Set a single-valued text property.
352
-	 * @param string $property One of the PROP_* constants.
353
-	 * @param string $value The value.
354
-	 */
355
-	public function setPropertyOfTypeText( $property, $value ) {
356
-		// First see if this property already exists, and that it is different from what's being set.
357
-		$entity = $this->getEntity( $this->id );
358
-		if ( !empty( $entity['claims'][$property] ) ) {
359
-			// Find this language's claim (if there is one).
360
-			foreach ( $entity['claims'][$property] as $claim ) {
361
-				if ( $claim['mainsnak']['datavalue']['value']['language'] == $this->lang ) {
362
-					// Modify this claim's text value.
363
-					$titleClaim = $claim;
364
-					$titleClaim['mainsnak']['datavalue']['value']['text'] = $value;
365
-					$setTitleParams = [
366
-						'action' => 'wbsetclaim',
367
-						'claim' => \GuzzleHttp\json_encode( $titleClaim ),
368
-					];
369
-					continue;
370
-				}
371
-			}
372
-		}
373
-
374
-		// If no claim was found (and modified) above, create a new claim.
375
-		if ( !isset( $setTitleParams ) ) {
376
-			$setTitleParams = [
377
-				'action' => 'wbcreateclaim',
378
-				'entity' => $this->getId(),
379
-				'property' => $property,
380
-				'snaktype' => 'value',
381
-				'value' => \GuzzleHttp\json_encode( [ 'text' => $value, 'language' => $this->lang ] ),
382
-			];
383
-		}
384
-
385
-		// Save the property.
386
-		$wdWpOauth = new WdWpOauth();
387
-		$wdWpOauth->makeCall( $setTitleParams, true );
388
-
389
-		// Clear the cache.
390
-		$this->cache->deleteItem( $this->getEntityCacheKey( $this->id ) );
391
-	}
392
-
393
-	/**
394
-	 * Does this item exist?
395
-	 * @return bool
396
-	 */
397
-	public function exists() {
398
-		return $this->getId() !== false;
399
-	}
400
-
401
-	public function getWikipediaIntro() {
402
-		$cacheKey = 'wikipedia-intro-' . $this->id . $this->lang;
403
-		if ( $this->cache->hasItem( $cacheKey ) ) {
404
-			return $this->cache->getItem( $cacheKey )->get();
405
-		}
406
-		$entity = $this->getEntity( $this->id );
407
-		if ( !isset( $entity['sitelinks'] ) ) {
408
-			return [];
409
-		}
410
-		foreach ( $entity['sitelinks'] as $sitelink ) {
411
-			if ( $sitelink['site'] == $this->lang . 'wiki' ) {
412
-				$api = new MediawikiApi( 'https://' . $this->lang . '.wikipedia.org/w/api.php' );
413
-				$req = new SimpleRequest( 'query', [
414
-					'prop' => 'extracts',
415
-					'exintro' => true,
416
-					'titles' => $sitelink['title'],
417
-				] );
418
-				$response = $api->getRequest( $req );
419
-				$page = array_shift( $response['query']['pages'] );
420
-				$out = [
421
-					'title' => $page['title'],
422
-					'html' => $page['extract'],
423
-				];
424
-				$cacheItem = $this->cache->getItem( $cacheKey )
425
-					->expiresAfter( new DateInterval( 'P1D' ) )
426
-					->set( $out );
427
-				$this->cache->save( $cacheItem );
428
-
429
-				return $out;
430
-			}
431
-		}
432
-
433
-		return [];
434
-	}
435
-
436
-	/**
437
-	 * Get the raw entity data from the 'wbgetentities' API call.
438
-	 * @param string $id The Q-number.
439
-	 * @param bool $ignoreCache
440
-	 * @return array|bool
441
-	 */
442
-	public function getEntity( $id = null, $ignoreCache = false ) {
443
-		$idActual = $id ?: $this->id;
444
-		$cacheKey = $this->getEntityCacheKey( $idActual );
445
-		if ( !$ignoreCache && $this->cache->hasItem( $cacheKey ) ) {
446
-			return $this->cache->getItem( $cacheKey )->get();
447
-		}
448
-		$metadataRequest = new SimpleRequest( 'wbgetentities', [ 'ids' => $idActual ] );
449
-		$itemResult = $this->wdApi->getRequest( $metadataRequest );
450
-		if ( !isset( $itemResult['success'] ) || !isset( $itemResult['entities'][$id] ) ) {
451
-			return false;
452
-		}
453
-		$metadata = $itemResult['entities'][$idActual];
454
-		$cacheItem = $this->cache->getItem( $cacheKey )
455
-			->expiresAfter( new DateInterval( 'PT10M' ) )
456
-			->set( $metadata );
457
-		$this->cache->save( $cacheItem );
458
-		return $metadata;
459
-	}
460
-
461
-	/**
462
-	 * @param $id
463
-	 *
464
-	 * @return string
465
-	 */
466
-	protected function getEntityCacheKey( $id ) {
467
-		return 'entities' . $id;
468
-	}
197
+            // }
198
+        }
199
+        return $times;
200
+    }
201
+
202
+    /**
203
+     * Get the Item that is referred to by the specified item's property.
204
+     *
205
+     * @param string $propertyId
206
+     *
207
+     * @return \Samwilson\SimpleWikidata\Properties\Item[]
208
+     */
209
+    public function getPropertyOfTypeItem( $propertyId ) {
210
+        $entity = $this->getEntity( $this->id );
211
+        if ( !isset( $entity['claims'][$propertyId] ) ) {
212
+            return [];
213
+        }
214
+        $items = [];
215
+        foreach ( $entity['claims'][$propertyId] as $claim ) {
216
+            $items[] = new Properties\Item( $claim, $this->lang, $this->cache );
217
+        }
218
+
219
+        return $items;
220
+    }
221
+
222
+    public function setPropertyOfTypeItem( $property, $itemId ) {
223
+        $itemIdNumeric = substr( $itemId, 1 );
224
+
225
+        // First see if this property already exists, and that it is different from what's being set.
226
+        $entity = $this->getEntity( $this->id );
227
+        if ( !empty( $entity['claims'][$property] ) ) {
228
+            // Get the first claim, and update it if necessary.
229
+            $claim = array_shift( $entity['claims'][$property] );
230
+            if ( $claim['mainsnak']['datavalue']['value']['id'] == $itemId ) {
231
+                // Already is the required value, no need to change.
232
+                return;
233
+            }
234
+            $claim['mainsnak']['datavalue']['value']['id'] = $itemId;
235
+            $claim['mainsnak']['datavalue']['value']['numeric-id'] = $itemIdNumeric;
236
+            $apiParams = [
237
+                'action' => 'wbsetclaim',
238
+                'claim' => json_encode( $claim ),
239
+            ];
240
+        }
241
+
242
+        // If no claim was found (and modified) above, create a new claim.
243
+        if ( !isset( $apiParams ) ) {
244
+            $apiParams = [
245
+                'action' => 'wbcreateclaim',
246
+                'entity' => $this->getId(),
247
+                'property' => $property,
248
+                'snaktype' => 'value',
249
+                'value' => json_encode( [ 'entity-type' => 'item', 'numeric-id' => $itemIdNumeric ] ),
250
+            ];
251
+        }
252
+
253
+        // @TODO Save the property.
254
+
255
+        // Clear the cache.
256
+        $this->cache->deleteItem( $this->getEntityCacheKey( $this->id ) );
257
+    }
258
+
259
+    public function getPropertyOfTypeUrl( $entityId, $propertyId ) {
260
+        $entity = $this->getEntity( $entityId );
261
+        if ( !isset( $entity['claims'][$propertyId] ) ) {
262
+            return false;
263
+        }
264
+        $urls = [];
265
+        foreach ( $entity['claims'][$propertyId] as $claim ) {
266
+            $urls[] = $claim['mainsnak']['datavalue']['value'];
267
+        }
268
+
269
+        return $urls;
270
+    }
271
+
272
+    public function getPropertyOfTypeExternalIdentifier( $entityId, $propertyId ) {
273
+        $entity = $this->getEntity( $entityId );
274
+        if ( !isset( $entity['claims'][$propertyId] ) ) {
275
+            return false;
276
+        }
277
+        $idents = [];
278
+        foreach ( $entity['claims'][$propertyId] as $claim ) {
279
+            $qualifiers = [];
280
+            if ( !isset( $claim['qualifiers'] ) ) {
281
+                continue;
282
+            }
283
+            foreach ( $claim['qualifiers'] as $qualsInfo ) {
284
+                foreach ( $qualsInfo as $qualInfo ) {
285
+                    $qualProp = self::factory( $qualInfo['property'], $this->lang, $this->cache );
286
+                    $propLabel = $qualProp->getLabel();
287
+                    if ( !isset( $qualifiers[$propLabel] ) ) {
288
+                        $qualifiers[$propLabel] = [];
289
+                    }
290
+                    $qualifiers[$propLabel][] = $qualInfo['datavalue']['value'];
291
+                }
292
+            }
293
+            $idents[] = [
294
+                'qualifiers' => $qualifiers,
295
+                'value' => $claim['mainsnak']['datavalue']['value'],
296
+            ];
297
+        }
298
+
299
+        return $idents;
300
+    }
301
+
302
+    /**
303
+     * Get a single-valued text property.
304
+     * @param string $property One of the PROP_* constants.
305
+     * @return string|bool The value, or false if it can't be found.
306
+     */
307
+    public function getPropertyOfTypeText( $property ) {
308
+        $entity = $this->getEntity( $this->id );
309
+        if ( isset( $entity['claims'][$property] ) ) {
310
+            // Use the first title.
311
+            foreach ( $entity['claims'][$property] as $t ) {
312
+                if ( !isset( $t['mainsnak']['datavalue']['value']['language'] ) ) {
313
+                    var_dump( $t['mainsnak']['datavalue']['value'] );
314
+                    exit();
315
+                }
316
+                if ( $t['mainsnak']['datavalue']['value']['language'] == $this->lang
317
+                    && !empty( $t['mainsnak']['datavalue']['value']['text'] )
318
+                ) {
319
+                    return $t['mainsnak']['datavalue']['value']['text'];
320
+                }
321
+            }
322
+        }
323
+        return false;
324
+    }
325
+
326
+    /**
327
+     * Literal data field for a quantity that relates to some kind of well-defined unit. The actual unit goes in the data values that is entered.
328
+     *   - amount – implicit part of the string (mapping of unit prefix is unclear)
329
+     *   - unit – implicit part of the string that defaults to "1" (mapping to standardizing body is unclear)
330
+     *   - upperbound - quantity's upper bound
331
+     *   - lowerbound - quantity's lower bound
332
+     * @param $property
333
+     * @return mixed[]|bool If it's not false it's an array with 'amount', 'unit', etc.
334
+     */
335
+    public function getPropertyOfTypeQuantity( $property ) {
336
+        $quantities = [];
337
+        $entity = $this->getEntity( $this->id );
338
+        if ( !isset( $entity['claims'][$property] ) ) {
339
+            return false;
340
+        }
341
+        foreach ( $entity['claims'][$property] as $t ) {
342
+            $quantity = $t['mainsnak']['datavalue']['value'];
343
+            $unitId = substr( $quantity['unit'], strlen( $this->wikidataUrlBase ) + 1 );
344
+            $quantity['unit'] = self::factory( $unitId, $this->lang, $this->cache );
345
+            $quantities[] = $quantity;
346
+        }
347
+        return $quantities;
348
+    }
349
+
350
+    /**
351
+     * Set a single-valued text property.
352
+     * @param string $property One of the PROP_* constants.
353
+     * @param string $value The value.
354
+     */
355
+    public function setPropertyOfTypeText( $property, $value ) {
356
+        // First see if this property already exists, and that it is different from what's being set.
357
+        $entity = $this->getEntity( $this->id );
358
+        if ( !empty( $entity['claims'][$property] ) ) {
359
+            // Find this language's claim (if there is one).
360
+            foreach ( $entity['claims'][$property] as $claim ) {
361
+                if ( $claim['mainsnak']['datavalue']['value']['language'] == $this->lang ) {
362
+                    // Modify this claim's text value.
363
+                    $titleClaim = $claim;
364
+                    $titleClaim['mainsnak']['datavalue']['value']['text'] = $value;
365
+                    $setTitleParams = [
366
+                        'action' => 'wbsetclaim',
367
+                        'claim' => \GuzzleHttp\json_encode( $titleClaim ),
368
+                    ];
369
+                    continue;
370
+                }
371
+            }
372
+        }
373
+
374
+        // If no claim was found (and modified) above, create a new claim.
375
+        if ( !isset( $setTitleParams ) ) {
376
+            $setTitleParams = [
377
+                'action' => 'wbcreateclaim',
378
+                'entity' => $this->getId(),
379
+                'property' => $property,
380
+                'snaktype' => 'value',
381
+                'value' => \GuzzleHttp\json_encode( [ 'text' => $value, 'language' => $this->lang ] ),
382
+            ];
383
+        }
384
+
385
+        // Save the property.
386
+        $wdWpOauth = new WdWpOauth();
387
+        $wdWpOauth->makeCall( $setTitleParams, true );
388
+
389
+        // Clear the cache.
390
+        $this->cache->deleteItem( $this->getEntityCacheKey( $this->id ) );
391
+    }
392
+
393
+    /**
394
+     * Does this item exist?
395
+     * @return bool
396
+     */
397
+    public function exists() {
398
+        return $this->getId() !== false;
399
+    }
400
+
401
+    public function getWikipediaIntro() {
402
+        $cacheKey = 'wikipedia-intro-' . $this->id . $this->lang;
403
+        if ( $this->cache->hasItem( $cacheKey ) ) {
404
+            return $this->cache->getItem( $cacheKey )->get();
405
+        }
406
+        $entity = $this->getEntity( $this->id );
407
+        if ( !isset( $entity['sitelinks'] ) ) {
408
+            return [];
409
+        }
410
+        foreach ( $entity['sitelinks'] as $sitelink ) {
411
+            if ( $sitelink['site'] == $this->lang . 'wiki' ) {
412
+                $api = new MediawikiApi( 'https://' . $this->lang . '.wikipedia.org/w/api.php' );
413
+                $req = new SimpleRequest( 'query', [
414
+                    'prop' => 'extracts',
415
+                    'exintro' => true,
416
+                    'titles' => $sitelink['title'],
417
+                ] );
418
+                $response = $api->getRequest( $req );
419
+                $page = array_shift( $response['query']['pages'] );
420
+                $out = [
421
+                    'title' => $page['title'],
422
+                    'html' => $page['extract'],
423
+                ];
424
+                $cacheItem = $this->cache->getItem( $cacheKey )
425
+                    ->expiresAfter( new DateInterval( 'P1D' ) )
426
+                    ->set( $out );
427
+                $this->cache->save( $cacheItem );
428
+
429
+                return $out;
430
+            }
431
+        }
432
+
433
+        return [];
434
+    }
435
+
436
+    /**
437
+     * Get the raw entity data from the 'wbgetentities' API call.
438
+     * @param string $id The Q-number.
439
+     * @param bool $ignoreCache
440
+     * @return array|bool
441
+     */
442
+    public function getEntity( $id = null, $ignoreCache = false ) {
443
+        $idActual = $id ?: $this->id;
444
+        $cacheKey = $this->getEntityCacheKey( $idActual );
445
+        if ( !$ignoreCache && $this->cache->hasItem( $cacheKey ) ) {
446
+            return $this->cache->getItem( $cacheKey )->get();
447
+        }
448
+        $metadataRequest = new SimpleRequest( 'wbgetentities', [ 'ids' => $idActual ] );
449
+        $itemResult = $this->wdApi->getRequest( $metadataRequest );
450
+        if ( !isset( $itemResult['success'] ) || !isset( $itemResult['entities'][$id] ) ) {
451
+            return false;
452
+        }
453
+        $metadata = $itemResult['entities'][$idActual];
454
+        $cacheItem = $this->cache->getItem( $cacheKey )
455
+            ->expiresAfter( new DateInterval( 'PT10M' ) )
456
+            ->set( $metadata );
457
+        $this->cache->save( $cacheItem );
458
+        return $metadata;
459
+    }
460
+
461
+    /**
462
+     * @param $id
463
+     *
464
+     * @return string
465
+     */
466
+    protected function getEntityCacheKey( $id ) {
467
+        return 'entities' . $id;
468
+    }
469 469
 }
Please login to merge, or discard this patch.