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

GanttPrinter::handleParameters()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 9.9
c 0
b 0
f 0
cc 1
nc 1
nop 2
1
<?php
2
/**
3
 * SMW result printer for Gantt Diagrams using mermaidjs.
4
 * https://github.com/knsv/mermaid
5
 *
6
 * In order to use this printer you need to have
7
 * the Mermaid MediaWiki extension installed.
8
 * https://www.mediawiki.org/wiki/Extension:Mermaid
9
 *
10
 * @file Gantt.php
11
 * @ingroup SemanticResultFormats
12
 *
13
 * @licence GNU GPL v2+
14
 * @author Sebastian Schmid
15
 */
16
17
namespace SRF\Gantt;
18
19
use SMWOutputs;
20
use SMWQueryResult;
21
use SMWResultPrinter;
22
use SMWDITime;
23
use SMWDIBlob;
24
use Html;
25
26
class GanttPrinter extends SMWResultPrinter {
27
28
	protected $mGantt = null;
29
	protected $mErrors = [];
30
31
	public function getName() {
32
		return wfMessage( 'srf-printername-gantt' )->text();
33
	}
34
35
	public function getParamDefinitions( array $definitions ) {
36
		$params = parent::getParamDefinitions( $definitions );
37
38
		$params[] = [
39
			'type'    => 'string',
40
			'name'    => 'diagramtitle',
41
			'message' => 'srf-paramdesc-gantt-diagramtitle',
42
			'default' => ''
43
		];
44
45
		$params[] = [
46
			'type'    => 'string',
47
			'name'    => 'theme',
48
			'message' => 'srf-paramdesc-gantt-diagramtheme',
49
			'default' => 'default'
50
		];
51
52
		$params[] = [
53
			'type'    => 'string',
54
			'name'    => 'axisformat',
55
			'message' => 'srf-paramdesc-gantt-axisformat',
56
			'default' => '%m/%d/%Y'
57
		];
58
59
		$params[] = [
60
			'type'    => 'string',
61
			'name'    => 'statusmapping',
62
			'message' => 'srf-paramdesc-gantt-statusmapping',
63
			'default' => ''
64
		];
65
66
		$params[] = [
67
			'type'    => 'string',
68
			'name'    => 'prioritymapping',
69
			'message' => 'srf-paramdesc-gantt-prioritymapping',
70
			'default' => ''
71
		];
72
73
		$params[] = [
74
			'type'    => 'integer',
75
			'name'    => 'titletopmargin',
76
			'message' => 'srf-paramdesc-gantt-titletopmargin',
77
			'default' => 25
78
		];
79
80
		$params[] = [
81
			'type'    => 'integer',
82
			'name'    => 'barheight',
83
			'message' => 'srf-paramdesc-gantt-barheight',
84
			'default' => 20
85
		];
86
87
		$params[] = [
88
			'type'    => 'integer',
89
			'name'    => 'leftpadding',
90
			'message' => 'srf-paramdesc-gantt-leftpadding',
91
			'default' => 75
92
		];
93
94
		$params[] = [
95
			'type'    => 'integer',
96
			'name'    => 'bargap',
97
			'message' => 'srf-paramdesc-gantt-bargap',
98
			'default' => 4
99
		];
100
101
		return $params;
102
	}
103
104
	/**
105
	 * Handle (set) the result format parameters
106
	 *
107
	 * @see SMWResultPrinter::handleParameters()
108
	 */
109
	protected function handleParameters( array $params, $outputmode ) {
110
111
		//Set header params
112
		$this->params['title'] = trim( $params['diagramtitle'] );
113
		$this->params['axisformat'] = trim( $params['axisformat'] );
114
		$this->params['statusmapping'] =  $this->getValidatedMapping( $params[ 'statusmapping' ], 'statusmapping', [ 'active', 'done' ] );
115
		$this->params['prioritymapping'] = $this->getValidatedMapping( $params[ 'prioritymapping' ], 'prioritymapping', [ 'crit' ] );
116
		$this->params['theme'] = $this->getValidatedTheme($params['theme']);
117
118
		$this->mGantt = $this->getGantt();
119
	}
120
121
	/**
122
	 * Return serialised results in specified format.
123
	 * @param SMWQueryResult $queryResult
124
	 * @param $outputmode
125
	 * @return string
126
	 */
127
	protected function getResultText( SMWQueryResult $queryResult, $outputmode ) {
128
129
		// Show warning if Extension:Mermaid is not available
130
		if ( !class_exists( 'Mermaid' ) && !class_exists( 'Mermaid\\MermaidParserFunction' ) ) {
131
			$queryResult->addErrors( [wfMessage('')->text()] );
132
			return '';
133
		}
134
135
		// Load general Modules
136
		SMWOutputs::requireResource( 'ext.srf.gantt' );
137
138
		//Add Tasks & Sections
139
		while ( $row = $queryResult->getNext() ) {
140
141
			$status = [];
142
			$priority = [];
143
			$startDate = '';
144
			$endDate = '';
145
			$taskID = '';
146
			$taskTitle = '';
147
			$sections = [];
148
149
			// Loop through all field of a row
150
			foreach ( $row as $field ) {
151
152
				$fieldLabel = $field->getPrintRequest()->getLabel();
153
154
				//get values
155
				foreach ( $field->getContent() as $dataItem ) {
156
157
					switch ( $fieldLabel ) {
158
						case 'section':
159
							$sections[$dataItem->getTitle()->getPrefixedDBKey()] = $dataItem->getSortKey();
160
							break;
161
						case 'task':
162
							if ( $dataItem instanceof SMWDIBlob ) {
163
								$taskTitle = $dataItem->getString();
164
								$taskID = $field->getResultSubject()->getTitle()->getPrefixedDBKey();
165
							}
166
							break;
167
						case 'startdate':
168
							if ( $dataItem instanceof SMWDITime ) {
169
								$startDate = $dataItem->getMwTimestamp();
170
							}
171
							break;
172
						case 'enddate':
173
							if ( $dataItem instanceof SMWDITime ) {
174
								$endDate = $dataItem->getMwTimestamp();
175
							}
176
							break;
177
						case 'status':
178
							if ( $dataItem instanceof SMWDIBlob ) {
179
								$status[] = $dataItem->getString();
180
							}
181
							break;
182
						case 'priority':
183
							if ( $dataItem instanceof SMWDIBlob ) {
184
								$priority[] = $dataItem->getString();
185
							}
186
							break;
187
					}
188
				}
189
			}
190
191
			// Add section/Task
192
			// Title, TaskID, StartDate and EndDate are required
193
			if ( $taskID !== '' && $taskTitle !== '' && $startDate !== '' && $endDate !== '' ) {
194
				$this->mGantt->addTask( $taskID, $taskTitle, $status, $priority, $startDate, $endDate );
195
196
				// If no section was found, put task into a dummy section object
197
				// "gantt-no-section#21780240" is used to identify Tasks that with no section (dummy section)
198
				if ( count( $sections ) == 0 ) {
199
					$this->mGantt->addSection( 'gantt-no-section#21780240', '', $startDate, $endDate, $taskID );
200
				} else {
201
					foreach ( $sections as $sectionID => $sectionTitle ) {
202
						$this->mGantt->addSection( $sectionID, $sectionTitle, $startDate, $endDate, $taskID );
203
					}
204
				}
205
			}
206
		}
207
208
		// Improve unique id by adding a random number
209
		$id = uniqid( 'srf-gantt-' . rand( 1, 10000 ) );
210
211
		// Add gantt configurations
212
		$config = [
213
			'theme' => $this->params['theme'],
214
			'gantt' => [
215
				'leftPadding'    => intval( $this->params['leftpadding'] ),
216
				'titleTopMargin' => intval( $this->params['titletopmargin'] ),
217
				'barHeight'      => intval( $this->params['barheight'] ),
218
				'barGap'         => intval( $this->params['bargap'] )
219
			]
220
		];
221
222
223
		// Manage Output
224
		if ( !empty( $this->mErrors ) ) {
225
			return $queryResult->addErrors( $this->mErrors );
226
		} else {
227
			return Html::rawElement( 'div', [
228
				'id'           => $id,
229
				'class'        => 'srf-gantt',
230
				'data-mermaid' => html_entity_decode( json_encode( [
231
					'content' => $this->mGantt->getGanttOutput(),
232
					'config'  => $config
233
				]))
234
			], Html::rawElement( 'div', [ 'class' => 'mermaid-dots' ]));
235
		}
236
	}
237
238
	private function getGantt(){
239
		return new Gantt( $this->params );
240
	}
241
242
	/**
243
	 * Return valid theme as string
244
	 * @param String $theme
245
	 *
246
	 * @return string
247
	 */
248
	private function getValidatedTheme( $theme ) {
249
		$theme = trim( $theme );
250
251
		if ( !in_array( $this->params['theme'], [ 'default', 'neutral', 'dark', 'forest' ] ) ) {
252
			$this->mErrors[] = wfMessage( 'srf-error-gantt-theme' )->text();
253
		}
254
255
		return $theme;
256
	}
257
258
259
	private function getValidatedMapping( $params, $mappingType, array $mappingKeys){
260
		//Validate mapping
261
		$mapping = [];
262
263
		if ( !empty( $params ) ) {
264
			$paramMapping = explode( ';', trim( $params ) );
265
266
			foreach ( $paramMapping as $pm ) {
267
				$pmKeyVal = explode( '=>', $pm, 2);
268
269
				// if no key value pair
270
				if ( count( $pmKeyVal ) !== 2 ) {
271
					$this->mErrors[] = wfMessage( 'srf-error-gantt-mapping-assignment', $mappingType )->text();
272
				} else {
273
					$mapping[trim( $pmKeyVal[0] )] = trim( $pmKeyVal[1] );
274
275
					if(!in_array(trim( $pmKeyVal[1] ), $mappingKeys)){
276
						$this->mErrors[] = wfMessage( 'srf-error-gantt-mapping-keywords' )->text();
277
					}
278
				}
279
			}
280
			return $mapping;
281
		}
282
		return '';
283
	}
284
}