Completed
Push — master ( 9eae06...a41cb5 )
by mw
16s
created

includes/storage/SMW_ResultArray.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\DataValueFactory;
4
use SMW\InTextAnnotationParser;
5
use SMW\Query\PrintRequest;
6
use SMW\Query\TemporaryEntityListAccumulator;
7
use SMWDataItem as DataItem;
8
use SMWDIBlob as DIBlob;
9
10
/**
11
 * Container for the contents of a single result field of a query result,
12
 * i.e. basically an array of SMWDataItems with some additional parameters.
13
 * The content of the array is fetched on demand only.
14
 *
15
 * @ingroup SMWQuery
16
 *
17
 * @author Markus Krötzsch
18
 * @author Jeroen De Dauw < [email protected] >
19
 */
20
class SMWResultArray {
21
22
	/**
23
	 * @var PrintRequest
24
	 */
25
	private $mPrintRequest;
26
27
	/**
28
	 * @var SMWDIWikiPage
29
	 */
30
	private $mResult;
31
32
	/**
33
	 * @var SMWStore
34
	 */
35
	private $mStore;
36
37
	/**
38
	 * @var SMWDataItem[]|false
39
	 */
40
	private $mContent;
41
42
	/**
43
	 * @var TemporaryEntityListAccumulator|null
44
	 */
45
	private $temporaryEntityListAccumulator;
46
47
	static private $catCacheObj = false;
48
	static private $catCache = false;
49
50
	/**
51
	 * Constructor.
52
	 *
53
	 * @param SMWDIWikiPage $resultPage
54
	 * @param PrintRequest $printRequest
55
	 * @param SMWStore $store
56
	 */
57 81
	public function __construct( SMWDIWikiPage $resultPage, PrintRequest $printRequest, SMWStore $store ) {
58 81
		$this->mResult = $resultPage;
59 81
		$this->mPrintRequest = $printRequest;
60 81
		$this->mStore = $store;
61 81
		$this->mContent = false;
62 81
	}
63
64
	/**
65
	 * Get the SMWStore object that this result is based on.
66
	 *
67
	 * @return SMWStore
68
	 */
69
	public function getStore() {
70
		return $this->mStore;
71
	}
72
73
	/**
74
	 * Returns the SMWDIWikiPage object to which this SMWResultArray refers.
75
	 * If you only care for those objects, consider using SMWQueryResult::getResults()
76
	 * directly.
77
	 *
78
	 * @return SMWDIWikiPage
79
	 */
80 1
	public function getResultSubject() {
81 1
		return $this->mResult;
82
	}
83
84
	/**
85
	 * Temporary track what entities are used while being instantiated, so an external
86
	 * service can have access to the list without requiring to resolve the objects
87
	 * independently.
88
	 *
89
	 * @since  2.4
90
	 *
91
	 * @return TemporaryEntityListAccumulator
92
	 */
93 81
	public function setEntityListAccumulator( TemporaryEntityListAccumulator $temporaryEntityListAccumulator ) {
94 81
		$this->temporaryEntityListAccumulator = $temporaryEntityListAccumulator;
95 81
	}
96
97
	/**
98
	 * Returns an array of SMWDataItem objects that contain the results of
99
	 * the given print request for the given result object.
100
	 *
101
	 * @return SMWDataItem[]|false
102
	 */
103 4
	public function getContent() {
104 4
		$this->loadContent();
105 4
		return $this->mContent;
106
	}
107
108
	/**
109
	 * Return a PrintRequest object describing what is contained in this
110
	 * result set.
111
	 *
112
	 * @return PrintRequest
113
	 */
114 50
	public function getPrintRequest() {
115 50
		return $this->mPrintRequest;
116
	}
117
118
	/**
119
	 * Compatibility alias for getNextDatItem().
120
	 * @deprecated since 1.6. Call getNextDataValue() or getNextDataItem() directly as needed. Method will vanish before SMW 1.7.
121
	 */
122
	public function getNextObject() {
123
		return $this->getNextDataValue();
124
	}
125
126
	/**
127
	 * Return the next SMWDataItem object or false if no further object exists.
128
	 *
129
	 * @since 1.6
130
	 *
131
	 * @return SMWDataItem|false
132
	 */
133 81
	public function getNextDataItem() {
134 81
		$this->loadContent();
135 81
		$result = current( $this->mContent );
136
137 81
		if ( $this->temporaryEntityListAccumulator !== null && $result instanceof DataItem ) {
138 81
			$this->temporaryEntityListAccumulator->addToEntityList( null, $result );
139
		}
140
141 81
		next( $this->mContent );
142 81
		return $result;
143
	}
144
145
	/**
146
	 * Set the internal pointer of the array of SMWDataItem objects to its first
147
	 * element. Return the first SMWDataItem object or false if the array is
148
	 * empty.
149
	 *
150
	 * @since 1.7.1
151
	 *
152
	 * @return SMWDataItem|false
153
	 */
154
	public function reset() {
155
		$this->loadContent();
156
		return reset( $this->mContent );
157
	}
158
159
	/**
160
	 * Return an SMWDataValue object for the next SMWDataItem object or
161
	 * false if no further object exists.
162
	 *
163
	 * @since 1.6
164
	 *
165
	 * @return SMWDataValue|false
166
	 */
167 78
	public function getNextDataValue() {
168 78
		$dataItem = $this->getNextDataItem();
169
170 78
		if ( $dataItem === false ) {
171 77
			return false;
172
		}
173
174 78
		if ( $this->mPrintRequest->getMode() == PrintRequest::PRINT_PROP &&
175 78
		    strpos( $this->mPrintRequest->getTypeID(), '_rec' ) !== false &&
176 78
		     $this->mPrintRequest->getParameter( 'index' ) !== false ) {
177
			// Not efficient, but correct: we need to find the right property for
178
			// the selected index of the record here.
179 3
			$pos = $this->mPrintRequest->getParameter( 'index' ) - 1;
180
181 3
			$recordValue = DataValueFactory::getInstance()->newDataValueByItem(
182
				$dataItem,
183 3
				$this->mPrintRequest->getData()->getDataItem()
184
			);
185
186 3
			$diProperties = $recordValue->getPropertyDataItems();
0 ignored issues
show
The method getPropertyDataItems() does not exist on SMWDataValue. Did you maybe mean getProperty()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
187
188 3
			if ( array_key_exists( $pos, $diProperties ) &&
189 3
				!is_null( $diProperties[$pos] ) ) {
190 3
				$diProperty = $diProperties[$pos];
191
			} else {
192 3
				$diProperty = null;
193
			}
194 78
		} elseif ( $this->mPrintRequest->getMode() == PrintRequest::PRINT_PROP ) {
195 70
			$diProperty = $this->mPrintRequest->getData()->getDataItem();
196
		} else {
197 53
			$diProperty = null;
198
		}
199
200
		// refs #1314
201 78
		if ( $this->mPrintRequest->getMode() == PrintRequest::PRINT_PROP &&
202 78
			strpos( $this->mPrintRequest->getTypeID(), '_txt' ) !== false &&
203 78
			$dataItem instanceof DIBlob ) {
204 18
			$dataItem = new DIBlob(
205 18
				InTextAnnotationParser::removeAnnotation( $dataItem->getString() )
206
			);
207
		}
208
209 78
		$dataValue = DataValueFactory::getInstance()->newDataValueByItem(
210
			$dataItem,
211
			$diProperty
212
		);
213
214 78
		$dataValue->setContextPage(
215 78
			$this->mResult
216
		);
217
218 78
		if ( $this->mPrintRequest->getOutputFormat() ) {
219 15
			$dataValue->setOutputFormat( $this->mPrintRequest->getOutputFormat() );
220
		}
221
222 78
		if ( $this->temporaryEntityListAccumulator !== null && $dataItem instanceof DataItem ) {
223 78
			$this->temporaryEntityListAccumulator->addToEntityList( $diProperty, $dataItem );
224
		}
225
226 78
		return $dataValue;
227
	}
228
229
	/**
230
	 * Return the main text representation of the next SMWDataItem object
231
	 * in the specified format, or false if no further object exists.
232
	 *
233
	 * The parameter $linker controls linking of title values and should
234
	 * be some Linker object (or NULL for no linking).
235
	 *
236
	 * @param integer $outputMode
237
	 * @param mixed $linker
238
	 *
239
	 * @return string|false
240
	 */
241 10
	public function getNextText( $outputMode, $linker = null ) {
242 10
		$dataValue = $this->getNextDataValue();
243 10
		if ( $dataValue !== false ) { // Print data values.
244 10
			return $dataValue->getShortText( $outputMode, $linker );
245
		} else {
246 10
			return false;
247
		}
248
	}
249
250
	/**
251
	 * Load results of the given print request and result subject. This is only
252
	 * done when needed.
253
	 */
254 81
	protected function loadContent() {
255 81
		if ( $this->mContent !== false ) {
256 80
			return;
257
		}
258
259 81
		switch ( $this->mPrintRequest->getMode() ) {
260 81
			case PrintRequest::PRINT_THIS: // NOTE: The limit is ignored here.
261 53
				$this->mContent = array( $this->mResult );
262 53
			break;
263 75
			case PrintRequest::PRINT_CATS:
264
				// Always recompute cache here to ensure output format is respected.
265 3
				self::$catCache = $this->mStore->getPropertyValues( $this->mResult,
266 3
					new SMW\DIProperty( '_INST' ), $this->getRequestOptions( false ) );
267 3
				self::$catCacheObj = $this->mResult->getHash();
268
269 3
				$limit = $this->mPrintRequest->getParameter( 'limit' );
270 3
				$this->mContent = ( $limit === false ) ? ( self::$catCache ) :
271
					array_slice( self::$catCache, 0, $limit );
272 3
			break;
273 74
			case PrintRequest::PRINT_PROP:
274 74
				$propertyValue = $this->mPrintRequest->getData();
275 74
				if ( $propertyValue->isValid() ) {
276 74
					$this->mContent = $this->mStore->getPropertyValues( $this->mResult,
277 74
						$propertyValue->getDataItem(), $this->getRequestOptions() );
278
				} else {
279
					$this->mContent = array();
280
				}
281
282
				// Print one component of a multi-valued string.
283
				// Known limitation: the printrequest still is of type _rec, so if printers check
284
				// for this then they will not recognize that it returns some more concrete type.
285 74
				if ( strpos( $this->mPrintRequest->getTypeID(), '_rec' ) !== false &&
286 74
				     ( $this->mPrintRequest->getParameter( 'index' ) !== false ) ) {
287 3
					$pos = $this->mPrintRequest->getParameter( 'index' ) - 1;
288 3
					$newcontent = array();
289
290 3
					foreach ( $this->mContent as $diContainer ) {
291 3
						/* SMWRecordValue */ $recordValue = DataValueFactory::getInstance()->newDataValueByItem( $diContainer, $propertyValue->getDataItem() );
292 3
						$dataItems = $recordValue->getDataItems();
0 ignored issues
show
The method getDataItems() does not exist on SMWDataValue. Did you maybe mean getDataItem()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
293
294 3
						if ( array_key_exists( $pos, $dataItems ) &&
295 3
							( !is_null( $dataItems[$pos] ) ) ) {
296 3
							$newcontent[] = $dataItems[$pos];
297
						}
298
					}
299
300 3
					$this->mContent = $newcontent;
301
				}
302 74
			break;
303
			case PrintRequest::PRINT_CCAT: ///NOTE: The limit is ignored here.
304
				if ( self::$catCacheObj != $this->mResult->getHash() ) {
305
					self::$catCache = $this->mStore->getPropertyValues( $this->mResult, new SMW\DIProperty( '_INST' ) );
306
					self::$catCacheObj = $this->mResult->getHash();
307
				}
308
309
				$found = false;
310
				$prkey = $this->mPrintRequest->getData()->getDBkey();
311
312
				foreach ( self::$catCache as $cat ) {
313
					if ( $cat->getDBkey() == $prkey ) {
314
						$found = true;
315
						break;
316
					}
317
				}
318
				$this->mContent = array( new SMWDIBoolean( $found ) );
319
			break;
320
			default: $this->mContent = array(); // Unknown print request.
321
		}
322
323 81
		reset( $this->mContent );
324
325 81
	}
326
327
	/**
328
	 * Make a request option object based on the given parameters, and
329
	 * return NULL if no such object is required. The parameter defines
330
	 * if the limit should be taken into account, which is not always desired
331
	 * (especially if results are to be cached for future use).
332
	 *
333
	 * @param boolean $useLimit
334
	 *
335
	 * @return SMWRequestOptions|null
336
	 */
337 75
	protected function getRequestOptions( $useLimit = true ) {
338 75
		$limit = $useLimit ? $this->mPrintRequest->getParameter( 'limit' ) : false;
339 75
		$order = trim( $this->mPrintRequest->getParameter( 'order' ) );
340
341
		// Important: use "!=" for order, since trim() above does never return "false", use "!==" for limit since "0" is meaningful here.
342 75
		if ( ( $limit !== false ) || ( $order != false ) ) {
343 2
			$options = new SMWRequestOptions();
344
345 2
			if ( $limit !== false ) {
346 1
				$options->limit = trim( $limit );
347
			}
348
349 2
			if ( ( $order == 'descending' ) || ( $order == 'reverse' ) || ( $order == 'desc' ) ) {
350 2
				$options->sort = true;
351 2
				$options->ascending = false;
352 1
			} elseif ( ( $order == 'ascending' ) || ( $order == 'asc' ) ) {
353 1
				$options->sort = true;
354 2
				$options->ascending = true;
355
			}
356
		} else {
357 73
			$options = null;
358
		}
359
360 75
		return $options;
361
	}
362
363
}
364