Completed
Push — master ( 5d1976...30add5 )
by mw
13s
created

includes/datavalues/SMW_DV_Property.php (2 issues)

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
use SMW\ApplicationFactory;
4
use SMW\DataValueFactory;
5
6
/**
7
 * Objects of this class represent properties in SMW.
8
 *
9
 * This class represents both normal (user-defined) properties and
10
 * predefined ("special") properties. Predefined properties may still
11
 * have a standard label (and associated wiki article) and they will
12
 * behave just like user-defined properties in most cases (e.g. when
13
 * asking for a printout text, a link to the according page is produced).
14
 * It is possible that predefined properties have no visible label at all,
15
 * if they are used only internally and never specified by or shown to
16
 * the user. Those will use their internal ID as DB key, and
17
 * empty texts for most printouts. All other proeprties use their
18
 * canonical DB key (even if they are predefined and have an id).
19
 * Functions are provided to check whether a property is visible or
20
 * user-defined, and to get the internal ID, if any.
21
 *
22
 * @note This datavalue is used only for representing properties and,
23
 * possibly objects/values, but never for subjects (pages as such). Hence
24
 * it does not provide a complete Title-like interface, or support for
25
 * things like sortkey.
26
 *
27
 * @author Markus Krötzsch
28
 * @ingroup SMWDataValues
29
 */
30
class SMWPropertyValue extends SMWDataValue {
31
32
	/**
33
	 * Cache for wiki page value object associated to this property, or
34
	 * null if no such page exists. Use getWikiPageValue() to get the data.
35
	 * @var SMWWikiPageValue
36
	 */
37
	protected $m_wikipage = null;
38
39
	/**
40
	 * Cache for type value of this property, or null if not calculated yet.
41
	 * @var SMWTypesValue
42
	 */
43
	private $mPropTypeValue;
44
45
	/**
46
	 * @var DIProperty
47
	 */
48
	private $inceptiveProperty = null;
49
50
	/**
51
	 * @since 2.4
52
	 *
53
	 * @param string $typeid
54
	 */
55 181
	public function __construct( $typeid ) {
56 181
		parent::__construct( $typeid );
57 181
	}
58
59
	/**
60
	 * Static function for creating a new property object from a
61
	 * propertyname (string) as a user might enter it.
62
	 * @note The resulting property object might be invalid if
63
	 * the provided name is not allowed. An object is returned
64
	 * in any case.
65
	 *
66
	 * @param string $propertyName
67
	 *
68
	 * @return SMWPropertyValue
69
	 */
70 105
	static public function makeUserProperty( $propertyLabel ) {
71 105
		return DataValueFactory::getInstance()->newPropertyValueByLabel( $propertyLabel );
72
	}
73
74
	/**
75
	 * Static function for creating a new property object from a property
76
	 * identifier (string) as it might be used internally. This might be
77
	 * the DB key version of some property title text or the id of a
78
	 * predefined property (such as '_TYPE').
79
	 * @note This function strictly requires an internal identifier, i.e.
80
	 * predefined properties must be referred to by their ID, and '-' is
81
	 * not supported for indicating inverses.
82
	 * @note The resulting property object might be invalid if
83
	 * the provided name is not allowed. An object is returned
84
	 * in any case.
85
	 */
86
	static public function makeProperty( $propertyid ) {
87
		$diProperty = new SMW\DIProperty( $propertyid );
88
		$dvProperty = new SMWPropertyValue( '__pro' );
89
		$dvProperty->setDataItem( $diProperty );
90
		return $dvProperty;
91
	}
92
93
	/**
94
	 * We use the internal wikipage object to store some of this objects data.
95
	 * Clone it to make sure that data can be modified independently from the
96
	 * original object's content.
97
	 */
98 1
	public function __clone() {
99 1
		if ( !is_null( $this->m_wikipage ) ) {
100 1
			$this->m_wikipage = clone $this->m_wikipage;
101
		}
102 1
	}
103
104
	/**
105
	 * @note If the inceptive property and the property referenced in dataItem
106
	 * are not equal then the dataItem represents the end target to which the
107
	 * inceptive property has been redirected.
108
	 *
109
	 * @since 2.4
110
	 *
111
	 * @return DIProperty
112
	 */
113 1
	public function getInceptiveProperty() {
114 1
		return $this->inceptiveProperty;
115
	}
116
117
	/**
118
	 * Extended parsing function to first check whether value refers to pre-defined
119
	 * property, resolve aliases, and set internal property id accordingly.
120
	 * @todo Accept/enforce property namespace.
121
	 */
122 162
	protected function parseUserValue( $value ) {
123 162
		$this->mPropTypeValue = null;
124 162
		$this->m_wikipage = null;
125
126 162
		if ( $this->m_caption === false ) { // always use this as caption
127 162
			$this->m_caption = $value;
128
		}
129 162
		$propertyName = smwfNormalTitleText( ltrim( rtrim( $value, ' ]' ), ' [' ) ); // slightly normalise label
130 162
		$inverse = false;
131 162
		if ( ( $propertyName !== '' ) && ( $propertyName { 0 } == '-' ) ) { // property refers to an inverse
132 8
			$propertyName = smwfNormalTitleText( (string)substr( $value, 1 ) );
133
			/// NOTE The cast is necessary at least in PHP 5.3.3 to get string '' instead of boolean false.
134
			/// NOTE It is necessary to normalize again here, since normalization may uppercase the first letter.
135 8
			$inverse = true;
136
		}
137
138
		try {
139 162
			$this->m_dataitem = SMW\DIProperty::newFromUserLabel( $propertyName, $inverse, $this->m_typeid );
140
		} catch ( SMWDataItemException $e ) { // happens, e.g., when trying to sort queries by property "-"
141
			$this->addError( wfMessage( 'smw_noproperty', $value )->inContentLanguage()->text() );
142
			$this->m_dataitem = new SMW\DIProperty( 'ERROR', false ); // just to have something
143
		}
144
145
		// @see the SMW_DV_PROV_DTITLE explanation
146 162
		if ( $this->isEnabledFeature( SMW_DV_PROV_DTITLE ) ) {
147
			$dataItem = $this->getPropertySpecificationLookup()->getPropertyFromDisplayTitle(
148
				$value
149
			);
150
151
			$this->m_dataitem = $dataItem ? $dataItem : $this->m_dataitem;
152
		}
153
154 162
		$this->inceptiveProperty = $this->m_dataitem;
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->m_dataitem of type object<SMW\DIProperty> is incompatible with the declared type object<DIProperty> of property $inceptiveProperty.

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...
155
156 162
		if ( $this->isEnabledFeature( SMW_DV_PROV_REDI ) ) {
157 160
			$this->m_dataitem = $this->m_dataitem->getRedirectTarget();
158
		}
159 162
	}
160
161
	/**
162
	 * @see SMWDataValue::loadDataItem()
163
	 * @param $dataitem SMWDataItem
164
	 * @return boolean
165
	 */
166 24
	protected function loadDataItem( SMWDataItem $dataItem ) {
167
168 24
		if ( $dataItem->getDIType() !== SMWDataItem::TYPE_PROPERTY ) {
169
			return false;
170
		}
171
172 24
		$this->inceptiveProperty = $dataItem;
0 ignored issues
show
Documentation Bug introduced by
It seems like $dataItem of type object<SMWDataItem> is incompatible with the declared type object<DIProperty> of property $inceptiveProperty.

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...
173 24
		$this->m_dataitem = $dataItem;
174
175 24
		$this->mPropTypeValue = null;
176 24
		unset( $this->m_wikipage );
177 24
		$this->m_caption = false;
178
179 24
		return true;
180
	}
181
182 82
	public function setCaption( $caption ) {
183 82
		parent::setCaption( $caption );
184 82
		if ( $this->getWikiPageValue() instanceof SMWDataValue ) { // pass caption to embedded datavalue (used for printout)
185 82
			$this->m_wikipage->setCaption( $caption );
186
		}
187 82
	}
188
189
	public function setOutputFormat( $formatstring ) {
190
		$this->m_outformat = $formatstring;
191
		if ( $this->m_wikipage instanceof SMWDataValue ) {
192
			$this->m_wikipage->setOutputFormat( $formatstring );
193
		}
194
	}
195
196
	public function setInverse( $isinverse ) {
197
		return $this->m_dataitem = new SMW\DIProperty( $this->m_dataitem->getKey(), ( $isinverse == true ) );
198
	}
199
200
	/**
201
	 * Return a wiki page value that can be used for displaying this
202
	 * property, or null if no such wiki page exists (for predefined
203
	 * properties without any label).
204
	 * @return SMWWikiPageValue or null
205
	 */
206 85
	public function getWikiPageValue() {
207 85
		if ( !isset( $this->m_wikipage ) ) {
208
209 85
			$diWikiPage = $this->m_dataitem->getDiWikiPage();
210
211 85
			if ( $diWikiPage !== null ) {
212 85
				$this->m_wikipage = \SMW\DataValueFactory::getInstance()->newDataItemValue( $diWikiPage, null, $this->m_caption );
213 85
				$this->m_wikipage->setOutputFormat( $this->m_outformat );
214 85
				$this->addError( $this->m_wikipage->getErrors() );
215
			} else { // should rarely happen ($value is only changed if the input $value really was a label for a predefined prop)
216
				$this->m_wikipage = null;
217
			}
218
		}
219
220 85
		return $this->m_wikipage;
221
	}
222
223
	/**
224
	 * Return TRUE if this is a property that can be displayed, and not a pre-defined
225
	 * property that is used only internally and does not even have a user-readable name.
226
	 * @note Every user defined property is necessarily visible.
227
	 */
228 54
	public function isVisible() {
229 54
		return $this->isValid() && ( $this->m_dataitem->isUserDefined() || $this->m_dataitem->getLabel() !== '' );
230
	}
231
232
	/**
233
	 * @since 2.2
234
	 *
235
	 * @return boolean
236
	 */
237 146
	public function canUse() {
238 146
		return $this->isValid() && $this->m_dataitem->isUnrestrictedForUse();
239
	}
240
241 28
	public function getShortWikiText( $linked = null ) {
242
243 28
		if ( $this->isVisible() ) {
244 28
			$wikiPageValue = $this->getWikiPageValue();
245 28
			return is_null( $wikiPageValue ) ? '' : $this->highlightText( $wikiPageValue->getShortWikiText( $linked ) );
246
		}
247
248
		return '';
249
	}
250
251 2
	public function getShortHTMLText( $linked = null ) {
252
253 2
		if ( $this->isVisible() ) {
254 2
			$wikiPageValue = $this->getWikiPageValue();
255 2
			return is_null( $wikiPageValue ) ? '' : $this->highlightText( $wikiPageValue->getShortHTMLText( $linked ), $linked );
256
		}
257
258
		return '';
259
	}
260
261 8
	public function getLongWikiText( $linked = null ) {
262
263 8
		if ( $this->isVisible() ) {
264 8
			$wikiPageValue = $this->getWikiPageValue();
265 8
			return is_null( $wikiPageValue ) ? '' : $this->highlightText( $wikiPageValue->getLongWikiText( $linked ) );
266
		}
267
268
		return '';
269
	}
270
271
	public function getLongHTMLText( $linked = null ) {
272
273
		if ( $this->isVisible() ) {
274
			$wikiPageValue = $this->getWikiPageValue();
275
			return is_null( $wikiPageValue ) ? '' : $this->highlightText( $wikiPageValue->getLongHTMLText( $linked ), $linked );
276
		}
277
278
		return '';
279
	}
280
281 48
	public function getWikiValue() {
282
283 48
		if ( !$this->isVisible() ) {
284
			return '';
285
		}
286
287 48
		if ( $this->getWikiPageValue() !== null && $this->getWikiPageValue()->getDisplayTitle() !== '' ) {
288 1
			return $this->getWikiPageValue()->getDisplayTitle();
289
		}
290
291 48
		return $this->m_dataitem->getLabel();
292
	}
293
294
	/**
295
	 * If this property was not user defined, return the internal ID string referring to
296
	 * that property. Otherwise return FALSE;
297
	 */
298
	public function getPropertyID() {
299
		return $this->m_dataitem->isUserDefined() ? false : $this->m_dataitem->getKey();
300
	}
301
302
	/**
303
	 * Return an SMWTypesValue object representing the datatype of this
304
	 * property.
305
	 * @deprecated Types values are not a good way to exchange SMW type information. They are for input only. Use getPropertyTypeID() if you want the type id. This method will vanish in SMW 1.7.
306
	 */
307
	public function getTypesValue() {
308
		$result = SMWTypesValue::newFromTypeId( $this->getPropertyTypeID() );
309
		if ( !$this->isValid() ) {
310
			$result->addError( $this->getErrors() );
311
		}
312
		return $result;
313
	}
314
315
	/**
316
	 * Convenience method to find the type id of this property. Most callers
317
	 * should rather use SMW\DIProperty::findPropertyTypeId() directly. Note
318
	 * that this is not the same as getTypeID(), which returns the id of
319
	 * this property datavalue.
320
	 *
321
	 * @return string
322
	 */
323 4
	public function getPropertyTypeID() {
324 4
		if ( $this->isValid() ) {
325 4
			return $this->m_dataitem->findPropertyTypeId();
326
		} else {
327
			return '__err';
328
		}
329
	}
330
331
	/**
332
	 * Create special highlighting for hinting at special properties.
333
	 */
334 35
	protected function highlightText( $text, $linker = null ) {
335
336 35
		$propertySpecificationLookup = ApplicationFactory::getInstance()->getPropertySpecificationLookup();
337
338 35
		if ( ( $content = $propertySpecificationLookup->getPropertyDescriptionFor( $this->m_dataitem, $linker ) ) !== '' ) {
339
340 6
			$highlighter = SMW\Highlighter::factory( SMW\Highlighter::TYPE_PROPERTY );
341 6
			$highlighter->setContent( array (
342 6
				'userDefined' => $this->m_dataitem->isUserDefined(),
343 6
				'caption' => $text,
344 6
				'content' => $content !== '' ? $content : wfMessage( 'smw_isspecprop' )->text()
345
			) );
346
347 6
			return $highlighter->getHtml();
348
		}
349
350 31
		return $text;
351
	}
352
353
	/**
354
	 * A function for registering/overwriting predefined properties for SMW. Should be called from
355
	 * within the hook 'smwInitProperties'. Ids should start with three underscores "___" to avoid
356
	 * current and future confusion with SMW built-ins.
357
	 *
358
	 * @deprecated Use SMW\DIProperty::registerProperty(). Will vanish before SMW 1.7.
359
	 */
360
	static public function registerProperty( $id, $typeid, $label = false, $show = false ) {
361
		SMW\DIProperty::registerProperty( $id, $typeid, $label, $show );
362
	}
363
364
	/**
365
	 * Add a new alias label to an existing datatype id. Note that every ID should have a primary
366
	 * label, either provided by SMW or registered with registerDatatype. This function should be
367
	 * called from within the hook 'smwInitDatatypes'.
368
	 *
369
	 * @deprecated Use SMW\DIProperty::registerPropertyAlias(). Will vanish before SMW 1.7.
370
	 */
371
	static public function registerPropertyAlias( $id, $label ) {
372
		SMW\DIProperty::registerPropertyAlias( $id, $label );
373
	}
374
375
	/**
376
	 * @see SMW\DIProperty::isUserDefined()
377
	 *
378
	 * @deprecated since 1.6
379
	 */
380
	public function isUserDefined() {
381
		return $this->m_dataitem->isUserDefined();
382
	}
383
384
	/**
385
	 * @see SMW\DIProperty::isShown()
386
	 *
387
	 * @deprecated since 1.6
388
	 */
389
	public function isShown() {
390
		return $this->m_dataitem->isShown();
391
	}
392
393
	/**
394
	 * @see SMW\DIProperty::isInverse()
395
	 *
396
	 * @deprecated since 1.6
397
	 */
398
	public function isInverse() {
399
		return $this->m_dataitem->isInverse();
400
	}
401
402
	/**
403
	 * Return a DB-key-like string: for visible properties, it is the actual DB key,
404
	 * for internal (invisible) properties, it is the property ID. The value agrees
405
	 * with the first component of getDBkeys() and it can be used in its place.
406
	 * @see SMW\DIProperty::getKey()
407
	 *
408
	 * @deprecated since 1.6
409
	 */
410
	public function getDBkey() {
411
		return $this->m_dataitem->getKey();
412
	}
413
414
	/**
415
	 * @see SMW\DIProperty::getLabel()
416
	 *
417
	 * @deprecated since 1.6
418
	 */
419
	public function getText() {
420
		return $this->m_dataitem->getLabel();
421
	}
422
423
}
424