Completed
Pull Request — master (#496)
by
unknown
17:19
created

SRFGraph::handleParameters()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 23
ccs 0
cts 14
cp 0
rs 9.552
c 0
b 0
f 0
cc 2
nc 2
nop 2
crap 6
1
<?php
2
3
/**
4
 * SMW result printer for graphs using graphViz.
5
 * In order to use this printer you need to have both
6
 * the graphViz library installed on your system and
7
 * have the graphViz MediaWiki extension installed.
8
 *
9
 * @file SRF_Graph.php
10
 * @ingroup SemanticResultFormats
11
 *
12
 * @licence GNU GPL v2+
13
 * @author Frank Dengler
14
 * @author Jeroen De Dauw < [email protected] >
15
 */
16
class SRFGraph extends SMWResultPrinter {
17
18
	public static $NODE_SHAPES = [
19
		'box',
20
		'box3d',
21
		'circle',
22
		'component',
23
		'diamond',
24
		'doublecircle',
25
		'doubleoctagon',
26
		'egg',
27
		'ellipse',
28
		'folder',
29
		'hexagon',
30
		'house',
31
		'invhouse',
32
		'invtrapezium',
33
		'invtriangle',
34
		'Mcircle',
35
		'Mdiamond',
36
		'Msquare',
37
		'none',
38
		'note',
39
		'octagon',
40
		'parallelogram',
41
		'pentagon ',
42
		'plaintext',
43
		'point',
44
		'polygon',
45
		'rect',
46
		'rectangle',
47
		'septagon',
48
		'square',
49
		'tab',
50
		'trapezium',
51
		'triangle',
52
		'tripleoctagon',
53
	];
54
55
	protected $m_graphName;
56
	protected $m_graphLabel;
57
	protected $m_graphColor;
58
	protected $m_graphLegend;
59
	protected $m_graphLink;
60
	protected $m_rankdir;
61
	protected $m_graphSize;
62
	protected $m_labelArray = [];
63
	protected $m_graphColors = [
64
		'black',
65
		'red',
66
		'green',
67
		'blue',
68
		'darkviolet',
69
		'gold',
70
		'deeppink',
71
		'brown',
72
		'bisque',
73
		'darkgreen',
74
		'yellow',
75
		'darkblue',
76
		'magenta',
77
		'steelblue2' ];
78
	protected $m_nameProperty;
79
	protected $m_nodeShape;
80
	protected $m_parentRelation;
81
	protected $m_wordWrapLimit;
82
	protected $m_nodeLabel;
83
84
	/**
85
	 * (non-PHPdoc)
86
	 * @see SMWResultPrinter::handleParameters()
87
	 */
88
	protected function handleParameters( array $params, $outputmode ) {
89
		parent::handleParameters( $params, $outputmode );
90
91
		$this->m_graphName = trim( $params['graphname'] );
92
		$this->m_graphSize = trim( $params['graphsize'] );
93
94
		$this->m_graphLegend = $params['graphlegend'];
95
		$this->m_graphLabel = $params['graphlabel'];
96
97
		$this->m_rankdir = strtoupper( trim( $params['arrowdirection'] ) );
98
99
		$this->m_graphLink = $params['graphlink'];
100
		$this->m_graphColor = $params['graphcolor'];
101
102
		$this->m_nameProperty = $params['nameproperty'] === false ? false : trim( $params['nameproperty'] );
103
104
		$this->m_parentRelation = strtolower( trim( $params['relation'] ) ) == 'parent';
105
106
		$this->m_nodeShape = $params['nodeshape'];
107
		$this->m_wordWrapLimit = $params['wordwraplimit'];
108
109
		$this->m_nodeLabel = $params['nodelabel'];
110
	}
111
112
	protected function getResultText( SMWQueryResult $res, $outputmode ) {
113
114
		if ( !class_exists( 'GraphViz' )
115
			&& !class_exists( '\\MediaWiki\\Extension\\GraphViz\\GraphViz' )
116
		) {
117
			wfWarn( 'The SRF Graph printer needs the GraphViz extension to be installed.' );
118
			return '';
119
		}
120
121
		$this->isHTML = true;
122
123
		$graphInput = "digraph $this->m_graphName {";
124
		if ( $this->m_graphSize != '' ) {
125
			$graphInput .= "size=\"$this->m_graphSize\";";
126
		}
127
		if ( $this->m_nodeShape ) {
128
			$graphInput .= "node [shape=$this->m_nodeShape];";
129
		}
130
		$graphInput .= "rankdir=$this->m_rankdir;";
131
132
		while ( $row = $res->getNext() ) {
133
			$graphInput .= $this->getGVForItem( $row, $outputmode );
134
		}
135
136
		$graphInput .= "}";
137
138
		// Calls graphvizParserHook function from MediaWiki GraphViz extension
139
		$result = $GLOBALS['wgParser']->recursiveTagParse( "<graphviz>$graphInput</graphviz>" );
140
141
		if ( $this->m_graphLegend && $this->m_graphColor ) {
142
			$arrayCount = 0;
143
			$arraySize = count( $this->m_graphColors );
144
			$result .= "<P>";
145
146
			foreach ( $this->m_labelArray as $m_label ) {
147
				if ( $arrayCount >= $arraySize ) {
148
					$arrayCount = 0;
149
				}
150
151
				$color = $this->m_graphColors[$arrayCount];
152
				$result .= "<font color=$color>$color: $m_label </font><br />";
153
154
				$arrayCount += 1;
155
			}
156
157
			$result .= "</P>";
158
		}
159
160
		return $result;
161
	}
162
163
	/**
164
	 * Returns the GV for a single subject.
165
	 *
166
	 * @since 1.5.4
167
	 *
168
	 * @param array $row
169
	 * @param $outputmode
170
	 *
171
	 * @return string
172
	 */
173
	protected function getGVForItem( array /* of SMWResultArray */
174
	$row, $outputmode ) {
175
		$segments = [];
176
177
		// Loop throught all fields of the record.
178
		foreach ( $row as $i => $resultArray ) {
179
180
			// Loop throught all the parts of the field value.
181
			while ( ( $object = $resultArray->getNextDataValue() ) !== false ) {
182
				$propName = $resultArray->getPrintRequest()->getLabel();
183
				$isName = $this->m_nameProperty ? ( $i != 0 && $this->m_nameProperty === $propName ) : $i == 0;
184
185
				if ( $isName ) {
186
					$name = $this->getWordWrappedText( $object->getShortText( $outputmode ), $this->m_wordWrapLimit );
187
				}
188
189
				if ( !( $this->m_nameProperty && $i == 0 ) ) {
190
					$segments[] = $this->getGVForDataValue( $object, $outputmode, $isName, $name, $propName );
0 ignored issues
show
Bug introduced by
The variable $name does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
191
				}
192
			}
193
		}
194
195
		return implode( "\n", $segments );
196
	}
197
198
	/**
199
	 * Returns the GV for a single SMWDataValue.
200
	 *
201
	 * @since 1.5.4
202
	 *
203
	 * @param SMWDataValue $object
204
	 * @param $outputmode
205
	 * @param boolean $isName Is this the name that should be used for the node?
206
	 * @param string $name
207
	 * @param string $labelName
208
	 *
209
	 * @return string
210
	 */
211
	protected function getGVForDataValue( SMWDataValue $object, $outputmode, $isName, $name, $labelName ) {
212
		$graphInput = '';
213
		$nodeLabel = '';
214
		$text = $object->getShortText( $outputmode );
215
216
		if ( $this->m_graphLink ) {
217
			$nodeLinkURL = "[[" . $text . "]]";
218
		}
219
220
		$text = $this->getWordWrappedText( $text, $this->m_wordWrapLimit );
221
222
		if ( $this->m_nodeLabel === 'displaytitle' && $object instanceof SMWWikiPageValue ) {
223
			$objectDisplayTitle = $object->getDisplayTitle();
224
			if ( !empty( $objectDisplayTitle )) {
225
				$nodeLabel = $this->getWordWrappedText( $objectDisplayTitle, $this->m_wordWrapLimit );
226
			}
227
		}
228
229
		if ( $this->m_graphLink ) {
230
			if( $nodeLabel === '' ) {
231
                $graphInput .= " \"$text\" [URL = \"$nodeLinkURL\"]; ";
0 ignored issues
show
Bug introduced by
The variable $nodeLinkURL does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
232
			} else {
233
                $graphInput .= " \"$text\" [URL = \"$nodeLinkURL\", label = \"$nodeLabel\"]; ";
234
			}
235
		}
236
237
		if ( !$isName ) {
238
			$graphInput .= $this->m_parentRelation ? " \"$text\" -> \"$name\" " : " \"$name\" -> \"$text\" ";
239
240
			if ( $this->m_graphLabel || $this->m_graphColor ) {
241
				$graphInput .= ' [';
242
243
				if ( array_search( $labelName, $this->m_labelArray, true ) === false ) {
244
					$this->m_labelArray[] = $labelName;
245
				}
246
247
				$color = $this->m_graphColors[array_search( $labelName, $this->m_labelArray, true )];
248
249
				if ( $this->m_graphLabel ) {
250
					$graphInput .= "label=\"$labelName\"";
251
					if ( $this->m_graphColor ) {
252
						$graphInput .= ",fontcolor=$color,";
253
					}
254
				}
255
256
				if ( $this->m_graphColor ) {
257
					$graphInput .= "color=$color";
258
				}
259
260
				$graphInput .= ']';
261
262
			}
263
264
			$graphInput .= ';';
265
		}
266
267
		return $graphInput;
268
	}
269
270
	/**
271
	 * Returns the word wrapped version of the provided text.
272
	 *
273
	 * @since 1.5.4
274
	 *
275
	 * @param string $text
276
	 * @param integer $charLimit
277
	 *
278
	 * @return string
279
	 */
280
	protected function getWordWrappedText( $text, $charLimit ) {
281
		$charLimit = max( [ $charLimit, 1 ] );
282
		$segments = [];
283
284
		while ( strlen( $text ) > $charLimit ) {
285
			// Find the last space in the allowed range.
286
			$splitPosition = strrpos( substr( $text, 0, $charLimit ), ' ' );
287
288
			if ( $splitPosition === false ) {
289
				// If there is no space (lond word), find the next space.
290
				$splitPosition = strpos( $text, ' ' );
291
292
				if ( $splitPosition === false ) {
293
					// If there are no spaces, everything goes on one line.
294
					$splitPosition = strlen( $text ) - 1;
295
				}
296
			}
297
298
			$segments[] = substr( $text, 0, $splitPosition + 1 );
299
			$text = substr( $text, $splitPosition + 1 );
300
		}
301
302
		$segments[] = $text;
303
304
		return implode( '\n', $segments );
305
	}
306
307
	/**
308
	 * (non-PHPdoc)
309
	 * @see SMWResultPrinter::getName()
310
	 */
311
	public function getName() {
312
		return wfMessage( 'srf-printername-graph' )->text();
313
	}
314
315
	/**
316
	 * @see SMWResultPrinter::getParamDefinitions
317
	 *
318
	 * @since 1.8
319
	 *
320
	 * @param $definitions array of IParamDefinition
321
	 *
322
	 * @return array of IParamDefinition|array
323
	 */
324
	public function getParamDefinitions( array $definitions ) {
325
		$params = parent::getParamDefinitions( $definitions );
326
327
		$params['graphname'] = [
328
			'default' => 'QueryResult',
329
			'message' => 'srf-paramdesc-graphname',
330
		];
331
332
		$params['graphsize'] = [
333
			'type' => 'string',
334
			'default' => '',
335
			'message' => 'srf-paramdesc-graphsize',
336
			'manipulatedefault' => false,
337
		];
338
339
		$params['graphlegend'] = [
340
			'type' => 'boolean',
341
			'default' => false,
342
			'message' => 'srf-paramdesc-graphlegend',
343
		];
344
345
		$params['graphlabel'] = [
346
			'type' => 'boolean',
347
			'default' => false,
348
			'message' => 'srf-paramdesc-graphlabel',
349
		];
350
351
		$params['graphlink'] = [
352
			'type' => 'boolean',
353
			'default' => false,
354
			'message' => 'srf-paramdesc-graphlink',
355
		];
356
357
		$params['graphcolor'] = [
358
			'type' => 'boolean',
359
			'default' => false,
360
			'message' => 'srf-paramdesc-graphcolor',
361
		];
362
363
		$params['arrowdirection'] = [
364
			'aliases' => 'rankdir',
365
			'default' => 'LR',
366
			'message' => 'srf-paramdesc-rankdir',
367
			'values' => [ 'LR', 'RL', 'TB', 'BT' ],
368
		];
369
370
		$params['nodeshape'] = [
371
			'default' => false,
372
			'message' => 'srf-paramdesc-graph-nodeshape',
373
			'manipulatedefault' => false,
374
			'values' => self::$NODE_SHAPES,
375
		];
376
377
		$params['relation'] = [
378
			'default' => 'child',
379
			'message' => 'srf-paramdesc-graph-relation',
380
			'manipulatedefault' => false,
381
			'values' => [ 'parent', 'child' ],
382
		];
383
384
		$params['nameproperty'] = [
385
			'default' => false,
386
			'message' => 'srf-paramdesc-graph-nameprop',
387
			'manipulatedefault' => false,
388
		];
389
390
		$params['wordwraplimit'] = [
391
			'type' => 'integer',
392
			'default' => 25,
393
			'message' => 'srf-paramdesc-graph-wwl',
394
			'manipulatedefault' => false,
395
		];
396
397
		$params['nodelabel'] = [
398
			'type' => 'string',
399
			'default' => '',
400
			'message' => 'srf-paramdesc-nodelabel',
401
		];
402
403
		return $params;
404
	}
405
406
}
407