Completed
Push — master ( 6dc7d8...407c40 )
by Karsten
15:45
created

formats/timeseries/SRF_Timeseries.php (1 issue)

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
/**
4
 * A query printer for timeseries using the flot plotting JavaScript library
5
 *
6
 * @see http://www.semantic-mediawiki.org/wiki/Help:Flot_timeseries_chart
7
 * @licence GNU GPL v2 or later
8
 *
9
 * @since 1.8
10
 *
11
 * @author mwjames
12
 */
13
class SRFTimeseries extends SMWResultPrinter {
14
15
	/**
16
	 * @see SMWResultPrinter::getName
17
	 * @return string
18
	 */
19
	public function getName() {
20
		return wfMessage( 'srf-printername-timeseries' )->text();
21
	}
22
23
	/**
24
	 * @see SMWResultPrinter::getResultText
25
	 *
26
	 * @param SMWQueryResult $result
27
	 * @param $outputMode
28
	 *
29
	 * @return string
30
	 */
31
	protected function getResultText( SMWQueryResult $result, $outputMode ) {
32
33
		// Data processing
34
		$data = $this->getAggregatedTimeSeries( $result, $outputMode );
35
36
		// Post-data processing check
37
		if ( $data === [] ) {
38
			return $result->addErrors( [ wfMessage( 'srf-warn-empy-chart' )->inContentLanguage()->text() ] );
39
		} else {
40
			$options['sask'] = SRFUtils::htmlQueryResultLink( $this->getLink( $result, SMW_OUTPUT_HTML ) );
0 ignored issues
show
Coding Style Comprehensibility introduced by
$options was never initialized. Although not strictly required by PHP, it is generally a good practice to add $options = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
41
			return $this->getFormatOutput( $data, $options );
42
		}
43
	}
44
45
	/**
46
	 * Returns an array with numerical data
47
	 *
48
	 * @since 1.8
49
	 *
50
	 * @param SMWQueryResult $result
51
	 * @param $outputMode
52
	 *
53
	 * @return array
54
	 */
55
	protected function getAggregatedTimeSeries( SMWQueryResult $result, $outputMode ) {
56
		$values = [];
57
		$aggregatedValues = [];
58
59
		while ( /* array of SMWResultArray */
60
		$row = $result->getNext() ) { // Objects (pages)
61
			$timeStamp = '';
62
			$series = [];
63
64
			foreach ( $row as /* SMWResultArray */
65
					  $field ) {
66
				$sum = [];
67
68
				// Group by subject (page object)  or property
69
				if ( $this->params['group'] == 'subject' ) {
70
					$group = $field->getResultSubject()->getTitle()->getText();
71
				} else {
72
					$group = $field->getPrintRequest()->getLabel();
73
				}
74
75
				while ( ( /* SMWDataValue */
76
					$dataValue = $field->getNextDataValue() ) !== false ) { // Data values
77
78
					// Find the timestamp
79
					if ( $dataValue->getDataItem()->getDIType() == SMWDataItem::TYPE_TIME ) {
80
						// We work with a timestamp, we have to use intval because DataItem
81
						// returns a string but we want a numeric representation of the timestamp
82
						$timeStamp = intval( $dataValue->getDataItem()->getMwTimestamp() );
83
					}
84
85
					// Find the values (numbers only)
86
					if ( $dataValue->getDataItem()->getDIType() == SMWDataItem::TYPE_NUMBER ) {
87
						$sum[] = $dataValue->getNumber();
88
					}
89
				}
90
				// Aggegate individual values into a sum
91
				$rowSum = array_sum( $sum );
92
93
				// Check the sum and threshold/min
94
				if ( $timeStamp !== '' && $field->getPrintRequest()->getTypeID(
95
					) !== '_dat' && $rowSum >= $this->params['min'] ) {
96
					$series[$group] = [ $timeStamp, $rowSum ];
97
				}
98
			}
99
			$values[] = $series;
100
		}
101
102
		// Re-assign values according to their group
103
		foreach ( $values as $key => $value ) {
104
			foreach ( $values[$key] as $row => $rowvalue ) {
105
				$aggregatedValues[$row][] = $rowvalue;
106
			}
107
		}
108
		return $aggregatedValues;
109
	}
110
111
	/**
112
	 * Prepare data for the output
113
	 *
114
	 * @since 1.8
115
	 *
116
	 * @param array $data
117
	 *
118
	 * @return string
119
	 */
120
	protected function getFormatOutput( array $data, $options ) {
121
122
		// Object count
123
		static $statNr = 0;
124
		$chartID = 'timeseries-' . ++$statNr;
125
126
		$this->isHTML = true;
127
128
		// Reorganize the raw data
129
		foreach ( $data as $key => $values ) {
130
			$dataObject[] = [ 'label' => $key, 'data' => $values ];
131
		}
132
133
		// Series colour
134
		$seriescolors = $this->params['chartcolor'] !== '' ? array_filter(
135
			explode( ",", $this->params['chartcolor'] )
136
		) : [];
137
138
		// Prepare transfer array
139
		$chartData = [
140
			'data' => $dataObject,
141
			'fcolumntypeid' => '_dat',
142
			'sask' => $options['sask'],
143
			'parameters' => [
144
				'width' => $this->params['width'],
145
				'height' => $this->params['height'],
146
				'charttitle' => $this->params['charttitle'],
147
				'charttext' => $this->params['charttext'],
148
				'infotext' => $this->params['infotext'],
149
				'charttype' => $this->params['charttype'],
150
				'gridview' => $this->params['gridview'],
151
				'zoom' => $this->params['zoompane'],
152
				'seriescolors' => $seriescolors
153
			]
154
		];
155
156
		// Array encoding and output
157
		$requireHeadItem = [ $chartID => FormatJson::encode( $chartData ) ];
158
		SMWOutputs::requireHeadItem( $chartID, Skin::makeVariablesScript( $requireHeadItem ) );
159
160
		// RL module
161
		SMWOutputs::requireResource( 'ext.srf.timeseries.flot' );
162
163
		if ( $this->params['gridview'] === 'tabs' ) {
164
			SMWOutputs::requireResource( 'ext.srf.util.grid' );
165
		}
166
167
		// Chart/graph placeholder
168
		$chart = Html::rawElement(
169
			'div',
170
			[
171
				'id' => $chartID,
172
				'class' => 'container',
173
				'style' => "display:none;"
174
			],
175
			null
176
		);
177
178
		// Processing/loading image
179
		$processing = SRFUtils::htmlProcessingElement( $this->isHTML );
180
181
		// Beautify class selector
182
		$class = $this->params['class'] ? ' ' . $this->params['class'] : ' flot-chart-common';
183
184
		// General output marker
185
		return Html::rawElement(
186
			'div',
187
			[
188
				'class' => 'srf-timeseries' . $class
189
			],
190
			$processing . $chart
191
		);
192
	}
193
194
	/**
195
	 * @see SMWResultPrinter::getParamDefinitions
196
	 *
197
	 * @since 1.8
198
	 *
199
	 * @param $definitions array of IParamDefinition
200
	 *
201
	 * @return array of IParamDefinition|array
202
	 */
203
	public function getParamDefinitions( array $definitions ) {
204
		$params = parent::getParamDefinitions( $definitions );
205
206
		$params['charttype'] = [
207
			'message' => 'srf-paramdesc-layout',
208
			'default' => 'line',
209
			'values' => [ 'line', 'bar' ],
210
		];
211
212
		$params['min'] = [
213
			'type' => 'integer',
214
			'message' => 'srf-paramdesc-minvalue',
215
			'default' => '',
216
		];
217
218
		$params['gridview'] = [
219
			'message' => 'srf-paramdesc-gridview',
220
			'default' => 'none',
221
			'values' => [ 'none', 'tabs' ],
222
		];
223
224
		$params['group'] = [
225
			'message' => 'srf-paramdesc-group',
226
			'default' => 'subject',
227
			'values' => [ 'property', 'subject' ],
228
		];
229
230
		$params['zoompane'] = [
231
			'message' => 'srf-paramdesc-zoompane',
232
			'default' => 'bottom',
233
			'values' => [ 'none', 'bottom', 'top' ],
234
		];
235
236
		$params['height'] = [
237
			'type' => 'integer',
238
			'message' => 'srf_paramdesc_chartheight',
239
			'default' => 400,
240
			'lowerbound' => 1,
241
		];
242
243
		$params['width'] = [
244
			'message' => 'srf_paramdesc_chartwidth',
245
			'default' => '100%',
246
		];
247
248
		$params['charttitle'] = [
249
			'message' => 'srf_paramdesc_charttitle',
250
			'default' => '',
251
		];
252
253
		$params['charttext'] = [
254
			'message' => 'srf-paramdesc-charttext',
255
			'default' => '',
256
		];
257
258
		$params['infotext'] = [
259
			'message' => 'srf-paramdesc-infotext',
260
			'default' => '',
261
		];
262
263
		$params['chartcolor'] = [
264
			'message' => 'srf-paramdesc-chartcolor',
265
			'default' => '',
266
		];
267
268
		$params['class'] = [
269
			'message' => 'srf-paramdesc-class',
270
			'default' => '',
271
		];
272
273
		return $params;
274
	}
275
}
276