Completed
Push — master ( 3837d1...eff53c )
by mw
164:04 queued 128:48
created

src/DataTypeRegistry.php (1 issue)

Severity

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 319
	public static function getInstance() {
0 ignored issues
show
getInstance uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
119
120 319
		if ( self::$instance === null ) {
121
122 295
			self::$instance = new self(
123 295
				$GLOBALS['smwgContLang']->getDatatypeLabels(),
124 295
				$GLOBALS['smwgContLang']->getDatatypeAliases(),
125 295
				$GLOBALS['smwgContLang']->getCanonicalDatatypeLabels()
126
			);
127
128 295
			self::$instance->initDatatypes();
129
130 295
			self::$instance->setOption(
131 295
				'smwgDVFeatures',
132 295
				ApplicationFactory::getInstance()->getSettings()->get( 'smwgDVFeatures' )
133
			);
134
		}
135
136 319
		return self::$instance;
137
	}
138
139
	/**
140
	 * Resets the DataTypeRegistry instance
141
	 *
142
	 * @since 1.9
143
	 */
144 310
	public static function clear() {
145 310
		self::$instance = null;
146 310
		ValueFormatterRegistry::getInstance()->clear();
147 310
		DVDescriptionDeserializerRegistry::getInstance()->clear();
148 310
	}
149
150
	/**
151
	 * @since 1.9.0.2
152
	 *
153
	 * @param array $typeLabels
154
	 * @param array $typeAliases
155
	 */
156 295
	public function __construct( array $typeLabels = array() , array $typeAliases = array(), array $canonicalLabels = array() ) {
157 295
		foreach ( $typeLabels as $typeId => $typeLabel ) {
158 295
			$this->registerTypeLabel( $typeId, $typeLabel );
159
		}
160
161 295
		foreach ( $typeAliases as $typeAlias => $typeId ) {
162 295
			$this->registerDataTypeAlias( $typeId, $typeAlias );
163
		}
164
165 295
		foreach ( $canonicalLabels as $label => $id ) {
166 295
			$this->canonicalLabels[$id] = $label;
167
		}
168 295
	}
169
170
	/**
171
	 * Get the preferred data item ID for a given type. The ID defines the
172
	 * appropriate data item class for processing data of this type. See
173
	 * DataItem for possible values.
174
	 *
175
	 * @note SMWDIContainer is a pseudo dataitem type that is used only in
176
	 * data input methods, but not for storing data. Types that work with
177
	 * SMWDIContainer use SMWDIWikiPage as their DI type. (Since SMW 1.8)
178
	 *
179
	 * @param $typeId string id string for the given type
180
	 * @return integer data item ID
181
	 */
182 257
	public function getDataItemId( $typeId ) {
183 257
		if ( isset( $this->typeDataItemIds[$typeId] ) ) {
184 257
			return $this->typeDataItemIds[$typeId];
185
		}
186
187 2
		return DataItem::TYPE_NOTYPE;
188
	}
189
190
	/**
191
	 * @since  2.0
192
	 *
193
	 * @param string
194
	 * @return boolean
195
	 */
196 16
	public function isKnownTypeId( $typeId ) {
197 16
		return isset( $this->typeDataItemIds[$typeId] );
198
	}
199
200
	/**
201
	 * @since 2.4
202
	 *
203
	 * @param string
204
	 * @return boolean
205
	 */
206 207
	public function isSubDataType( $typeId ) {
207 207
		return isset( $this->subDataTypes[$typeId] ) && $this->subDataTypes[$typeId];
208
	}
209
210
	/**
211
	 * A function for registering/overwriting datatypes for SMW. Should be
212
	 * called from within the hook 'smwInitDatatypes'.
213
	 *
214
	 * @param $id string type ID for which this datatype is registered
215
	 * @param $className string name of the according subclass of SMWDataValue
216
	 * @param $dataItemId integer ID of the data item class that this data value uses, see DataItem
217
	 * @param $label mixed string label or false for types that cannot be accessed by users
218
	 * @param boolean $isSubDataType
219
	 */
220 2
	public function registerDataType( $id, $className, $dataItemId, $label = false, $isSubDataType = false ) {
221 2
		$this->typeClasses[$id] = $className;
222 2
		$this->typeDataItemIds[$id] = $dataItemId;
223 2
		$this->subDataTypes[$id] = $isSubDataType;
224
225 2
		if ( $label !== false ) {
226 2
			$this->registerTypeLabel( $id, $label );
227
		}
228 2
	}
229
230 295
	private function registerTypeLabel( $typeId, $typeLabel ) {
231 295
		$this->typeLabels[$typeId] = $typeLabel;
232 295
		$this->addTextToIdLookupMap( $typeId, $typeLabel );
233 295
	}
234
235 295
	private function addTextToIdLookupMap( $dataTypeId, $text ) {
236 295
		$this->typeByLabelOrAliasLookup[strtolower($text)] = $dataTypeId;
237 295
	}
238
239
	/**
240
	 * Add a new alias label to an existing datatype id. Note that every ID
241
	 * should have a primary label, either provided by SMW or registered with
242
	 * registerDataType(). This function should be called from within the hook
243
	 * 'smwInitDatatypes'.
244
	 *
245
	 * @param string $typeId
246
	 * @param string $typeAlias
247
	 */
248 295
	public function registerDataTypeAlias( $typeId, $typeAlias ) {
249 295
		$this->typeAliases[$typeAlias] = $typeId;
250 295
		$this->addTextToIdLookupMap( $typeId, $typeAlias );
251 295
	}
252
253
	/**
254
	 * Look up the ID that identifies the datatype of the given label
255
	 * internally. This id is used for all internal operations. If the
256
	 * label does not belong to a known type, the empty string is returned.
257
	 *
258
	 * The lookup is case insensitive.
259
	 *
260
	 * @param string $label
261
	 *
262
	 * @return string
263
	 */
264 9
	public function findTypeId( $label ) {
265
266 9
		$label = strtolower( $label );
267
268 9
		if ( isset( $this->typeByLabelOrAliasLookup[$label] ) ) {
269 9
			return $this->typeByLabelOrAliasLookup[$label];
270
		}
271
272 1
		return '';
273
	}
274
275
	/**
276
	 * @since 2.5
277
	 *
278
	 * @param string $label
279
	 * @param string|false $languageCode
280
	 *
281
	 * @return string
282
	 */
283 148
	public function findTypeIdByLanguage( $label, $languageCode = false ) {
284
285 148
		$label = mb_strtolower( $label );
286
287 148
		if ( !$languageCode ) {
288
			return $this->findTypeId( $label );
289
		}
290
291 148
		$extraneousLanguage = Localizer::getInstance()->getExtraneousLanguage( $languageCode );
292
293 148
		$datatypeLabels = $extraneousLanguage->getDatatypeLabels();
294 148
		$datatypeLabels = array_flip( $datatypeLabels );
295 148
		$datatypeLabels += $extraneousLanguage->getDatatypeAliases();
296
297 148
		foreach ( $datatypeLabels as $key => $id ) {
298 148
			if ( mb_strtolower( $key ) === $label ) {
299 148
				return $id;
300
			}
301
		}
302
303
		return '';
304
	}
305
306
	/**
307
	 * Get the translated user label for a given internal ID. If the ID does
308
	 * not have a label associated with it in the current language, the
309
	 * empty string is returned. This is the case both for internal type ids
310
	 * and for invalid (unknown) type ids, so this method cannot be used to
311
	 * distinguish the two.
312
	 *
313
	 * @param string $id
314
	 *
315
	 * @return string
316
	 */
317 156
	public function findTypeLabel( $id ) {
318
319 156
		if ( isset( $this->typeLabels[$id] ) ) {
320 156
			return $this->typeLabels[$id];
321
		}
322
323
		// internal type without translation to user space;
324
		// might also happen for historic types after an upgrade --
325
		// alas, we have no idea what the former label would have been
326 3
		return '';
327
	}
328
329
	/**
330
	 * Returns a label for a typeId that is independent from the user/content
331
	 * language
332
	 *
333
	 * @since 2.3
334
	 *
335
	 * @return string
336
	 */
337 1
	public function findCanonicalLabelById( $id ) {
338
339 1
		if ( isset( $this->canonicalLabels[$id] ) ) {
340 1
			return $this->canonicalLabels[$id];
341
		}
342
343
		return '';
344
	}
345
346
	/**
347
	 * @since 2.4
348
	 *
349
	 * @return array
350
	 */
351
	public function getCanonicalDatatypeLabels() {
352
		return $this->canonicalLabels;
353
	}
354
355
	/**
356
	 * Return an array of all labels that a user might specify as the type of
357
	 * a property, and that are internal (i.e. not user defined). No labels are
358
	 * returned for internal types without user labels (e.g. the special types
359
	 * for some special properties), and for user defined types.
360
	 *
361
	 * @return array
362
	 */
363 260
	public function getKnownTypeLabels() {
364 260
		return $this->typeLabels;
365
	}
366
367
	/**
368
	 * @since 2.1
369
	 *
370
	 * @return array
371
	 */
372 260
	public function getKnownTypeAliases() {
373 260
		return $this->typeAliases;
374
	}
375
376
	/**
377
	 * Returns a default DataItemId
378
	 *
379
	 * @since 1.9
380
	 *
381
	 * @param string $diType
382
	 *
383
	 * @return string|null
384
	 */
385 141
	public function getDefaultDataItemTypeId( $diType ) {
386
387 141
		if ( isset( $this->defaultDataItemTypeIds[$diType] ) ) {
388 140
			return $this->defaultDataItemTypeIds[$diType];
389
		}
390
391 1
		return null;
392
	}
393
394
	/**
395
	 * Returns a class based on a typeId
396
	 *
397
	 * @since 1.9
398
	 *
399
	 * @param string $typeId
400
	 *
401
	 * @return string|null
402
	 */
403 233
	public function getDataTypeClassById( $typeId ) {
404
405 233
		if ( $this->hasDataTypeClassById( $typeId ) ) {
406 233
			return $this->typeClasses[$typeId];
407
		}
408
409 1
		return null;
410
	}
411
412
	/**
413
	 * Whether a datatype class is registered for a particular typeId
414
	 *
415
	 * @since 1.9
416
	 *
417
	 * @param string $typeId
418
	 *
419
	 * @return boolean
420
	 */
421 233
	public function hasDataTypeClassById( $typeId ) {
422 233
		return isset( $this->typeClasses[$typeId] ) && class_exists( $this->typeClasses[$typeId] );
423
	}
424
425
	/**
426
	 * Gather all available datatypes and label<=>id<=>datatype
427
	 * associations. This method is called before most methods of this
428
	 * factory.
429
	 */
430 295
	protected function initDatatypes() {
431
		// Setup built-in datatypes.
432
		// NOTE: all ids must start with underscores, where two underscores indicate
433
		// truly internal (non user-acceptable types). All others should also get a
434
		// translation in the language files, or they won't be available for users.
435 295
		$this->typeClasses = array(
436
			'_txt'  => 'SMWStringValue', // Text type
437
			'_cod'  => 'SMWStringValue', // Code type
438
			'_str'  => 'SMWStringValue', // DEPRECATED Will vanish after SMW 1.9; use '_txt'
439
			'_ema'  => 'SMWURIValue', // Email type
440
			'_uri'  => 'SMWURIValue', // URL/URI type
441
			'_anu'  => 'SMWURIValue', // Annotation URI type
442
			'_tel'  => 'SMW\DataValues\TelephoneUriValue', // Phone number (URI) type
443
			'_wpg'  => 'SMWWikiPageValue', // Page type
444
			'_wpp'  => 'SMWWikiPageValue', // Property page type TODO: make available to user space
445
			'_wpc'  => 'SMWWikiPageValue', // Category page type TODO: make available to user space
446
			'_wpf'  => 'SMWWikiPageValue', // Form page type for Semantic Forms
447
			'_num'  => 'SMWNumberValue', // Number type
448
			'_tem'  => 'SMW\DataValues\TemperatureValue', // Temperature type
449
			'_dat'  => 'SMWTimeValue', // Time type
450
			'_boo'  => 'SMW\DataValues\BooleanValue', // Boolean type
451
			'_rec'  => 'SMWRecordValue', // Value list type (replacing former nary properties)
452
			'_mlt_rec'  => 'SMW\DataValues\MonolingualTextValue',
453
			'_ref_rec'  => 'SMW\DataValues\ReferenceValue',
454
			'_qty'  => 'SMWQuantityValue', // Type for numbers with units of measurement
455
			// Special types are not avaialble directly for users (and have no local language name):
456
			'__typ' => 'SMWTypesValue', // Special type page type
457
			'__pls' => 'SMWPropertyListValue', // Special type list for decalring _rec properties
458
			'__con' => 'SMWConceptValue', // Special concept page type
459
			'__sps' => 'SMWStringValue', // Special string type
460
			'__spu' => 'SMWURIValue', // Special uri type
461
			'__sob' => 'SMWWikiPageValue', // Special subobject type
462
			'__sup' => 'SMWWikiPageValue', // Special subproperty type
463
			'__suc' => 'SMWWikiPageValue', // Special subcategory type
464
			'__spf' => 'SMWWikiPageValue', // Special Form page type for Semantic Forms
465
			'__sin' => 'SMWWikiPageValue', // Special instance of type
466
			'__red' => 'SMWWikiPageValue', // Special redirect type
467
			'__err' => 'SMWErrorValue', // Special error type
468
			'__errt' => 'SMW\DataValues\ErrorMsgTextValue', // Special error type
469
			'__imp' => 'SMW\DataValues\ImportValue', // Special import vocabulary type
470
			'__pro' => 'SMWPropertyValue', // Property type (possibly predefined, no always based on a page)
471
			'__key' => 'SMWStringValue', // Sort key of a page
472
			'__lcode' => 'SMW\DataValues\LanguageCodeValue',
473
			'__pval' => 'SMW\DataValues\AllowsListValue',
474
			'__pvap' => 'SMW\DataValues\AllowsPatternValue',
475
			'__pvuc' => 'SMW\DataValues\UniquenessConstraintValue',
476
			'_eid' => 'SMW\DataValues\ExternalIdentifierValue',
477
			'__pefu' => 'SMW\DataValues\ExternalFormatterUriValue',
478
			'__pchn' => 'SMW\DataValues\PropertyChainValue',
479
		);
480
481 295
		$this->typeDataItemIds = array(
482 295
			'_txt'  => DataItem::TYPE_BLOB, // Text type
483 295
			'_cod'  => DataItem::TYPE_BLOB, // Code type
484 295
			'_str'  => DataItem::TYPE_BLOB, // DEPRECATED Will vanish after SMW 1.9; use '_txt'
485 295
			'_ema'  => DataItem::TYPE_URI, // Email type
486 295
			'_uri'  => DataItem::TYPE_URI, // URL/URI type
487 295
			'_anu'  => DataItem::TYPE_URI, // Annotation URI type
488 295
			'_tel'  => DataItem::TYPE_URI, // Phone number (URI) type
489 295
			'_wpg'  => DataItem::TYPE_WIKIPAGE, // Page type
490 295
			'_wpp'  => DataItem::TYPE_WIKIPAGE, // Property page type TODO: make available to user space
491 295
			'_wpc'  => DataItem::TYPE_WIKIPAGE, // Category page type TODO: make available to user space
492 295
			'_wpf'  => DataItem::TYPE_WIKIPAGE, // Form page type for Semantic Forms
493 295
			'_num'  => DataItem::TYPE_NUMBER, // Number type
494 295
			'_tem'  => DataItem::TYPE_NUMBER, // Temperature type
495 295
			'_dat'  => DataItem::TYPE_TIME, // Time type
496 295
			'_boo'  => DataItem::TYPE_BOOLEAN, // Boolean type
497 295
			'_rec'  => DataItem::TYPE_WIKIPAGE, // Value list type (replacing former nary properties)
498 295
			'_mlt_rec' => DataItem::TYPE_WIKIPAGE, // Monolingual text container
499 295
			'_ref_rec' => DataItem::TYPE_WIKIPAGE, // Reference container
500 295
			'_geo'  => DataItem::TYPE_GEO, // Geographical coordinates
501 295
			'_gpo'  => DataItem::TYPE_BLOB, // Geographical polygon
502 295
			'_qty'  => DataItem::TYPE_NUMBER, // Type for numbers with units of measurement
503 295
			'_eid' => DataItem::TYPE_BLOB, // External ID
504
			// Special types are not available directly for users (and have no local language name):
505 295
			'__typ' => DataItem::TYPE_URI, // Special type page type
506 295
			'__pls' => DataItem::TYPE_BLOB, // Special type list for decalring _rec properties
507 295
			'__con' => DataItem::TYPE_CONCEPT, // Special concept page type
508 295
			'__sps' => DataItem::TYPE_BLOB, // Special string type
509 295
			'__pval' => DataItem::TYPE_BLOB, // Special string type
510 295
			'__spu' => DataItem::TYPE_URI, // Special uri type
511 295
			'__sob' => DataItem::TYPE_WIKIPAGE, // Special subobject type
512 295
			'__sup' => DataItem::TYPE_WIKIPAGE, // Special subproperty type
513 295
			'__suc' => DataItem::TYPE_WIKIPAGE, // Special subcategory type
514 295
			'__spf' => DataItem::TYPE_WIKIPAGE, // Special Form page type for Semantic Forms
515 295
			'__sin' => DataItem::TYPE_WIKIPAGE, // Special instance of type
516 295
			'__red' => DataItem::TYPE_WIKIPAGE, // Special redirect type
517 295
			'__err' => DataItem::TYPE_ERROR, // Special error type
518 295
			'__errt' => DataItem::TYPE_BLOB, // error text
519 295
			'__imp' => DataItem::TYPE_BLOB, // Special import vocabulary type
520 295
			'__pro' => DataItem::TYPE_PROPERTY, // Property type (possibly predefined, no always based on a page)
521 295
			'__key' => DataItem::TYPE_BLOB, // Sort key of a page
522 295
			'__lcode' => DataItem::TYPE_BLOB, // Language code
523 295
			'__pvap' => DataItem::TYPE_BLOB, // Allows pattern
524 295
			'__pvuc' => DataItem::TYPE_BOOLEAN, // Uniqueness constraint
525 295
			'__pefu' => DataItem::TYPE_URI, // External formatter uri
526 295
			'__pchn' => DataItem::TYPE_BLOB, // Property chain
527
		);
528
529 295
		$this->subDataTypes = array(
530
			'__sob' => true,
531
			'_rec'  => true,
532
			'_mlt_rec' => true,
533
			'_ref_rec' => true
534
		);
535
536
		// Deprecated since 1.9
537 295
		\Hooks::run( 'smwInitDatatypes' );
538
539
		// Since 1.9
540 295
		\Hooks::run( 'SMW::DataType::initTypes', array( $this ) );
541 295
	}
542
543
	/**
544
	 * @since 2.4
545
	 *
546
	 * @param DataValueFormatter $dataValueFormatter
547
	 */
548 1
	public function registerDataValueFormatter( DataValueFormatter $dataValueFormatter ) {
549 1
		ValueFormatterRegistry::getInstance()->registerDataValueFormatter( $dataValueFormatter );
550 1
	}
551
552
	/**
553
	 * @since 2.4
554
	 *
555
	 * @param DescriptionDeserializer $descriptionDeserializer
556
	 */
557 1
	public function registerDVDescriptionDeserializer( DescriptionDeserializer $descriptionDeserializer ) {
558 1
		DVDescriptionDeserializerRegistry::getInstance()->registerDescriptionDeserializer( $descriptionDeserializer );
559 1
	}
560
561
	/**
562
	 * Inject services and objects that are planned to be used during the invocation of
563
	 * a DataValue
564
	 *
565
	 * @since 2.3
566
	 *
567
	 * @param string  $name
568
	 * @param \Closure $callback
569
	 */
570 1
	public function registerExtraneousFunction( $name, \Closure $callback ) {
571 1
		$this->extraneousFunctions[$name] = $callback;
572 1
	}
573
574
	/**
575
	 * @since 2.3
576
	 *
577
	 * @return Closure[]
578
	 */
579 233
	public function getExtraneousFunctions() {
580 233
		return $this->extraneousFunctions;
581
	}
582
583
	/**
584
	 * @since 2.4
585
	 *
586
	 * @return Options
587
	 */
588 310
	public function getOptions() {
589
590 310
		if ( $this->options === null ) {
591 295
			$this->options = new Options();
592
		}
593
594 310
		return $this->options;
595
	}
596
597
	/**
598
	 * @since 2.4
599
	 *
600
	 * @param string $key
601
	 * @param string $value
602
	 */
603 295
	public function setOption( $key, $value ) {
604 295
		$this->getOptions()->set( $key, $value );
605 295
	}
606
607
}
608