Completed
Push — master ( d749c2...317d6d )
by mw
36:25 queued 10:28
created

src/DataTypeRegistry.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace SMW;
4
5
use SMW\DataValues\ValueFormatterRegistry;
6
use SMW\DataValues\ValueFormatters\DataValueFormatter;
7
use SMW\Deserializers\DVDescriptionDeserializer\DescriptionDeserializer;
8
use SMW\Deserializers\DVDescriptionDeserializerRegistry;
9
use SMWDataItem as DataItem;
10
11
/**
12
 * DataTypes registry class
13
 *
14
 * Registry class that manages datatypes, and provides various methods to access
15
 * the information
16
 *
17
 * @license GNU GPL v2+
18
 * @since 1.9
19
 *
20
 * @author Markus Krötzsch
21
 * @author Jeroen De Dauw
22
 * @author mwjames
23
 */
24
class DataTypeRegistry {
25
26
	/**
27
	 * @var DataTypeRegistry
28
	 */
29
	protected static $instance = null;
30
31
	/**
32
	 * Array of type labels indexed by type ids. Used for datatype resolution.
33
	 *
34
	 * @var string[]
35
	 */
36
	private $typeLabels = array();
37
38
	/**
39
	 * Array of ids indexed by type aliases. Used for datatype resolution.
40
	 *
41
	 * @var string[]
42
	 */
43
	private $typeAliases = array();
44
45
	/**
46
	 * @var string[]
47
	 */
48
	private $canonicalLabels = array();
49
50
	/**
51
	 * Array of class names for creating new SMWDataValue, indexed by type
52
	 * id.
53
	 *
54
	 * @var string[]
55
	 */
56
	private $typeClasses;
57
58
	/**
59
	 * Array of data item classes, indexed by type id.
60
	 *
61
	 * @var integer[]
62
	 */
63
	private $typeDataItemIds;
64
65
	/**
66
	 * @var string[]
67
	 */
68
	private $subDataTypes = array();
69
70
	/**
71
	 * Lookup map that allows finding a datatype id given a label or alias.
72
	 * All labels and aliases (ie array keys) are stored lower case.
73
	 *
74
	 * @var string[]
75
	 */
76
	private $typeByLabelOrAliasLookup = array();
77
78
	/**
79
	 * Array of default types to use for making datavalues for dataitems.
80
	 *
81
	 * @var string[]
82
	 */
83
	private $defaultDataItemTypeIds = array(
84
		DataItem::TYPE_BLOB => '_txt', // Text type
85
		DataItem::TYPE_URI => '_uri', // URL/URI type
86
		DataItem::TYPE_WIKIPAGE => '_wpg', // Page type
87
		DataItem::TYPE_NUMBER => '_num', // Number type
88
		DataItem::TYPE_TIME => '_dat', // Time type
89
		DataItem::TYPE_BOOLEAN => '_boo', // Boolean type
90
		DataItem::TYPE_CONTAINER => '_rec', // Value list type (replacing former nary properties)
91
		DataItem::TYPE_GEO => '_geo', // Geographical coordinates
92
		DataItem::TYPE_CONCEPT => '__con', // Special concept page type
93
		DataItem::TYPE_PROPERTY => '__pro', // Property type
94
95
		// If either of the following two occurs, we want to see a PHP error:
96
		//DataItem::TYPE_NOTYPE => '',
97
		//DataItem::TYPE_ERROR => '',
98
	);
99
100
101
	/**
102
	 * @var Closure[]
103
	 */
104
	private $extraneousFunctions = array();
105
106
	/**
107
	 * @var Options
108
	 */
109
	private $options = null;
110
111
	/**
112
	 * Returns a DataTypeRegistry instance
113
	 *
114
	 * @since 1.9
115
	 *
116
	 * @return DataTypeRegistry
117
	 */
118 281
	public static function getInstance() {
119
120 281
		if ( self::$instance === null ) {
121
122
			// This is the earliest point we can reset the language in accordance with
123
			// the user setting because any access to Language::getCode during the
124
			// setup violates MW's internal state
125 244
			NamespaceManager::getNamespacesByLanguageCode(
126 244
				Localizer::getInstance()->getUserLanguage()->getCode()
127
			);
128
129 244
			self::$instance = new self(
130 244
				$GLOBALS['smwgContLang']->getDatatypeLabels(),
131 244
				$GLOBALS['smwgContLang']->getDatatypeAliases(),
132 244
				$GLOBALS['smwgContLang']->getCanonicalDatatypeLabels()
133
			);
134
135 244
			self::$instance->initDatatypes();
136
137 244
			self::$instance->setOption(
138 244
				'smwgDVFeatures',
139 244
				ApplicationFactory::getInstance()->getSettings()->get( 'smwgDVFeatures' )
140
			);
141
		}
142
143 281
		return self::$instance;
144
	}
145
146
	/**
147
	 * Resets the DataTypeRegistry instance
148
	 *
149
	 * @since 1.9
150
	 */
151 258
	public static function clear() {
152 258
		self::$instance = null;
153 258
		ValueFormatterRegistry::getInstance()->clear();
154 258
		DVDescriptionDeserializerRegistry::getInstance()->clear();
155 258
	}
156
157
	/**
158
	 * @since 1.9.0.2
159
	 *
160
	 * @param array $typeLabels
161
	 * @param array $typeAliases
162
	 */
163 244
	public function __construct( array $typeLabels = array() , array $typeAliases = array(), array $canonicalLabels = array() ) {
164 244
		foreach ( $typeLabels as $typeId => $typeLabel ) {
165 244
			$this->registerTypeLabel( $typeId, $typeLabel );
166
		}
167
168 244
		foreach ( $typeAliases as $typeAlias => $typeId ) {
169 244
			$this->registerDataTypeAlias( $typeId, $typeAlias );
170
		}
171
172 244
		foreach ( $canonicalLabels as $label => $id ) {
173 244
			$this->canonicalLabels[$id] = $label;
174
		}
175 244
	}
176
177
	/**
178
	 * Get the preferred data item ID for a given type. The ID defines the
179
	 * appropriate data item class for processing data of this type. See
180
	 * DataItem for possible values.
181
	 *
182
	 * @note SMWDIContainer is a pseudo dataitem type that is used only in
183
	 * data input methods, but not for storing data. Types that work with
184
	 * SMWDIContainer use SMWDIWikiPage as their DI type. (Since SMW 1.8)
185
	 *
186
	 * @param $typeId string id string for the given type
187
	 * @return integer data item ID
188
	 */
189 236
	public function getDataItemId( $typeId ) {
190 236
		if ( isset( $this->typeDataItemIds[$typeId] ) ) {
191 236
			return $this->typeDataItemIds[$typeId];
192
		}
193
194 2
		return DataItem::TYPE_NOTYPE;
195
	}
196
197
	/**
198
	 * @since  2.0
199
	 *
200
	 * @param string
201
	 * @return boolean
202
	 */
203 16
	public function isKnownTypeId( $typeId ) {
204 16
		return isset( $this->typeDataItemIds[$typeId] );
205
	}
206
207
	/**
208
	 * @since 2.4
209
	 *
210
	 * @param string
211
	 * @return boolean
212
	 */
213 181
	public function isSubDataType( $typeId ) {
214 181
		return isset( $this->subDataTypes[$typeId] ) && $this->subDataTypes[$typeId];
215
	}
216
217
	/**
218
	 * A function for registering/overwriting datatypes for SMW. Should be
219
	 * called from within the hook 'smwInitDatatypes'.
220
	 *
221
	 * @param $id string type ID for which this datatype is registered
222
	 * @param $className string name of the according subclass of SMWDataValue
223
	 * @param $dataItemId integer ID of the data item class that this data value uses, see DataItem
224
	 * @param $label mixed string label or false for types that cannot be accessed by users
225
	 * @param boolean $isSubDataType
226
	 */
227 2
	public function registerDataType( $id, $className, $dataItemId, $label = false, $isSubDataType = false ) {
228 2
		$this->typeClasses[$id] = $className;
229 2
		$this->typeDataItemIds[$id] = $dataItemId;
230 2
		$this->subDataTypes[$id] = $isSubDataType;
231
232 2
		if ( $label !== false ) {
233 2
			$this->registerTypeLabel( $id, $label );
234
		}
235 2
	}
236
237 244
	private function registerTypeLabel( $typeId, $typeLabel ) {
238 244
		$this->typeLabels[$typeId] = $typeLabel;
239 244
		$this->addTextToIdLookupMap( $typeId, $typeLabel );
240 244
	}
241
242 244
	private function addTextToIdLookupMap( $dataTypeId, $text ) {
243 244
		$this->typeByLabelOrAliasLookup[strtolower($text)] = $dataTypeId;
244 244
	}
245
246
	/**
247
	 * Add a new alias label to an existing datatype id. Note that every ID
248
	 * should have a primary label, either provided by SMW or registered with
249
	 * registerDataType(). This function should be called from within the hook
250
	 * 'smwInitDatatypes'.
251
	 *
252
	 * @param string $typeId
253
	 * @param string $typeAlias
254
	 */
255 244
	public function registerDataTypeAlias( $typeId, $typeAlias ) {
256 244
		$this->typeAliases[$typeAlias] = $typeId;
257 244
		$this->addTextToIdLookupMap( $typeId, $typeAlias );
258 244
	}
259
260
	/**
261
	 * Look up the ID that identifies the datatype of the given label
262
	 * internally. This id is used for all internal operations. If the
263
	 * label does not belong to a known type, the empty string is returned.
264
	 *
265
	 * The lookup is case insensitive.
266
	 *
267
	 * @param string $label
268
	 *
269
	 * @return string
270
	 */
271 129
	public function findTypeId( $label ) {
272
273 129
		$label = strtolower( $label );
274
275 129
		if ( isset( $this->typeByLabelOrAliasLookup[$label] ) ) {
276 129
			return $this->typeByLabelOrAliasLookup[$label];
277
		}
278
279 1
		return '';
280
	}
281
282
	/**
283
	 * Get the translated user label for a given internal ID. If the ID does
284
	 * not have a label associated with it in the current language, the
285
	 * empty string is returned. This is the case both for internal type ids
286
	 * and for invalid (unknown) type ids, so this method cannot be used to
287
	 * distinguish the two.
288
	 *
289
	 * @param string $id
290
	 *
291
	 * @return string
292
	 */
293 133
	public function findTypeLabel( $id ) {
294
295 133
		if ( isset( $this->typeLabels[$id] ) ) {
296 133
			return $this->typeLabels[$id];
297
		}
298
299
		// internal type without translation to user space;
300
		// might also happen for historic types after an upgrade --
301
		// alas, we have no idea what the former label would have been
302 3
		return '';
303
	}
304
305
	/**
306
	 * Returns a label for a typeId that is independent from the user/content
307
	 * language
308
	 *
309
	 * @since 2.3
310
	 *
311
	 * @return string
312
	 */
313 1
	public function findCanonicalLabelById( $id ) {
314
315 1
		if ( isset( $this->canonicalLabels[$id] ) ) {
316 1
			return $this->canonicalLabels[$id];
317
		}
318
319
		return '';
320
	}
321
322
	/**
323
	 * @since 2.4
324
	 *
325
	 * @return array
326
	 */
327
	public function getCanonicalDatatypeLabels() {
328
		return $this->canonicalLabels;
329
	}
330
331
	/**
332
	 * Return an array of all labels that a user might specify as the type of
333
	 * a property, and that are internal (i.e. not user defined). No labels are
334
	 * returned for internal types without user labels (e.g. the special types
335
	 * for some special properties), and for user defined types.
336
	 *
337
	 * @return array
338
	 */
339 235
	public function getKnownTypeLabels() {
340 235
		return $this->typeLabels;
341
	}
342
343
	/**
344
	 * @since 2.1
345
	 *
346
	 * @return array
347
	 */
348 235
	public function getKnownTypeAliases() {
349 235
		return $this->typeAliases;
350
	}
351
352
	/**
353
	 * Returns a default DataItemId
354
	 *
355
	 * @since 1.9
356
	 *
357
	 * @param string $diType
358
	 *
359
	 * @return string|null
360
	 */
361 119
	public function getDefaultDataItemTypeId( $diType ) {
362
363 119
		if ( isset( $this->defaultDataItemTypeIds[$diType] ) ) {
364 118
			return $this->defaultDataItemTypeIds[$diType];
365
		}
366
367 1
		return null;
368
	}
369
370
	/**
371
	 * Returns a class based on a typeId
372
	 *
373
	 * @since 1.9
374
	 *
375
	 * @param string $typeId
376
	 *
377
	 * @return string|null
378
	 */
379 204
	public function getDataTypeClassById( $typeId ) {
380
381 204
		if ( $this->hasDataTypeClassById( $typeId ) ) {
382 204
			return $this->typeClasses[$typeId];
383
		}
384
385 1
		return null;
386
	}
387
388
	/**
389
	 * Whether a datatype class is registered for a particular typeId
390
	 *
391
	 * @since 1.9
392
	 *
393
	 * @param string $typeId
394
	 *
395
	 * @return boolean
396
	 */
397 204
	public function hasDataTypeClassById( $typeId ) {
398 204
		return isset( $this->typeClasses[$typeId] ) && class_exists( $this->typeClasses[$typeId] );
399
	}
400
401
	/**
402
	 * Gather all available datatypes and label<=>id<=>datatype
403
	 * associations. This method is called before most methods of this
404
	 * factory.
405
	 */
406 244
	protected function initDatatypes() {
407
		// Setup built-in datatypes.
408
		// NOTE: all ids must start with underscores, where two underscores indicate
409
		// truly internal (non user-acceptable types). All others should also get a
410
		// translation in the language files, or they won't be available for users.
411 244
		$this->typeClasses = array(
0 ignored issues
show
Documentation Bug introduced by
It seems like array('_txt' => 'SMWStri...uenessConstraintValue') of type array<string,string,{"_t...ng","__pvuc":"string"}> is incompatible with the declared type array<integer,string> of property $typeClasses.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
412
			'_txt'  => 'SMWStringValue', // Text type
413
			'_cod'  => 'SMWStringValue', // Code type
414
			'_str'  => 'SMWStringValue', // DEPRECATED Will vanish after SMW 1.9; use '_txt'
415
			'_ema'  => 'SMWURIValue', // Email type
416
			'_uri'  => 'SMWURIValue', // URL/URI type
417
			'_anu'  => 'SMWURIValue', // Annotation URI type
418
			'_tel'  => 'SMW\DataValues\TelephoneUriValue', // Phone number (URI) type
419
			'_wpg'  => 'SMWWikiPageValue', // Page type
420
			'_wpp'  => 'SMWWikiPageValue', // Property page type TODO: make available to user space
421
			'_wpc'  => 'SMWWikiPageValue', // Category page type TODO: make available to user space
422
			'_wpf'  => 'SMWWikiPageValue', // Form page type for Semantic Forms
423
			'_num'  => 'SMWNumberValue', // Number type
424
			'_tem'  => 'SMW\DataValues\TemperatureValue', // Temperature type
425
			'_dat'  => 'SMWTimeValue', // Time type
426
			'_boo'  => 'SMW\DataValues\BooleanValue', // Boolean type
427
			'_rec'  => 'SMWRecordValue', // Value list type (replacing former nary properties)
428
			'_mlt_rec'  => 'SMW\DataValues\MonolingualTextValue',
429
			'_qty'  => 'SMWQuantityValue', // Type for numbers with units of measurement
430
			// Special types are not avaialble directly for users (and have no local language name):
431
			'__typ' => 'SMWTypesValue', // Special type page type
432
			'__pls' => 'SMWPropertyListValue', // Special type list for decalring _rec properties
433
			'__con' => 'SMWConceptValue', // Special concept page type
434
			'__sps' => 'SMWStringValue', // Special string type
435
			'__spu' => 'SMWURIValue', // Special uri type
436
			'__sob' => 'SMWWikiPageValue', // Special subobject type
437
			'__sup' => 'SMWWikiPageValue', // Special subproperty type
438
			'__suc' => 'SMWWikiPageValue', // Special subcategory type
439
			'__spf' => 'SMWWikiPageValue', // Special Form page type for Semantic Forms
440
			'__sin' => 'SMWWikiPageValue', // Special instance of type
441
			'__red' => 'SMWWikiPageValue', // Special redirect type
442
			'__err' => 'SMWErrorValue', // Special error type
443
			'__imp' => 'SMW\DataValues\ImportValue', // Special import vocabulary type
444
			'__pro' => 'SMWPropertyValue', // Property type (possibly predefined, no always based on a page)
445
			'__key' => 'SMWStringValue', // Sort key of a page
446
			'__lcode' => 'SMW\DataValues\LanguageCodeValue',
447
			'__pval' => 'SMW\DataValues\AllowsListValue',
448
			'__pvap' => 'SMW\DataValues\AllowsPatternValue',
449
			'__pvuc' => 'SMW\DataValues\UniquenessConstraintValue',
450
		);
451
452 244
		$this->typeDataItemIds = array(
453 244
			'_txt'  => DataItem::TYPE_BLOB, // Text type
454 244
			'_cod'  => DataItem::TYPE_BLOB, // Code type
455 244
			'_str'  => DataItem::TYPE_BLOB, // DEPRECATED Will vanish after SMW 1.9; use '_txt'
456 244
			'_ema'  => DataItem::TYPE_URI, // Email type
457 244
			'_uri'  => DataItem::TYPE_URI, // URL/URI type
458 244
			'_anu'  => DataItem::TYPE_URI, // Annotation URI type
459 244
			'_tel'  => DataItem::TYPE_URI, // Phone number (URI) type
460 244
			'_wpg'  => DataItem::TYPE_WIKIPAGE, // Page type
461 244
			'_wpp'  => DataItem::TYPE_WIKIPAGE, // Property page type TODO: make available to user space
462 244
			'_wpc'  => DataItem::TYPE_WIKIPAGE, // Category page type TODO: make available to user space
463 244
			'_wpf'  => DataItem::TYPE_WIKIPAGE, // Form page type for Semantic Forms
464 244
			'_num'  => DataItem::TYPE_NUMBER, // Number type
465 244
			'_tem'  => DataItem::TYPE_NUMBER, // Temperature type
466 244
			'_dat'  => DataItem::TYPE_TIME, // Time type
467 244
			'_boo'  => DataItem::TYPE_BOOLEAN, // Boolean type
468 244
			'_rec'  => DataItem::TYPE_WIKIPAGE, // Value list type (replacing former nary properties)
469 244
			'_mlt_rec' => DataItem::TYPE_WIKIPAGE, // Monolingual text container
470 244
			'_geo'  => DataItem::TYPE_GEO, // Geographical coordinates
471 244
			'_gpo'  => DataItem::TYPE_BLOB, // Geographical polygon
472 244
			'_qty'  => DataItem::TYPE_NUMBER, // Type for numbers with units of measurement
473
			// Special types are not available directly for users (and have no local language name):
474 244
			'__typ' => DataItem::TYPE_URI, // Special type page type
475 244
			'__pls' => DataItem::TYPE_BLOB, // Special type list for decalring _rec properties
476 244
			'__con' => DataItem::TYPE_CONCEPT, // Special concept page type
477 244
			'__sps' => DataItem::TYPE_BLOB, // Special string type
478 244
			'__pval' => DataItem::TYPE_BLOB, // Special string type
479 244
			'__spu' => DataItem::TYPE_URI, // Special uri type
480 244
			'__sob' => DataItem::TYPE_WIKIPAGE, // Special subobject type
481 244
			'__sup' => DataItem::TYPE_WIKIPAGE, // Special subproperty type
482 244
			'__suc' => DataItem::TYPE_WIKIPAGE, // Special subcategory type
483 244
			'__spf' => DataItem::TYPE_WIKIPAGE, // Special Form page type for Semantic Forms
484 244
			'__sin' => DataItem::TYPE_WIKIPAGE, // Special instance of type
485 244
			'__red' => DataItem::TYPE_WIKIPAGE, // Special redirect type
486 244
			'__err' => DataItem::TYPE_ERROR, // Special error type
487 244
			'__imp' => DataItem::TYPE_BLOB, // Special import vocabulary type
488 244
			'__pro' => DataItem::TYPE_PROPERTY, // Property type (possibly predefined, no always based on a page)
489 244
			'__key' => DataItem::TYPE_BLOB, // Sort key of a page
490 244
			'__lcode' => DataItem::TYPE_BLOB, // Language code
491 244
			'__pvap' => DataItem::TYPE_BLOB, // Allows pattern
492 244
			'__pvuc' => DataItem::TYPE_BOOLEAN, // Uniqueness constraint
493
		);
494
495 244
		$this->subDataTypes = array(
496
			'__sob' => true,
497
			'_rec'  => true,
498
			'_mlt_rec' => true
499
		);
500
501
		// Deprecated since 1.9
502 244
		\Hooks::run( 'smwInitDatatypes' );
503
504
		// Since 1.9
505 244
		\Hooks::run( 'SMW::DataType::initTypes', array( $this ) );
506 244
	}
507
508
	/**
509
	 * @since 2.4
510
	 *
511
	 * @param DataValueFormatter $dataValueFormatter
512
	 */
513 1
	public function registerDataValueFormatter( DataValueFormatter $dataValueFormatter ) {
514 1
		ValueFormatterRegistry::getInstance()->registerDataValueFormatter( $dataValueFormatter );
515 1
	}
516
517
	/**
518
	 * @since 2.4
519
	 *
520
	 * @param DescriptionDeserializer $descriptionDeserializer
521
	 */
522 1
	public function registerDVDescriptionDeserializer( DescriptionDeserializer $descriptionDeserializer ) {
523 1
		DVDescriptionDeserializerRegistry::getInstance()->registerDescriptionDeserializer( $descriptionDeserializer );
524 1
	}
525
526
	/**
527
	 * Inject services and objects that are planned to be used during the invocation of
528
	 * a DataValue
529
	 *
530
	 * @since 2.3
531
	 *
532
	 * @param string  $name
533
	 * @param \Closure $callback
534
	 */
535 1
	public function registerExtraneousFunction( $name, \Closure $callback ) {
536 1
		$this->extraneousFunctions[$name] = $callback;
537 1
	}
538
539
	/**
540
	 * @since 2.3
541
	 *
542
	 * @return Closure[]
543
	 */
544 204
	public function getExtraneousFunctions() {
545 204
		return $this->extraneousFunctions;
546
	}
547
548
	/**
549
	 * @since 2.4
550
	 *
551
	 * @return Options
552
	 */
553 269
	public function getOptions() {
554
555 269
		if ( $this->options === null ) {
556 244
			$this->options = new Options();
557
		}
558
559 269
		return $this->options;
560
	}
561
562
	/**
563
	 * @since 2.4
564
	 *
565
	 * @param string $key
566
	 * @param string $value
567
	 */
568 244
	public function setOption( $key, $value ) {
569 244
		$this->getOptions()->set( $key, $value );
570 244
	}
571
572
}
573