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

includes/datavalues/SMW_DV_Property.php (2 issues)

assigning incompatible types to properties.

Bug Documentation Major

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