Completed
Push — master ( 249923...ac15b4 )
by Jeroen De
135:11 queued 115:11
created

formats/timeline/SRF_Timeline.php (1 issue)

Severity

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
 * Print query results in interactive timelines.
4
 *
5
 * @file SRF_Timeline.php
6
 * @ingroup SemanticResultFormats
7
 *
8
 * @author Markus Krötzsch
9
 *
10
 * FIXME: this code is just insane; rewrite from 0 is probably the only way to get it right
11
 */
12
13
/**
14
 * Result printer for timeline data.
15
 * @ingroup SemanticResultFormats
16
 */
17
class SRFTimeline extends SMWResultPrinter {
18
19
	protected $m_tlstart = '';  // name of the start-date property if any
20
	protected $m_tlend = '';  // name of the end-date property if any
21
	protected $m_tlsize = ''; // CSS-compatible size (such as 400px)
22
	protected $m_tlbands = ''; // array of band IDs (MONTH, YEAR, ...)
23
	protected $m_tlpos = ''; // position identifier (start, end, today, middle)
24
	protected $mTemplate;
25
	protected $mNamedArgs;
26
27
	/**
28
	 * @see SMWResultPrinter::handleParameters
29
	 *
30
	 * @since 1.6.3
31
	 *
32
	 * @param array $params
33
	 * @param $outputmode
34
	 */
35 1
	protected function handleParameters( array $params, $outputmode ) {
36 1
		parent::handleParameters( $params, $outputmode );
37
38 1
		$this->mTemplate = trim( $params['template'] );
39 1
		$this->mNamedArgs = $params['named args'];
40 1
		$this->m_tlstart = smwfNormalTitleDBKey( $params['timelinestart'] );
41 1
		$this->m_tlend = smwfNormalTitleDBKey( $params['timelineend'] );
42 1
		$this->m_tlbands = $params['timelinebands'];
43 1
		$this->m_tlpos = strtolower( trim( $params['timelineposition'] ) );
44
45
			// str_replace makes sure this is only one value, not mutliple CSS fields (prevent CSS attacks)
46
			// / FIXME: this is either unsafe or redundant, since Timeline is Wiki-compatible. If the JavaScript makes user inputs to CSS then it is bad even if we block this injection path.
47 1
		$this->m_tlsize = htmlspecialchars( str_replace( ';', ' ', strtolower( $params['timelinesize'] ) ) );
48 1
	}
49
50
	public function getName() {
51
		// Give grep a chance to find the usages:
52
		// srf_printername_timeline, srf_printername_eventline
53
		return wfMessage( 'srf_printername_' . $this->mFormat )->text();
54
	}
55
56 1
	protected function getResultText( SMWQueryResult $res, $outputmode ) {
57
58 1
		SMWOutputs::requireHeadItem( SMW_HEADER_STYLE );
59 1
		SMWOutputs::requireResource( 'ext.srf.timeline' );
60
61 1
		$isEventline = 'eventline' == $this->mFormat;
62 1
		$id = uniqid();
63
64 1
		if ( !$isEventline && ( $this->m_tlstart == '' ) ) { // seek defaults
65 1
			foreach ( $res->getPrintRequests() as $pr ) {
66 1
				if ( ( $pr->getMode() == SMWPrintRequest::PRINT_PROP ) && ( $pr->getTypeID() == '_dat' ) ) {
67 1
					$dataValue = $pr->getData();
68
69 1
					$date_value = $dataValue->getDataItem()->getLabel();
70
71 1
					if ( ( $this->m_tlend == '' ) && ( $this->m_tlstart != '' ) &&
72 1
					     ( $this->m_tlstart != $date_value ) ) {
73
						$this->m_tlend = $date_value;
74 1
					} elseif ( ( $this->m_tlstart == '' ) && ( $this->m_tlend != $date_value ) ) {
75 1
						$this->m_tlstart = $date_value;
76
					}
77
				}
78
			}
79
		}
80
81
		// print header
82 1
		$result = "<div id=\"smwtimeline-$id\" class=\"smwtimeline is-disabled\" style=\"height: $this->m_tlsize\">";
83 1
		$result .= '<span class="smw-overlay-spinner medium" style="top:40%; transform: translate(-50%, -50%);"></span>';
84
85 1
		foreach ( $this->m_tlbands as $band ) {
86 1
			$result .= '<span class="smwtlband" style="display:none;">' . htmlspecialchars( $band ) . '</span>';
87
			// just print any "band" given, the JavaScript will figure out what to make of it
88
		}
89
90
		// print all result rows
91 1
		if ( ( $this->m_tlstart != '' ) || $isEventline ) {
92 1
			$result .= $this->getEventsHTML( $res, $outputmode, $isEventline );
93
		}
94
		// no further results displayed ...
95
96
		// print footer
97 1
		$result .= '</div>';
98
99
		// yes, our code can be viewed as HTML if requested, no more parsing needed
100 1
		$this->isHTML = $outputmode == SMW_OUTPUT_HTML;
101
102 1
		return $result;
103
	}
104
105
	/**
106
	 * Returns the HTML for the events.
107
	 *
108
	 * @since 1.5.3
109
	 *
110
	 * @param SMWQueryResult $res
111
	 * @param $outputmode
112
	 * @param boolean $isEventline
113
	 *
114
	 * @return string
115
	 */
116 1
	protected function getEventsHTML( SMWQueryResult $res, $outputmode, $isEventline ) {
117 1
		global $curarticle, $cururl; // why not, code flow has reached max insanity already
118
119 1
		$positions = []; // possible positions, collected to select one for centering
120 1
		$curcolor = 0; // color cycling is used for eventline
121
122 1
		$result = '';
123
124 1
		$output = false; // true if output for the popup was given on current line
125 1
		if ( $isEventline ) $events = []; // array of events that are to be printed
126
127 1
		while ( $row = $res->getNext() ) { // Loop over the objcts (pages)
128 1
			$hastime = false; // true as soon as some startdate value was found
129 1
			$hastitle = false; // true as soon as some label for the event was found
130 1
			$curdata = ''; // current *inner* print data (within some event span)
131 1
			$curmeta = ''; // current event meta data
132 1
			$cururl = '';
133 1
			$curarticle = ''; // label of current article, if it was found; needed only for eventline labeling
134 1
			$first_col = true;
135
136 1
			if ( $this->mTemplate != '' ) {
137
				$this->hasTemplates = true;
138
				$template_text = '';
139
				$wikitext = '';
0 ignored issues
show
$wikitext is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
140
				$i = 0;
141
			}
142
143 1
			foreach ( $row as $field ) { // Loop over the returned properties
144 1
				$first_value = true;
145 1
				$pr = $field->getPrintRequest();
146 1
				$dataValue = $pr->getData();
147
148 1
				if ( $dataValue == '' ) {
149 1
					$date_value = null;
150
				}
151
				else {
152 1
					$date_value = $dataValue->getDataItem()->getLabel();
153
				}
154
155 1
				while ( ( $object = $field->getNextDataValue() ) !== false ) { // Loop over property values
156 1
					$event = $this->handlePropertyValue(
157 1
						$object, $outputmode, $pr, $first_col, $hastitle, $hastime,
158 1
						$first_value, $isEventline, $curmeta, $curdata, $date_value, $output, $positions
159
					);
160
161 1
					if ( $this->mTemplate != '')
162
					{
163
						$template_text .= '|' . ( $this->mNamedArgs ? '?' . $field->getPrintRequest()->getLabel() : $i + 1 ) . '=';
164
						if ( !$first_value ) {
165
							$template_text .= ', ';
166
						}
167
						$template_text .= $object->getShortText( SMW_OUTPUT_WIKI, $this->getLinker( $first_value ) );
168
						$i++;
169
					}
170
171 1
					if ( $event !== false ) {
172
						$events[] = $event;
173
					}
174
175 1
					$first_value = false;
176
				}
177
178 1
				if ( $output ) {
179 1
					$curdata .= '<br />';
180
				}
181
182 1
				$output = false;
183 1
				$first_col = false;
184
			}
185
186 1
			if ( $this->mTemplate != '')
187
			{
188
				$curdata = '{{' . $this->mTemplate . $template_text . '}}';
189
			}
190
191 1
			if ( $hastime ) {
192 1
				$result .= Html::rawElement(
193 1
					'span',
194 1
					[ 'class' => 'smwtlevent', 'style' => 'display:none;' ],
195 1
					$curmeta . Html::element(
196 1
						'span',
197 1
						[ 'class' => 'smwtlcoloricon' ],
198 1
						$curcolor
199 1
					) . $curdata
200
				);
201
			}
202
203 1
			if ( $isEventline ) {
204
				foreach ( $events as $event ) {
205
					$result .= '<span class="smwtlevent" style="display:none;" ><span class="smwtlstart">' . $event[0] . '</span><span class="smwtlurl">' . $curarticle . '</span><span class="smwtlcoloricon">' . $curcolor . '</span>';
206
					if ( $curarticle != '' ) $result .= '<span class="smwtlprefix">' . $curarticle . ' </span>';
207
					$result .=  $curdata . '</span>';
208
					$positions[$event[2]] = $event[0];
209
				}
210
				$events = [];
211
				$curcolor = ( $curcolor + 1 ) % 10;
212
			}
213
		}
214
215 1
		if ( count( $positions ) > 0 ) {
216 1
			ksort( $positions );
217 1
			$positions = array_values( $positions );
218
219 1
			switch ( $this->m_tlpos ) {
220 1
				case 'start':
221
					$result .= '<span class="smwtlposition" style="display:none;" >' . $positions[0] . '</span>';
222
					break;
223 1
				case 'end':
224
					$result .= '<span class="smwtlposition" style="display:none;" >' . $positions[count( $positions ) - 1] . '</span>';
225
					break;
226 1
				case 'today': break; // default
227 1
				case 'middle': default:
228 1
					$result .= '<span class="smwtlposition" style="display:none;" >' . $positions[ceil( count( $positions ) / 2 ) - 1] . '</span>';
229 1
					break;
230
			}
231
		}
232
233 1
		return $result;
234
	}
235
236
	/**
237
	 * Hanldes a single property value. Returns an array with data for a single event or false.
238
	 *
239
	 * FIXME: 13 arguments, of which a whole bunch are byref... not a good design :)
240
	 *
241
	 * @since 1.5.3
242
	 *
243
	 * @param SMWDataValue $object
244
	 * @param $outputmode
245
	 * @param SMWPrintRequest $pr
246
	 * @param boolean $first_col
247
	 * @param boolean &$hastitle
248
	 * @param boolean &$hastime
249
	 * @param boolean $first_value
250
	 * @param boolean $isEventline
251
	 * @param string &$curmeta
252
	 * @param string &$curdata
253
	 * @param &$date_value
254
	 * @param boolean &$output
255
	 * @param array &$positions
256
	 *
257
	 * @return false or array
258
	 */
259 1
	protected function handlePropertyValue( SMWDataValue $object, $outputmode, SMWPrintRequest $pr, $first_col,
260
		&$hastitle, &$hastime, $first_value, $isEventline, &$curmeta, &$curdata, $date_value, &$output, array &$positions ) {
261 1
			global $curarticle, $cururl;
262
263 1
		$event = false;
264
265 1
		$l = $this->getLinker( $first_col );
266
267 1
		if ( !$hastitle && $object->getTypeID() != '_wpg' ) { // "linking" non-pages in title positions confuses timeline scripts, don't try this
268
			$l = null;
269
		}
270
271 1
		if ( $object->getTypeID() == '_wpg' ) { // use shorter "LongText" for wikipage
272 1
			$objectlabel = $object->getLongText( $outputmode, $l );
273
		} else {
274 1
			$objectlabel = $object->getShortText( $outputmode, $l );
275
		}
276
277 1
		$urlobject =  ( $l !== null );
278 1
		$header = '';
279
280 1
		if ( $first_value ) {
281
			// find header for current value:
282 1
			if ( $this->mShowHeaders && ( '' != $pr->getLabel() ) ) {
283 1
				$header = $pr->getText( $outputmode, $this->mLinker ) . ': ';
284
			}
285
286
			// is this a start date?
287 1
			if ( ( $pr->getMode() == SMWPrintRequest::PRINT_PROP ) &&
288 1
			     ( $date_value == $this->m_tlstart ) ) {
289
				// FIXME: Timeline scripts should support XSD format explicitly. They
290
				// currently seem to implement iso8601 which deviates from XSD in cases.
291
				// NOTE: We can assume $object to be an SMWDataValue in this case.
292 1
				$curmeta .= Html::element(
293 1
					'span',
294 1
					[ 'class' => 'smwtlstart' ],
295 1
					$object->getXMLSchemaDate()
296
				);
297 1
				$positions[$object->getHash()] = $object->getXMLSchemaDate();
298 1
				$hastime = true;
299
			}
300
301
			// is this the end date?
302 1
			if ( ( $pr->getMode() == SMWPrintRequest::PRINT_PROP ) &&
303 1
			     ( $date_value == $this->m_tlend ) ) {
304
				// NOTE: We can assume $object to be an SMWDataValue in this case.
305
				$curmeta .= Html::element(
306
					'span',
307
					[ 'class' => 'smwtlend' ],
308
					$object->getXMLSchemaDate( false )
309
				);
310
			}
311
312
			// find title for displaying event
313 1
			if ( !$hastitle ) {
314 1
				$curmeta .= Html::rawElement(
315 1
					'span',
316
					[
317 1
						'class' => $urlobject ? 'smwtlurl' : 'smwtltitle'
318
					],
319 1
					$objectlabel
320
				);
321
322 1
				if ( $pr->getMode() == SMWPrintRequest::PRINT_THIS ) {
323 1
					$curarticle = $object->getLongText( $outputmode, $l );
324 1
					$cururl = $object->getTitle()->getFullUrl();
325
				}
326
327
				// NOTE: type Title of $object implied
328 1
				$hastitle = true;
329
			}
330
		} elseif ( $output ) {
331
			// it *can* happen that output is false here, if the subject was not printed (fixed subject query) and mutliple items appear in the first row
332
			$curdata .= ', ';
333
		}
334
335 1
		if ( !$first_col || !$first_value || $isEventline ) {
336 1
			$curdata .= $header . $objectlabel;
337 1
			$output = true;
338
		}
339
340 1
		if ( $isEventline && ( $pr->getMode() == SMWPrintRequest::PRINT_PROP ) && ( $pr->getTypeID() == '_dat' ) && ( '' != $pr->getLabel() ) && ( $date_value != $this->m_tlstart ) && ( $date_value != $this->m_tlend ) ) {
341
			$event = [
342
				$object->getXMLSchemaDate(),
343
				$pr->getLabel(),
344
				$object->getDataItem()->getSortKey(),
345
			];
346
		}
347
348 1
		return $event;
349
	}
350
351
	/**
352
	 * @see SMWResultPrinter::getParamDefinitions
353
	 *
354
	 * @since 1.8
355
	 *
356
	 * @param $definitions array of IParamDefinition
357
	 *
358
	 * @return array of IParamDefinition|array
359
	 */
360 1
	public function getParamDefinitions( array $definitions ) {
361 1
		$params = parent::getParamDefinitions( $definitions );
362
363 1
		$params['timelinesize'] = [
364
			'default' => '300px',
365
			'message' => 'srf_paramdesc_timelinesize',
366
		];
367
368 1
		$params['timelineposition'] = [
369
			'default' => 'middle',
370
			'message' => 'srf_paramdesc_timelineposition',
371
			'values' => [ 'start', 'middle', 'end', 'today' ],
372
		];
373
374 1
		$params['timelinestart'] = [
375
			'default' => '',
376
			'message' => 'srf_paramdesc_timelinestart',
377
		];
378
379 1
		$params['timelineend'] = [
380
			'default' => '',
381
			'message' => 'srf_paramdesc_timelineend',
382
		];
383
384 1
		$params['timelinebands'] = [
385
			'islist' => true,
386
			'default' => [ 'MONTH', 'YEAR' ],
387
			'message' => 'srf_paramdesc_timelinebands',
388
			'values' => [ 'MINUTE', 'HOUR', 'DAY', 'WEEK', 'MONTH', 'YEAR', 'DECADE' ],
389
		];
390
391 1
		$params['template'] = [
392
			'message' => 'smw-paramdesc-template',
393
			'default' => '',
394
		];
395
396 1
		$params['named args'] = [
397
			'type' => 'boolean',
398
			'message' => 'smw-paramdesc-named_args',
399
			'default' => false,
400
		];
401
402
403 1
		return $params;
404
	}
405
406
}
407