Completed
Push — master ( 14d2bd...06e609 )
by mw
81:37 queued 59:24
created

includes/datavalues/SMW_DataValue.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
/**
4
 * This group contains all parts of SMW that relate to the processing of datavalues
5
 * of various types.
6
 *
7
 * @defgroup SMWDataValues SMWDataValues
8
 * @ingroup SMW
9
 */
10
use SMW\ApplicationFactory;
11
use SMW\DataValues\ValueFormatterRegistry;
12
use SMW\DataValues\ValueValidatorRegistry;
13
use SMW\Deserializers\DVDescriptionDeserializerRegistry;
14
use SMW\Message;
15
use SMW\Options;
16
use SMW\Localizer;
17
use SMW\Query\QueryComparator;
18
19
/**
20
 * Objects of this type represent all that is known about a certain user-provided
21
 * data value, especially its various representations as strings, tooltips,
22
 * numbers, etc.  Objects can be created as "emtpy" containers of a certain type,
23
 * but are then usually filled with data to present one particular data value.
24
 *
25
 * Data values have two chief representation forms: the user-facing syntax and the
26
 * internal representation. In user syntax, every value is (necessarily) a single
27
 * string, however complex the value is. For example, a string such as "Help:editing"
28
 * may represent a wiki page called "Editing" in the namespace for "Help". The
29
 * internal representation may be any numerical array of strings and numbers. In the
30
 * example, it might be array("Editing",12), where 12 is the number used for identifying
31
 * the namespace "Help:". Of course, the internal representation could also use a single
32
 * string value, such as in array("Help:Editing"), but this might be less useful for
33
 * certain operations (e.g. filterng by namespace). Moreover, all values that are
34
 * restored from the database are given in the internal format, so it wise to choose a
35
 * format that allows for very fast and easy processing without unnecessary parsing.
36
 *
37
 * The main functions of data value objects are:
38
 * - setUserValue() which triggers parseUserValue() to process a user-level string.
39
 *
40
 * In addition, there are a number of get-functions that provide useful output versions
41
 * for displaying and serializing the value.
42
 *
43
 * @ingroup SMWDataValues
44
 *
45
 * @author Markus Krötzsch
46
 */
47
abstract class SMWDataValue {
48
49
	/**
50
	 * Associated data item. This is the reference to the immutable object
51
	 * that represents the current data content. All other data stored here
52
	 * is only about presentation and parsing, but is not relevant to the
53
	 * actual data that is represented (and stored later on).
54
	 *
55
	 * This variable must always be set to some data item, even if there
56
	 * have been errors in initialising the data.
57
	 * @var SMWDataItem
58
	 */
59
	protected $m_dataitem;
60
61
	/**
62
	 * The property for which this value is constructed or null if none
63
	 * given. Property pages are used to make settings that affect parsing
64
	 * and display, hence it is sometimes needed to know them.
65
	 *
66
	 * @var SMWDIProperty
67
	 */
68
	protected $m_property = null;
69
70
	/**
71
	 * Wiki page in the context of which the value is to be interpreted, or
72
	 * null if not given (or not on a page). This information is used to
73
	 * parse user values such as "#subsection" which only make sense when
74
	 * used on a certain page.
75
	 *
76
	 * @var SMWDIWikiPage
77
	 */
78
	protected $m_contextPage = null;
79
80
	/**
81
	 * The text label to be used for output or false if none given.
82
	 * @var string
83
	 */
84
	protected $m_caption;
85
86
	/**
87
	 * The type id for this value object.
88
	 * @var string
89
	 */
90
	protected $m_typeid;
91
92
	/**
93
	 * Array of SMWInfolink objects.
94
	 * @var array
95
	 */
96
	protected $m_infolinks = array();
97
98
	/**
99
	 * Output formatting string, false when not set.
100
	 * @see setOutputFormat()
101
	 * @var mixed
102
	 */
103
	protected $m_outformat = false;
104
105
	/**
106
	 * Used to control the addition of the standard search link.
107
	 * @var boolean
108
	 */
109
	private $mHasSearchLink;
110
111
	/**
112
	 * Used to control service link creation.
113
	 * @var boolean
114
	 */
115
	private $mHasServiceLinks;
116
117
	/**
118
	 * Array of error text messages. Private to allow us to track error insertion
119
	 * (PHP's count() is too slow when called often) by using $mHasErrors.
120
	 * @var array
121
	 */
122
	private $mErrors = array();
123
124
	/**
125
	 * Boolean indicating if there where any errors.
126
	 * Should be modified accordingly when modifying $mErrors.
127
	 * @var boolean
128
	 */
129
	private $mHasErrors = false;
130
131
	/**
132
	 * @var boolean
133
	 */
134
	private $serviceLinksRenderState = true;
135
136
	/**
137
	 * Extraneous services and object container
138
	 *
139
	 * @var array
140
	 */
141
	private $extraneousFunctions = array();
142
143
	/**
144
	 * @var Options
145
	 */
146
	private $options;
147
148
	/**
149
	 * @var boolean
150
	 */
151
	protected $approximateValue = false;
152
153
	/**
154
	 * @var ValueConstraintValidator
155
	 */
156
	private $valueConstraintValidator = null;
157
158
	/**
159
	 * Constructor.
160
	 *
161
	 * @param string $typeid
162
	 */
163 205
	public function __construct( $typeid ) {
164 205
		$this->m_typeid = $typeid;
165 205
	}
166
167
///// Set methods /////
168
169
	/**
170
	 * Set the user value (and compute other representations if possible).
171
	 * The given value is a string as supplied by some user. An alternative
172
	 * label for printout might also be specified.
173
	 *
174
	 * The third argument was added in SMW 1.9 and should not be used from outside SMW.
175
	 *
176
	 * @param string $value
177
	 * @param mixed $caption
178
	 * @param boolean $approximateValue
179
	 */
180 189
	public function setUserValue( $value, $caption = false, $approximateValue = false ) {
181
182 189
		$this->m_dataitem = null;
183 189
		$this->mErrors = array(); // clear errors
184 189
		$this->mHasErrors = false;
185 189
		$this->m_infolinks = array(); // clear links
186 189
		$this->mHasSearchLink = false;
187 189
		$this->mHasServiceLinks = false;
188 189
		$this->m_caption = is_string( $caption ) ? trim( $caption ) : false;
189 189
		$this->approximateValue = $approximateValue;
190
191
192 189
		$this->parseUserValue( $value ); // may set caption if not set yet, depending on datavalue
193
194
		// The following checks for Strip markers generated by MediaWiki to handle special content,
195
		// from parser and extension tags e.g. <pre>,<nowiki>,<math>,<source>.
196
		// See https://en.wikipedia.org/wiki/Help:Strip_markers
197
		// In general, we are not prepared to handle such content properly, and we
198
		// also have no means of obtaining the user input at this point. Hence the assignment
199
		// just fails, even if parseUserValue() above might not have noticed this issue.
200
		// Note: \x07 was used in MediaWiki 1.11.0, \x7f is used now (backwards compatiblity, b/c)
201 189
		if ( ( strpos( $value, "\x7f" ) !== false ) || ( strpos( $value, "\x07" ) !== false ) ) {
202
			$this->addError( wfMessage( 'smw_parseerror' )->inContentLanguage()->text() );
203
		}
204
205 189
		if ( $this->isValid() && !$approximateValue ) {
206 188
			$this->checkAllowedValues();
207
		}
208
209 189
	}
210
211
	/**
212
	 * Set the actual data contained in this object. The method returns
213
	 * true if this was successful (requiring the type of the dataitem
214
	 * to match the data value). If false is returned, the data value is
215
	 * left unchanged (the data item was rejected).
216
	 *
217
	 * @note Even if this function returns true, the data value object
218
	 * might become invalid if the content of the data item caused errors
219
	 * in spite of it being of the right basic type. False is only returned
220
	 * if the data item is fundamentally incompatible with the data value.
221
	 *
222
	 * @param $dataitem SMWDataItem
223
	 * @return boolean
224
	 */
225 146
	public function setDataItem( SMWDataItem $dataItem ) {
226 146
		$this->m_dataitem = null;
227 146
		$this->mErrors = $this->m_infolinks = array();
228 146
		$this->mHasErrors = $this->mHasSearchLink = $this->mHasServiceLinks = $this->m_caption = false;
229 146
		return $this->loadDataItem( $dataItem );
230
	}
231
232
	/**
233
	 * Specify the property to which this value refers. Property pages are
234
	 * used to make settings that affect parsing and display, hence it is
235
	 * sometimes needed to know them.
236
	 *
237
	 * @since 1.6
238
	 *
239
	 * @param SMWDIProperty $property
240
	 */
241 184
	public function setProperty( SMWDIProperty $property ) {
242 184
		$this->m_property = $property;
243 184
	}
244
245
	/**
246
	 * Returns the property to which this value refers.
247
	 *
248
	 * @since 1.8
249
	 *
250
	 * @return SMWDIProperty|null
251
	 */
252 198
	public function getProperty() {
253 198
		return $this->m_property;
254
	}
255
256
	/**
257
	 * Specify the wiki page to which this value refers. This information is
258
	 * used to parse user values such as "#subsection" which only make sense
259
	 * when used on a certain page.
260
	 *
261
	 * @since 1.7
262
	 *
263
	 * @param SMWDIWikiPage|null $contextPage
264
	 */
265 180
	public function setContextPage( SMWDIWikiPage $contextPage = null ) {
266 180
		$this->m_contextPage = $contextPage;
267
268 180
		$this->setOption(
269 180
			'content.language',
270 180
			Localizer::getInstance()->getPreferredContentLanguage( $contextPage )->getCode()
271
		);
272 180
	}
273
274
	/**
275
	 * @since 2.4
276
	 *
277
	 * @return DIWikiPage|null
278
	 */
279 173
	public function getContextPage() {
280 173
		return $this->m_contextPage;
281
	}
282
283
	/**
284
	 * @since 2.4
285
	 *
286
	 * @return Options $options
287
	 */
288 202
	public function setOptions( Options $options ) {
289 202
		foreach ( $options->getOptions() as $key => $value ) {
290 202
			$this->setOption( $key, $value );
291
		}
292 202
	}
293
294
	/**
295
	 * @since 2.4
296
	 *
297
	 * @return string $key
298
	 * @param mxied $value
299
	 */
300 202
	public function setOption( $key, $value ) {
301
302 202
		if ( $this->options === null ) {
303 202
			$this->options = new Options();
304
		}
305
306 202
		$this->options->set( $key, $value );
307 202
	}
308
309
	/**
310
	 * @since 2.4
311
	 *
312
	 * @param string $key
313
	 *
314
	 * @return mixed|false
315
	 */
316 187
	public function getOptionValueFor( $key ) {
317
318 187
		if ( $this->options !== null && $this->options->has( $key ) ) {
319 187
			return $this->options->get( $key );
320
		}
321
322 60
		return false;
323
	}
324
325
	/**
326
	 * @since 2.4
327
	 *
328
	 * @param integer $feature
329
	 *
330
	 * @return boolean
331
	 */
332 185
	public function isEnabledFeature( $feature ) {
333 185
		return ( $this->getOptionValueFor( 'smwgDVFeatures' ) & $feature ) != 0;
334
	}
335
336
	/**
337
	 * Change the caption (the text used for displaying this datavalue). The given
338
	 * value must be a string.
339
	 *
340
	 * @param string $caption
341
	 */
342 92
	public function setCaption( $caption ) {
343 92
		$this->m_caption = $caption;
344 92
	}
345
346
	/**
347
	 * @since 2.4
348
	 *
349
	 * @param string $caption
350
	 */
351 85
	public function getCaption() {
352 85
		return $this->m_caption;
353
	}
354
355
	/**
356
	 * Adds a single SMWInfolink object to the m_infolinks array.
357
	 *
358
	 * @param SMWInfolink $link
359
	 */
360
	public function addInfolink( SMWInfolink $link ) {
361
		$this->m_infolinks[] = $link;
362
	}
363
364
	/**
365
	 * Servicelinks are special kinds of infolinks that are created from
366
	 * current parameters and in-wiki specification of URL templates. This
367
	 * method adds the current property's servicelinks found in the
368
	 * messages. The number and content of the parameters is depending on
369
	 * the datatype, and the service link message is usually crafted with a
370
	 * particular datatype in mind.
371
	 */
372 3
	public function addServiceLinks() {
373 3
		if ( $this->mHasServiceLinks ) {
374
			return;
375
		}
376
377 3
		if ( !is_null( $this->m_property ) ) {
378 3
			$propertyDiWikiPage = $this->m_property->getDiWikiPage();
379
		}
380
381 3
		if ( is_null( $this->m_property ) || is_null( $propertyDiWikiPage ) ) {
0 ignored issues
show
The variable $propertyDiWikiPage does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
382
			return; // no property known, or not associated with a page
383
		}
384
385 3
		$args = $this->getServiceLinkParams();
386
387 3
		if ( $args === false ) {
388 3
			return; // no services supported
389
		}
390
391
		array_unshift( $args, '' ); // add a 0 element as placeholder
392
		$servicelinks = \SMW\StoreFactory::getStore()->getPropertyValues( $propertyDiWikiPage, new SMW\DIProperty( '_SERV' ) );
393
394
		foreach ( $servicelinks as $dataItem ) {
395
			if ( !( $dataItem instanceof SMWDIBlob ) ) {
396
				continue;
397
			}
398
399
			$args[0] = 'smw_service_' . str_replace( ' ', '_', $dataItem->getString() ); // messages distinguish ' ' from '_'
400
			$text = call_user_func_array( 'wfMessage', $args )->inContentLanguage()->text();
401
			$links = preg_split( "/[\n][\s]?/u", $text );
402
403
			foreach ( $links as $link ) {
404
				$linkdat = explode( '|', $link, 2 );
405
406
				if ( count( $linkdat ) == 2 ) {
407
					$this->addInfolink( SMWInfolink::newExternalLink( $linkdat[0], trim( $linkdat[1] ) ) );
408
				}
409
			}
410
		}
411
		$this->mHasServiceLinks = true;
412
	}
413
414
	/**
415
	 * Define a particular output format. Output formats are user-supplied strings
416
	 * that the datavalue may (or may not) use to customise its return value. For
417
	 * example, quantities with units of measurement may interpret the string as
418
	 * a desired output unit. In other cases, the output format might be built-in
419
	 * and subject to internationalisation (which the datavalue has to implement).
420
	 * In any case, an empty string resets the output format to the default.
421
	 *
422
	 * There is one predefined output format that all datavalues should respect: the
423
	 * format '-' indicates "plain" output that is most useful for further processing
424
	 * the value in a template. It should not use any wiki markup or beautification,
425
	 * and it should also avoid localization to the current language. When users
426
	 * explicitly specify an empty format string in a query, it is normalized to "-"
427
	 * to avoid confusion. Note that empty format strings are not interpreted in
428
	 * this way when directly passed to this function.
429
	 *
430
	 * @param string $formatString
431
	 */
432 94
	public function setOutputFormat( $formatString ) {
433 94
		$this->m_outformat = $formatString; // just store it, subclasses may or may not use this
434 94
	}
435
436
	/**
437
	 * @since 2.4
438
	 *
439
	 * @return string
440
	 */
441 46
	public function getOutputFormat() {
442 46
		return $this->m_outformat;
443
	}
444
445
	/**
446
	 * Add a new error string or array of such strings to the error list.
447
	 *
448
	 * @note Errors should not be escaped here in any way, in contradiction to what
449
	 * the docs used to say here in 1.5 and before. Escaping should happen at the output.
450
	 *
451
	 * @param mixed $error A single string, or array of strings.
452
	 */
453 116
	public function addError( $error ) {
454 116
		if ( is_array( $error ) ) {
455 94
			$this->mErrors = array_merge( $this->mErrors, $error );
456 94
			$this->mHasErrors = $this->mHasErrors || ( count( $error ) > 0 );
457
		} else {
458 32
			$this->mErrors[] = $error;
459 32
			$this->mHasErrors = true;
460
		}
461 116
	}
462
463
	/**
464
	 * @since 2.4
465
	 *
466
	 * @param $parameters
467
	 * @param integer|null $type
468
	 * @param integer|null $language
469
	 */
470 19
	public function addErrorMsg( $parameters, $type = null, $language = null ) {
471 19
		$this->addError( Message::get( $parameters, $type, $language ) );
472 19
	}
473
474
	/**
475
	 * @since 2.4
476
	 */
477
	public function clearErrors() {
478
		$this->mErrors = array();
479
		$this->mHasErrors = false;
480
	}
481
482
///// Abstract processing methods /////
483
484
	/**
485
	 * Initialise the datavalue from the given value string.
486
	 * The format of this strings might be any acceptable user input
487
	 * and especially includes the output of getWikiValue().
488
	 *
489
	 * @param string $value
490
	 */
491
	abstract protected function parseUserValue( $value );
492
493
	/**
494
	 * Set the actual data contained in this object. The method returns
495
	 * true if this was successful (requiring the type of the dataitem
496
	 * to match the data value). If false is returned, the data value is
497
	 * left unchanged (the data item was rejected).
498
	 *
499
	 * @note Even if this function returns true, the data value object
500
	 * might become invalid if the content of the data item caused errors
501
	 * in spite of it being of the right basic type. False is only returned
502
	 * if the data item is fundamentally incompatible with the data value.
503
	 *
504
	 * @since 1.6
505
	 *
506
	 * @param SMWDataItem $dataItem
507
	 *
508
	 * @return boolean
509
	 */
510
	abstract protected function loadDataItem( SMWDataItem $dataItem );
511
512
513
///// Query support /////
514
515
	/**
516
	 * @see DataValueDescriptionDeserializer::deserialize
517
	 *
518
	 * @note Descriptions of values need to know their property to be able to
519
	 * create a parsable wikitext version of a query condition again. Thus it
520
	 * might be necessary to call setProperty() before using this method.
521
	 *
522
	 * @param string $value
523
	 *
524
	 * @return Description
525
	 * @throws InvalidArgumentException
526
	 */
527 93
	public function getQueryDescription( $value ) {
528
529 93
		$descriptionDeserializer = DVDescriptionDeserializerRegistry::getInstance()->getDescriptionDeserializerFor( $this );
530 93
		$description = $descriptionDeserializer->deserialize( $value );
531
532 93
		foreach ( $descriptionDeserializer->getErrors() as $error ) {
533 1
			$this->addError( $error );
534
		}
535
536 93
		return $description;
537
	}
538
539
	/**
540
	 * Returns a DataValueFormatter that was matched and dispatched for the current
541
	 * DV instance.
542
	 *
543
	 * @since 2.4
544
	 *
545
	 * @return DataValueFormatter
546
	 */
547 115
	public function getDataValueFormatter() {
548 115
		return ValueFormatterRegistry::getInstance()->getDataValueFormatterFor( $this );
549
	}
550
551
	/**
552
	 * @since 2.4
553
	 *
554
	 * @return PropertySpecificationLookup
555
	 */
556 174
	public function getPropertySpecificationLookup() {
557 174
		return ApplicationFactory::getInstance()->getPropertySpecificationLookup();
558
	}
559
560
	/**
561
	 * @deprecated 2.3
562
	 * @see DescriptionDeserializer::prepareValue
563
	 *
564
	 * This method should no longer be used for direct public access, instead a
565
	 * DataValue is expected to register a DescriptionDeserializer with
566
	 * DVDescriptionDeserializerRegistry.
567
	 *
568
	 * FIXME as of 2.3, SMGeoCoordsValue still uses this method and requires
569
	 * migration before 3.0
570
	 */
571
	static public function prepareValue( &$value, &$comparator ) {
572
		$comparator = QueryComparator::getInstance()->extractComparatorFromString( $value );
573
	}
574
575
///// Get methods /////
576
577
	/**
578
	 * Get the actual data contained in this object or null if the data is
579
	 * not defined (due to errors or due to not being set at all).
580
	 * @note Most implementations ensure that a data item is always set,
581
	 * even if errors occurred, to avoid additional checks for not
582
	 * accessing null. Hence, one must not assume that a non-null return
583
	 * value here implies that isValid() returns true.
584
	 *
585
	 * @since 1.6
586
	 *
587
	 * @return SMWDataItem|SMWDIError
588
	 */
589 191
	public function getDataItem() {
590
591 191
		if ( $this->isValid() ) {
592 191
			return $this->m_dataitem;
593
		}
594
595 1
		return new SMWDIError( $this->mErrors );
596
	}
597
598
	/**
599
	 * @since 2.2
600
	 *
601
	 * @return string
602
	 */
603
	public function __toString() {
604
		return $this->getDataItem()->getSerialization();
605
	}
606
607
	/**
608
	 * Returns a short textual representation for this data value. If the value
609
	 * was initialised from a user supplied string, then this original string
610
	 * should be reflected in this short version (i.e. no normalisation should
611
	 * normally happen). There might, however, be additional parts such as code
612
	 * for generating tooltips. The output is in wiki text.
613
	 *
614
	 * The parameter $linked controls linking of values such as titles and should
615
	 * be non-NULL and non-false if this is desired.
616
	 */
617
	abstract public function getShortWikiText( $linked = null );
618
619
	/**
620
	 * Returns a short textual representation for this data value. If the value
621
	 * was initialised from a user supplied string, then this original string
622
	 * should be reflected in this short version (i.e. no normalisation should
623
	 * normally happen). There might, however, be additional parts such as code
624
	 * for generating tooltips. The output is in HTML text.
625
	 *
626
	 * The parameter $linker controls linking of values such as titles and should
627
	 * be some Linker object (or NULL for no linking).
628
	 */
629
	abstract public function getShortHTMLText( $linker = null );
630
631
	/**
632
	 * Return the long textual description of the value, as printed for
633
	 * example in the factbox. If errors occurred, return the error message
634
	 * The result always is a wiki-source string.
635
	 *
636
	 * The parameter $linked controls linking of values such as titles and should
637
	 * be non-NULL and non-false if this is desired.
638
	 */
639
	abstract public function getLongWikiText( $linked = null );
640
641
	/**
642
	 * Return the long textual description of the value, as printed for
643
	 * example in the factbox. If errors occurred, return the error message
644
	 * The result always is an HTML string.
645
	 *
646
	 * The parameter $linker controls linking of values such as titles and should
647
	 * be some Linker object (or NULL for no linking).
648
	 */
649
	abstract public function getLongHTMLText( $linker = null );
650
651
	/**
652
	 * Returns a short textual representation for this data value. If the value
653
	 * was initialised from a user supplied string, then this original string
654
	 * should be reflected in this short version (i.e. no normalisation should
655
	 * normally happen). There might, however, be additional parts such as code
656
	 * for generating tooltips. The output is in the specified format.
657
	 *
658
	 * The parameter $linker controls linking of values such as titles and should
659
	 * be some Linker object (for HTML output), or NULL for no linking.
660
	 */
661 47
	public function getShortText( $outputformat, $linker = null ) {
662
		switch ( $outputformat ) {
663 47
			case SMW_OUTPUT_WIKI:
664 47
				return $this->getShortWikiText( $linker );
665
			case SMW_OUTPUT_HTML:
666
			case SMW_OUTPUT_FILE:
667
			default:
668
				return $this->getShortHTMLText( $linker );
669
		}
670
	}
671
672
	/**
673
	 * Return the long textual description of the value, as printed for
674
	 * example in the factbox. If errors occurred, return the error message.
675
	 * The output is in the specified format.
676
	 *
677
	 * The parameter $linker controls linking of values such as titles and should
678
	 * be some Linker object (for HTML output), or NULL for no linking.
679
	 */
680
	public function getLongText( $outputformat, $linker = null ) {
681
		switch ( $outputformat ) {
682
			case SMW_OUTPUT_WIKI:
683
				return $this->getLongWikiText( $linker );
684
			case SMW_OUTPUT_HTML:
685
			case SMW_OUTPUT_FILE:
686
			default:
687
				return $this->getLongHTMLText( $linker );
688
		}
689
	}
690
691
	/**
692
	 * Return text serialisation of info links. Ensures more uniform layout
693
	 * throughout wiki (Factbox, Property pages, ...).
694
	 *
695
	 * @param integer $outputformat Element of the SMW_OUTPUT_ enum
696
	 * @param $linker
697
	 *
698
	 * @return string
699
	 */
700 4
	public function getInfolinkText( $outputformat, $linker = null ) {
701 4
		$result = '';
702 4
		$first = true;
703 4
		$extralinks = array();
704
705
		switch ( $outputformat ) {
706 4
			case SMW_OUTPUT_WIKI:
707 1
				foreach ( $this->getInfolinks() as $link ) {
708 1
					if ( $first ) {
709 1
						$result .= '<!-- -->  ' . $link->getWikiText();
710
							// the comment is needed to prevent MediaWiki from linking URL-strings together with the nbsps!
711 1
						$first = false;
712
					} else {
713 1
						$extralinks[] = $link->getWikiText();
714
					}
715
				}
716 1
				break;
717
718 3
			case SMW_OUTPUT_HTML: case SMW_OUTPUT_FILE: default:
719 3
				foreach ( $this->getInfolinks() as $link ) {
720 3
					if ( $first ) {
721 3
						$result .= '&#160;&#160;' . $link->getHTML( $linker );
722 3
						$first = false;
723
					} else {
724 3
						$extralinks[] = $link->getHTML( $linker );
725
					}
726
				}
727 3
				break;
728
		}
729
730 4
		if ( count( $extralinks ) > 0 ) {
731
			$result .= smwfEncodeMessages( $extralinks, 'service', '', false );
732
		}
733
734
		// #1453 SMW::on/off will break any potential link therefore just don't even try
735 4
		return strpos( $result, 'SMW::off' ) !== false || strpos( $result, 'SMW::on' ) !== false ? '' : $result;
736
	}
737
738
	/**
739
	 * Return the plain wiki version of the value, or
740
	 * FALSE if no such version is available. The returned
741
	 * string suffices to reobtain the same DataValue
742
	 * when passing it as an input string to setUserValue().
743
	 */
744
	abstract public function getWikiValue();
745
746
	/**
747
	 * Return a short string that unambiguously specify the type of this
748
	 * value. This value will globally be used to identify the type of a
749
	 * value (in spite of the class it actually belongs to, which can still
750
	 * implement various types).
751
	 */
752 128
	public function getTypeID() {
753 128
		return $this->m_typeid;
754
	}
755
756
	/**
757
	 * @since 2.1
758
	 * @param boolean $renderState
759
	 */
760 1
	public function setServiceLinksRenderState( $renderState = true ) {
761 1
		$this->serviceLinksRenderState = $renderState;
762 1
	}
763
764
	/**
765
	 * Return an array of SMWLink objects that provide additional resources
766
	 * for the given value. Captions can contain some HTML markup which is
767
	 * admissible for wiki text, but no more. Result might have no entries
768
	 * but is always an array.
769
	 */
770 4
	public function getInfolinks() {
771 4
		if ( $this->isValid() && !is_null( $this->m_property ) ) {
772 4
			if ( !$this->mHasSearchLink ) { // add default search link
773 4
				$this->mHasSearchLink = true;
774 4
				$this->m_infolinks[] = SMWInfolink::newPropertySearchLink( '+',
775 4
					$this->m_property->getLabel(), $this->getWikiValue() );
776
			}
777
778 4
			if ( !$this->mHasServiceLinks && $this->serviceLinksRenderState ) { // add further service links
779 3
				$this->addServiceLinks();
780
			}
781
		}
782
783 4
		return $this->m_infolinks;
784
	}
785
786
	/**
787
	 * Overwritten by callers to supply an array of parameters that can be used for
788
	 * creating servicelinks. The number and content of values in the parameter array
789
	 * may vary, depending on the concrete datatype.
790
	 */
791 3
	protected function getServiceLinkParams() {
792 3
		return false;
793
	}
794
795
	/**
796
	 * Return a string that identifies the value of the object, and that can
797
	 * be used to compare different value objects.
798
	 * Possibly overwritten by subclasses (e.g. to ensure that returned
799
	 * value is normalized first)
800
	 *
801
	 * @return string
802
	 */
803
	public function getHash() {
804
		return $this->isValid() ? $this->m_dataitem->getHash() : implode( "\t", $this->mErrors );
805
	}
806
807
	/**
808
	 * Convenience method that checks if the value that is used to sort
809
	 * data of this type is numeric. This only works if the value is set.
810
	 *
811
	 * @return boolean
812
	 */
813
	public function isNumeric() {
814
		if ( isset( $this->m_dataitem ) ) {
815
			return is_numeric( $this->m_dataitem->getSortKey() );
816
		} else {
817
			return false;
818
		}
819
	}
820
821
	/**
822
	 * Return true if a value was defined and understood by the given type,
823
	 * and false if parsing errors occurred or no value was given.
824
	 *
825
	 * @return boolean
826
	 */
827 201
	public function isValid() {
828 201
		return !$this->mHasErrors && isset( $this->m_dataitem );
829
	}
830
831
	/**
832
	 * Whether a datavalue can be used or not (can be made more restrictive then
833
	 * isValid).
834
	 *
835
	 * @note Validity defines a processable state without any technical restrictions
836
	 * while usability is determined by its accessibility to a context
837
	 * (permission, convention etc.)
838
	 *
839
	 * @since  2.2
840
	 *
841
	 * @return boolean
842
	 */
843 162
	public function canUse() {
844 162
		return true;
845
	}
846
847
	/**
848
	 * @note Normally set by the DataValueFactory, or during tests
849
	 *
850
	 * @since 2.3
851
	 *
852
	 * @param array
853
	 */
854 202
	public function setExtraneousFunctions( array $extraneousFunctions ) {
855 202
		$this->extraneousFunctions = $extraneousFunctions;
856 202
	}
857
858
	/**
859
	 * @since 2.3
860
	 *
861
	 * @param string $name
862
	 * @param array $parameters
863
	 *
864
	 * @return mixed
865
	 * @throws RuntimeException
866
	 */
867
	public function getExtraneousFunctionFor( $name, array $parameters = array() ) {
868
869
		if ( isset( $this->extraneousFunctions[$name] ) && is_callable( $this->extraneousFunctions[$name] ) ) {
870
			return call_user_func_array( $this->extraneousFunctions[$name], $parameters );
871
		}
872
873
		throw new RuntimeException( "$name is not registered as extraneous function." );
874
	}
875
876
	/**
877
	 * Return a string that displays all error messages as a tooltip, or
878
	 * an empty string if no errors happened.
879
	 *
880
	 * @return string
881
	 */
882 13
	public function getErrorText() {
883 13
		return smwfEncodeMessages( $this->mErrors );
884
	}
885
886
	/**
887
	 * Return an array of error messages, or an empty array
888
	 * if no errors occurred.
889
	 *
890
	 * @return array
891
	 */
892 158
	public function getErrors() {
893 158
		return $this->mErrors;
894
	}
895
896
	/**
897
	 * Check if property is range restricted and, if so, whether the current value is allowed.
898
	 * Creates an error if the value is illegal.
899
	 */
900 188
	protected function checkAllowedValues() {
901 188
		ValueValidatorRegistry::getInstance()->getConstraintValueValidator()->validate( $this );
902 188
	}
903
904
	/**
905
	 * @since 2.4
906
	 *
907
	 * @param string $value
908
	 *
909
	 * @return string
910
	 */
911 36
	protected function convertDoubleWidth( $value ) {
912 36
		return Localizer::convertDoubleWidth( $value );
913
	}
914
915
}
916