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 Html; |
||
6 | use Sanitizer; |
||
7 | use SMWDataItem; |
||
8 | use SMWQueryResult; |
||
9 | use SMWResultArray; |
||
10 | |||
11 | /** |
||
12 | * Print query results in lists. |
||
13 | * |
||
14 | * @author Markus Krötzsch |
||
15 | * @ingroup SMWQuery |
||
16 | */ |
||
17 | |||
18 | /** |
||
19 | * New implementation of SMW's printer for results in lists. |
||
20 | * The implementation covers comma-separated lists, ordered and unordered lists. |
||
21 | * List items may be formatted using templates, and list output can be in |
||
22 | * multiple columns (at least for ordered and unordered lists). |
||
23 | * |
||
24 | * In the code below, one list item (with all extra information displayed for |
||
25 | * it) is called a "row", while one entry in this row is called a "field" to |
||
26 | * avoid confusion with the "columns" that we have in multi-column display. |
||
27 | * Every field may in turn contain many "values". |
||
28 | * |
||
29 | * @ingroup SMWQuery |
||
30 | */ |
||
31 | class ListResultPrinter extends ResultPrinter { |
||
32 | |||
33 | protected $mTemplate; |
||
34 | protected $mNamedArgs; |
||
35 | protected $mUserParam; |
||
36 | protected $mColumns; |
||
37 | protected $mIntroTemplate; |
||
38 | protected $mOutroTemplate; |
||
39 | |||
40 | /** |
||
41 | * The text used to start the list. |
||
42 | * @var string |
||
43 | * @since 1.9 |
||
44 | */ |
||
45 | protected $header; |
||
46 | /** |
||
47 | * The text used to end the list. |
||
48 | * @var string |
||
49 | * @since 1.9 |
||
50 | */ |
||
51 | protected $footer; |
||
52 | /** |
||
53 | * The text used to start a row in the list. |
||
54 | * @var string |
||
55 | * @since 1.9 |
||
56 | */ |
||
57 | protected $rowstart; |
||
58 | /** |
||
59 | * The text used to end a row in the list. |
||
60 | * @var string |
||
61 | * @since 1.9 |
||
62 | */ |
||
63 | protected $rowend; |
||
64 | /** |
||
65 | * The text used to separate items in the list, other than the final |
||
66 | * one. |
||
67 | * @var string |
||
68 | * @since 1.9 |
||
69 | */ |
||
70 | protected $listsep; |
||
71 | /** |
||
72 | * The text used to separate the last item in the list from the rest. |
||
73 | * @var string |
||
74 | * @since 1.9 |
||
75 | */ |
||
76 | protected $finallistsep; |
||
77 | /** |
||
78 | * Width (in percent) of columns in multi-column display. |
||
79 | * @var integer |
||
80 | * @since 1.9 |
||
81 | */ |
||
82 | protected $columnWidth; |
||
83 | /** |
||
84 | * Number of results per column in multi-column display. |
||
85 | * @var integer |
||
86 | * @since 1.9 |
||
87 | */ |
||
88 | protected $rowsPerColumn; |
||
89 | /** |
||
90 | * Number of results in current column in multi-column display. |
||
91 | * @var integer |
||
92 | * @since 1.9 |
||
93 | */ |
||
94 | protected $numRowsInColumn; |
||
95 | /** |
||
96 | * Number of results printed so far (equals index of result |
||
97 | * to print next). |
||
98 | * @var integer |
||
99 | * @since 1.9 |
||
100 | */ |
||
101 | protected $numRows; |
||
102 | |||
103 | |||
104 | /** |
||
105 | * @see SMWResultPrinter::handleParameters |
||
106 | * |
||
107 | * @since 1.6 |
||
108 | * |
||
109 | * @param array $params |
||
110 | * @param $outputmode |
||
111 | */ |
||
112 | 23 | protected function handleParameters( array $params, $outputmode ) { |
|
113 | 23 | parent::handleParameters( $params, $outputmode ); |
|
114 | |||
115 | 23 | $this->mTemplate = trim( $params['template'] ); |
|
116 | 23 | $this->mNamedArgs = $params['named args']; |
|
117 | 23 | $this->mUserParam = trim( $params['userparam'] ); |
|
118 | 23 | $this->mColumns = !$this->isPlainlist() ? $params['columns'] : 1; |
|
119 | 23 | $this->mIntroTemplate = $params['introtemplate']; |
|
120 | 23 | $this->mOutroTemplate = $params['outrotemplate']; |
|
121 | 23 | } |
|
122 | |||
123 | /** |
||
124 | * @see SMW\ResultPrinter::getName |
||
125 | * |
||
126 | */ |
||
127 | public function getName() { |
||
128 | // Give grep a chance to find the usages: |
||
129 | // smw_printername_list, smw_printername_ol,smw_printername_ul, smw_printername_template |
||
130 | return $this->getContext()->msg( 'smw_printername_' . $this->mFormat )->text(); |
||
131 | } |
||
132 | |||
133 | /** |
||
134 | * @see SMW\ResultPrinter::getResultText |
||
135 | * |
||
136 | * @param SMWQueryResult $queryResult |
||
137 | * @param $outputMode |
||
138 | * |
||
139 | * @return string |
||
140 | */ |
||
141 | 16 | protected function getResultText( SMWQueryResult $queryResult, $outputMode ) { |
|
142 | 16 | if ( $this->mFormat == 'template' && !$this->mTemplate ) { |
|
143 | $queryResult->addErrors( array( |
||
144 | $this->getContext()->msg( 'smw_notemplategiven' )->inContentLanguage()->text() |
||
145 | ) ); |
||
146 | return ''; |
||
147 | } |
||
148 | |||
149 | 16 | $this->templateRenderer = ApplicationFactory::getInstance()->newMwCollaboratorFactory()->newWikitextTemplateRenderer(); |
|
150 | |||
151 | 16 | $this->initializePrintingParameters( $queryResult ); |
|
152 | |||
153 | 16 | $result = ''; |
|
154 | |||
155 | // Set up floating divs if there's more than one column |
||
156 | 16 | if ( $this->mColumns > 1 ) { |
|
157 | $result .= '<div style="float: left; width: ' . $this->columnWidth . '%">' . "\n"; |
||
158 | } |
||
159 | |||
160 | 16 | $result .= $this->header; |
|
161 | |||
162 | 16 | if ( $this->mIntroTemplate !== '' ) { |
|
163 | 1 | $this->addCommonTemplateFields( $queryResult ); |
|
164 | 1 | $this->templateRenderer->packFieldsForTemplate( $this->mIntroTemplate ); |
|
165 | 1 | $result .= $this->templateRenderer->render(); |
|
166 | } |
||
167 | |||
168 | 16 | while ( $row = $queryResult->getNext() ) { |
|
169 | 16 | $result .= $this->getRowText( $row, $queryResult ); |
|
170 | } |
||
171 | |||
172 | 16 | if ( $this->mOutroTemplate !== '' ) { |
|
173 | 1 | $this->addCommonTemplateFields( $queryResult ); |
|
174 | 1 | $this->templateRenderer->packFieldsForTemplate( $this->mOutroTemplate ); |
|
175 | 1 | $result .= $this->templateRenderer->render(); |
|
176 | } |
||
177 | |||
178 | // Make label for finding further results |
||
179 | 16 | if ( $this->linkFurtherResults( $queryResult ) && |
|
180 | 16 | ( $this->mFormat != 'ol' || $this->getSearchLabel( SMW_OUTPUT_WIKI ) ) ) { |
|
181 | 1 | $result .= trim( $this->getFurtherResultsText( $queryResult, $outputMode ) ); |
|
182 | } |
||
183 | |||
184 | 16 | $result .= $this->footer; |
|
185 | |||
186 | 16 | if ( $this->mColumns > 1 ) { |
|
187 | $result .= "</div>\n" . '<br style="clear: both" />' . "\n"; |
||
188 | } |
||
189 | |||
190 | // Display default if the result is empty |
||
191 | 16 | if ( $result == '' ) { |
|
192 | 2 | $result = $this->params['default']; |
|
193 | } |
||
194 | |||
195 | 16 | return $result; |
|
196 | } |
||
197 | |||
198 | /** |
||
199 | * Initialize the internal parameters that should be used to print this |
||
200 | * list, and reset row counters. |
||
201 | * |
||
202 | * @since 1.9 |
||
203 | * @param SMWQueryResult $queryResult |
||
204 | */ |
||
205 | 16 | protected function initializePrintingParameters( SMWQueryResult $queryResult ) { |
|
206 | 16 | $this->numRows = 0; |
|
207 | 16 | $this->numRowsInColumn = 0; |
|
208 | 16 | $this->rowSortkey = ''; |
|
209 | |||
210 | 16 | $this->columnWidth = floor( 100 / $this->mColumns ); |
|
0 ignored issues
–
show
|
|||
211 | 16 | $this->rowsPerColumn = ceil( $queryResult->getCount() / $this->mColumns ); |
|
0 ignored issues
–
show
The property
$rowsPerColumn was declared of type integer , but ceil($queryResult->getCount() / $this->mColumns) is of type double . Maybe add a type cast?
This check looks for assignments to scalar types that may be of the wrong type. To ensure the code behaves as expected, it may be a good idea to add an explicit type cast. $answer = 42;
$correct = false;
$correct = (bool) $answer;
Loading history...
|
|||
212 | |||
213 | // Determine mark-up strings used around list items: |
||
214 | 16 | if ( $this->mFormat == 'ul' || $this->mFormat == 'ol' ) { |
|
215 | 1 | $this->header = "<" . $this->mFormat . ">\n"; |
|
216 | 1 | $this->footer = "</" . $this->mFormat . ">\n"; |
|
217 | 1 | $this->rowstart = "\t<li>"; |
|
218 | 1 | $this->rowend = "</li>\n"; |
|
219 | } else { // "list" and "template" format |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
38% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them.
Loading history...
|
|||
220 | 15 | $this->header = ''; |
|
221 | 15 | $this->footer = ''; |
|
222 | 15 | $this->rowstart = ''; |
|
223 | 15 | $this->rowend = ''; |
|
224 | } |
||
225 | |||
226 | // Define separators for list items |
||
227 | 16 | if ( $this->params['format'] !== 'template' ){ |
|
228 | 10 | if ( $this->params['format'] === 'list' && $this->params['sep'] === ',' ){ |
|
229 | // Make default list ", , , and " |
||
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
38% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them.
Loading history...
|
|||
230 | 8 | $this->listsep = ', '; |
|
231 | 8 | $this->finallistsep = $this->getContext()->msg( 'smw_finallistconjunct' )->inContentLanguage()->text() . ' '; |
|
232 | } else { |
||
233 | // Allow "_" for encoding spaces, as documented |
||
234 | 2 | $this->listsep = str_replace( '_', ' ', $this->params['sep'] ); |
|
235 | 10 | $this->finallistsep = $this->listsep; |
|
236 | } |
||
237 | } else { |
||
238 | // No default separators for format "template" |
||
239 | 6 | $this->listsep = ''; |
|
240 | 6 | $this->finallistsep = ''; |
|
241 | } |
||
242 | 16 | } |
|
243 | |||
244 | /** |
||
245 | * Get result text for one result row as part of getResultText(). |
||
246 | * |
||
247 | * @since 1.9 |
||
248 | * @param SMWResultArray[] $row |
||
249 | * @param SMWQueryResult $res |
||
250 | * @return string |
||
251 | */ |
||
252 | 16 | protected function getRowText( array $row, SMWQueryResult $res ) { |
|
253 | 16 | $result = ''; |
|
254 | |||
255 | // Start new column: |
||
256 | 16 | if ( $this->numRowsInColumn == $this->rowsPerColumn ) { |
|
257 | // If it's a numbered list, and it's split |
||
258 | // into columns, add in the 'start=' |
||
259 | // attribute so that each additional column |
||
260 | // starts at the right place. This attribute |
||
261 | // is actually deprecated, but it appears to |
||
262 | // still be supported by the major browsers... |
||
263 | if ( $this->mFormat == 'ol' ) { |
||
264 | $header = "<ol start=\"" . ( $this->numRows + 1 ) . "\">"; |
||
265 | } else { |
||
266 | $header = $this->header; |
||
267 | } |
||
268 | |||
269 | $this->numRowsInColumn = 0; |
||
270 | |||
271 | $result .= $this->footer . '</div>' . |
||
272 | "<div style=\"float: left; width: {$this->columnWidth}%\">" . |
||
273 | $header; |
||
274 | } |
||
275 | |||
276 | 16 | if ( $this->mTemplate !== '' ) { // Build template code |
|
277 | 7 | $this->hasTemplates = true; |
|
278 | |||
279 | 7 | $this->addTemplateContentFields( $row ); |
|
280 | 7 | $this->addCommonTemplateFields( $res ); |
|
281 | 7 | $this->templateRenderer->packFieldsForTemplate( $this->mTemplate ); |
|
282 | |||
283 | 7 | $result .= $this->getRowStart( $res ) . $this->templateRenderer->render(); |
|
284 | } else { // Build simple list |
||
285 | 9 | $content = $this->getRowListContent( $row ); |
|
286 | 9 | $result .= $this->getRowStart( $res ) . $content; |
|
287 | } |
||
288 | |||
289 | 16 | $result .= $this->rowend; |
|
290 | 16 | $this->numRows++; |
|
291 | 16 | $this->numRowsInColumn++; |
|
292 | 16 | $this->rowSortkey = ''; |
|
293 | |||
294 | 16 | return $result; |
|
295 | } |
||
296 | |||
297 | /** |
||
298 | * Returns row start element |
||
299 | * |
||
300 | * @since 1.9 |
||
301 | * |
||
302 | * @param SMWQueryResult $res |
||
303 | * |
||
304 | * @return string |
||
305 | */ |
||
306 | 16 | protected function getRowStart( SMWQueryResult $res ) { |
|
307 | |||
308 | 16 | if ( $this->numRows > 0 && $this->isPlainlist() ) { |
|
309 | // Use comma between "rows" other than the last one: |
||
310 | 4 | return ( $this->numRows <= $res->getCount() ) ? $this->listsep : $this->finallistsep; |
|
311 | } |
||
312 | |||
313 | 16 | if ( $this->rowSortkey !== '' ) { |
|
314 | 1 | return "\t" . Html::openElement( 'li', |
|
315 | 1 | array( 'data-sortkey' => mb_substr( $this->rowSortkey, 0, 1 ) ) |
|
316 | ); |
||
317 | } |
||
318 | |||
319 | 15 | return $this->rowstart; |
|
320 | } |
||
321 | |||
322 | /** |
||
323 | * Returns text for one result row, formatted as a list. |
||
324 | * |
||
325 | * @since 1.9 |
||
326 | * @todo The inner lists of values per field should use different separators. |
||
327 | * @todo Some spaces are hard-coded here; should probably be part of separators. |
||
328 | * @bug Bad HTML tag escaping with hardcoded exceptions (for datatype _qty) |
||
329 | * |
||
330 | * @param SMWResultArray[] $row |
||
331 | * |
||
332 | * @return string |
||
333 | */ |
||
334 | 9 | protected function getRowListContent( array $row ) { |
|
335 | 9 | $firstField = true; // is this the first entry in this row? |
|
336 | 9 | $extraFields = false; // has anything but the first field been printed? |
|
337 | 9 | $result = ''; |
|
338 | |||
339 | 9 | foreach ( $row as $field ) { |
|
340 | 9 | $firstValue = true; // is this the first value in this field? |
|
341 | |||
342 | 9 | while ( ( $dataValue = $field->getNextDataValue() ) !== false ) { |
|
343 | |||
344 | // Add sortkey for all non-list formats |
||
345 | 8 | if ( $firstField && $this->params['format'] !== 'list' && |
|
346 | 8 | $dataValue->getDataItem()->getDIType() === SMWDataItem::TYPE_WIKIPAGE ) { |
|
347 | 1 | $this->rowSortkey = StoreFactory::getStore()->getWikiPageSortKey( $dataValue->getDataItem() ); |
|
348 | } |
||
349 | |||
350 | 8 | $text = $dataValue->getShortText( SMW_OUTPUT_WIKI, $this->getLinker( $firstField ) ); |
|
351 | |||
352 | 8 | if ( !$firstField && !$extraFields ) { // first values after first column |
|
353 | 2 | $result .= ' ('; |
|
354 | 2 | $extraFields = true; |
|
355 | 8 | } elseif ( $extraFields || !$firstValue ) { |
|
356 | // any value after '(' or non-first values on first column |
||
357 | 1 | $result .= $this->listsep . ' '; |
|
358 | } |
||
359 | |||
360 | 8 | if ( $firstValue ) { // first value in any field, print header |
|
361 | 8 | $firstValue = false; |
|
362 | |||
363 | 8 | if ( ( $this->mShowHeaders != SMW_HEADERS_HIDE ) && ( $field->getPrintRequest()->getLabel() !== '' ) ) { |
|
364 | 2 | $result .= $field->getPrintRequest()->getText( SMW_OUTPUT_WIKI, ( $this->mShowHeaders == SMW_HEADERS_PLAIN ? null:$this->mLinker ) ) . ' '; |
|
365 | } |
||
366 | } |
||
367 | |||
368 | // Display the text with tags for all non-list type outputs and |
||
369 | // where the property is of type _qty (to ensure the highlighter |
||
370 | // is displayed) but for others remove tags so that lists are |
||
371 | // not distorted by unresolved in-text tags |
||
372 | // FIXME This is a hack that limits extendibility of SMW datatypes |
||
373 | // by giving _qty a special status that no other type can have. |
||
374 | 8 | if ( $dataValue->getTypeID() === '_qty' || $this->isPlainlist() ) { |
|
375 | 7 | $result .= $text; |
|
376 | } else { |
||
377 | 1 | $result .= Sanitizer::stripAllTags( $text ); |
|
378 | } |
||
379 | } |
||
380 | |||
381 | 9 | $firstField = false; |
|
382 | } |
||
383 | 9 | if ( $extraFields ) { |
|
384 | 2 | $result .= ')'; |
|
385 | } |
||
386 | |||
387 | 9 | return $result; |
|
388 | } |
||
389 | |||
390 | /** |
||
391 | * Returns text for one result row, formatted as a template call. |
||
392 | * |
||
393 | * @since 1.9 |
||
394 | * |
||
395 | * @param $row |
||
396 | * |
||
397 | * @return string |
||
398 | */ |
||
399 | 7 | protected function addTemplateContentFields( $row ) { |
|
400 | |||
401 | 7 | foreach ( $row as $i => $field ) { |
|
402 | |||
403 | 7 | $value = ''; |
|
404 | 7 | $fieldName = ''; |
|
405 | |||
406 | 7 | if ( $this->mNamedArgs ) { |
|
407 | 2 | $fieldName = '?' . $field->getPrintRequest()->getLabel(); |
|
408 | } |
||
409 | |||
410 | 7 | if ( $fieldName === '' || $fieldName === '?' ) { |
|
411 | 7 | $fieldName = $fieldName . $i + 1; |
|
412 | } |
||
413 | |||
414 | 7 | while ( ( $text = $field->getNextText( SMW_OUTPUT_WIKI, $this->getLinker( $i == 0 ) ) ) !== false ) { |
|
415 | 7 | $value .= $value === '' ? $text : $this->params['sep'] . ' ' . $text; |
|
416 | } |
||
417 | |||
418 | 7 | $this->templateRenderer->addField( $fieldName, $value ); |
|
419 | } |
||
420 | |||
421 | 7 | $this->templateRenderer->addField( '#', $this->numRows ); |
|
422 | 7 | } |
|
423 | |||
424 | 7 | protected function addCommonTemplateFields( $queryResult ) { |
|
425 | |||
426 | 7 | if ( $this->mUserParam ) { |
|
427 | 3 | $this->templateRenderer->addField( 'userparam', $this->mUserParam ); |
|
428 | } |
||
429 | |||
430 | 7 | $this->templateRenderer->addField( |
|
431 | 7 | 'smw-resultquerycondition', |
|
432 | 7 | $queryResult->getQuery()->getQueryString() |
|
433 | ); |
||
434 | |||
435 | 7 | $this->templateRenderer->addField( |
|
436 | 7 | 'smw-resultquerylimit', |
|
437 | 7 | $queryResult->getQuery()->getLimit() |
|
438 | ); |
||
439 | |||
440 | 7 | $this->templateRenderer->addField( |
|
441 | 7 | 'smw-resultqueryoffset', |
|
442 | 7 | $queryResult->getQuery()->getOffset() |
|
443 | ); |
||
444 | 7 | } |
|
445 | |||
446 | /** |
||
447 | * Get text for further results link. Used only during getResultText(). |
||
448 | * |
||
449 | * @since 1.9 |
||
450 | * @param SMWQueryResult $res |
||
451 | * @param integer $outputMode |
||
452 | * @return string |
||
453 | */ |
||
454 | 1 | protected function getFurtherResultsText( SMWQueryResult $res, $outputMode ) { |
|
455 | 1 | $link = $this->getFurtherResultsLink( $res, $outputMode ); |
|
456 | 1 | return $this->rowstart . ' ' . |
|
457 | 1 | $link->getText( SMW_OUTPUT_WIKI, $this->mLinker ) . |
|
458 | 1 | $this->rowend; |
|
459 | } |
||
460 | |||
461 | 30 | protected function isPlainlist() { |
|
462 | 30 | return $this->mFormat != 'ul' && $this->mFormat != 'ol'; |
|
463 | } |
||
464 | |||
465 | 30 | public function getParameters() { |
|
466 | 30 | $params = parent::getParameters(); |
|
467 | |||
468 | 30 | $params['sep'] = array( |
|
469 | 'message' => 'smw-paramdesc-sep', |
||
470 | 'default' => ',', |
||
471 | ); |
||
472 | |||
473 | 30 | $params['template'] = array( |
|
474 | 'message' => 'smw-paramdesc-template', |
||
475 | 'default' => '', |
||
476 | ); |
||
477 | |||
478 | 30 | $params['named args'] = array( |
|
479 | 'type' => 'boolean', |
||
480 | 'message' => 'smw-paramdesc-named_args', |
||
481 | 'default' => false, |
||
482 | ); |
||
483 | |||
484 | 30 | if ( !$this->isPlainlist() ) { |
|
485 | 2 | $params['columns'] = array( |
|
486 | 'type' => 'integer', |
||
487 | 'message' => 'smw-paramdesc-columns', |
||
488 | 'default' => 1, |
||
489 | 'range' => array( 1, 10 ), |
||
490 | ); |
||
491 | } |
||
492 | |||
493 | 30 | $params['userparam'] = array( |
|
494 | 'message' => 'smw-paramdesc-userparam', |
||
495 | 'default' => '', |
||
496 | ); |
||
497 | |||
498 | 30 | $params['introtemplate'] = array( |
|
499 | 'message' => 'smw-paramdesc-introtemplate', |
||
500 | 'default' => '', |
||
501 | ); |
||
502 | |||
503 | 30 | $params['outrotemplate'] = array( |
|
504 | 'message' => 'smw-paramdesc-outrotemplate', |
||
505 | 'default' => '', |
||
506 | ); |
||
507 | |||
508 | 30 | $params['import-annotation'] = array( |
|
509 | 'message' => 'smw-paramdesc-import-annotation', |
||
510 | 'type' => 'boolean', |
||
511 | 'default' => false |
||
512 | ); |
||
513 | |||
514 | 30 | return $params; |
|
515 | } |
||
516 | } |
||
517 |
This check looks for assignments to scalar types that may be of the wrong type.
To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.