Completed
Pull Request — master (#507)
by
unknown
14:08
created

GraphPrinter::getResultText()   F

Complexity

Conditions 21
Paths 2321

Size

Total Lines 115

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 462

Importance

Changes 0
Metric Value
dl 0
loc 115
ccs 0
cts 74
cp 0
rs 0
c 0
b 0
f 0
cc 21
nc 2321
nop 2
crap 462

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace SRF\Graph;
4
5
use SMW\ResultPrinter;
6
use SMWQueryResult;
7
use SMWWikiPageValue;
8
use GraphViz;
9
use Html;
10
11
/**
12
 * SMW result printer for graphs using graphViz.
13
 * In order to use this printer you need to have both
14
 * the graphViz library installed on your system and
15
 * have the graphViz MediaWiki extension installed.
16
 *
17
 * @file SRF_Graph.php
18
 * @ingroup SemanticResultFormats
19
 *
20
 * @licence GNU GPL v2+
21
 * @author Frank Dengler
22
 * @author Jeroen De Dauw < [email protected] >
23
 * @author Sebastian Schmid
24
 */
25
class GraphPrinter extends ResultPrinter {
26
27
	const NODELABEL_DISPLAYTITLE = 'displaytitle';
28
	public static $NODE_LABELS = [
29
		self::NODELABEL_DISPLAYTITLE,
30
	];
31
32
	public static $NODE_SHAPES = [
33
		'box',
34
		'box3d',
35
		'circle',
36
		'component',
37
		'diamond',
38
		'doublecircle',
39
		'doubleoctagon',
40
		'egg',
41
		'ellipse',
42
		'folder',
43
		'hexagon',
44
		'house',
45
		'invhouse',
46
		'invtrapezium',
47
		'invtriangle',
48
		'Mcircle',
49
		'Mdiamond',
50
		'Msquare',
51
		'none',
52
		'note',
53
		'octagon',
54
		'parallelogram',
55
		'pentagon ',
56
		'plaintext',
57
		'point',
58
		'polygon',
59
		'rect',
60
		'rectangle',
61
		'septagon',
62
		'square',
63
		'tab',
64
		'trapezium',
65
		'triangle',
66
		'tripleoctagon',
67
	];
68
	protected $nodeShape;
69
	protected $nodes = [];
70
	protected $nodeLabel;
71
	protected $parentRelation;
72
73
	protected $graphName;
74
	protected $graphSize;
75
	protected $graphColors = [
76
		'black',
77
		'red',
78
		'green',
79
		'blue',
80
		'darkviolet',
81
		'gold',
82
		'deeppink',
83
		'brown',
84
		'bisque',
85
		'darkgreen',
86
		'yellow',
87
		'darkblue',
88
		'magenta',
89
		'steelblue2'
90
	];
91
92
	protected $showGraphColor;
93
	protected $showGraphLabel;
94
	protected $showGraphLegend;
95
	protected $enableGraphLink;
96
97
	protected $rankdir;
98
	protected $legendItem = [];
99
	protected $nameProperty;
100
	protected $wordWrapLimit;
101
102
103
	public function getName() {
104
		return $this->msg( 'srf-printername-graph' )->text();
105
	}
106
107
108
	/**
109
	 * @see SMWResultPrinter::handleParameters()
110
	 */
111
	protected function handleParameters( array $params, $outputmode ) {
112
		parent::handleParameters( $params, $outputmode );
113
114
		$this->graphName = trim( $params['graphname'] );
115
		$this->graphSize = trim( $params['graphsize'] );
116
		$this->showGraphLegend = $params['graphlegend'];
117
		$this->showGraphLabel = $params['graphlabel'];
118
		$this->enableGraphLink = $params['graphlink'];
119
		$this->showGraphColor = $params['graphcolor'];
120
		$this->rankdir = strtoupper( trim( $params['arrowdirection'] ) );
121
		$this->nameProperty = $params['nameproperty'] === false ? false : trim( $params['nameproperty'] );
122
		$this->parentRelation =
123
			strtolower( trim( $params['relation'] ) ) == 'parent';        // false if anything other than 'parent'
124
		$this->nodeShape = $params['nodeshape'];
125
		$this->wordWrapLimit = $params['wordwraplimit'];
126
		$this->nodeLabel = $params['nodelabel'];
127
	}
128
129
130
	/**
131
	 * @param SMWQueryResult $res
132
	 * @param $outputmode
133
	 * @return string
134
	 */
135
	protected function getResultText( SMWQueryResult $res, $outputmode ) {
136
		if ( !class_exists( 'GraphViz' )
137
			&& !class_exists( '\\MediaWiki\\Extension\\GraphViz\\GraphViz' )
138
		) {
139
			wfWarn( 'The SRF Graph printer needs the GraphViz extension to be installed.' );
140
			return '';
141
		}
142
143
		// set name of current graph
144
		$graphInput = "digraph $this->graphName {";
145
146
		// set fontsize and fontname of graph, nodes and edges
147
		$graphInput .= "graph [fontsize=10, fontname=\"Verdana\"]\n";
148
		$graphInput .= "node [fontsize=10, fontname=\"Verdana\"];\n";
149
		$graphInput .= "edge [fontsize=10, fontname=\"Verdana\"];\n";
150
151
		// choose graphsize, nodeshapes and rank direction
152
		if ( $this->graphSize != '' ) {
153
			$graphInput .= "size=\"$this->graphSize\";";
154
		}
155
156
		if ( $this->nodeShape ) {
157
			$graphInput .= "node [shape=$this->nodeShape];";
158
		}
159
160
		$graphInput .= "rankdir=$this->rankdir;";
161
162
		$nodeLabel = '';
163
164
		// iterate query result and create SRF\GraphNodes
165
		while ( $row = $res->getNext() ) {
166
			$this->processResultRow( $row );
167
		}
168
169
		/** @var \SRF\GraphNode $node */
170
		foreach ( $this->nodes as $node ) {
171
172
			$nodeName = $node->getID();
173
174
			// take "displaytitle" as node-label if it is set
175
			if ( $this->nodeLabel === self::NODELABEL_DISPLAYTITLE) {
176
				$objectDisplayTitle = $node->getLabel();
177
				if ( !empty( $objectDisplayTitle )) {
178
					$nodeLabel = $this->getWordWrappedText( $objectDisplayTitle,
179
						$this->wordWrapLimit );
180
				}
181
			}
182
183
			// add the node
184
			$graphInput .= "\"" . $nodeName . "\"";
185
186
			if ( $this->enableGraphLink ) {
187
188
				$nodeLinkURL = "[[" . $nodeName . "]]";
189
190
				if( $nodeLabel === '' ) {
191
					$graphInput .= " [URL = \"$nodeLinkURL\"]";
192
				} else {
193
					$graphInput .= " [URL = \"$nodeLinkURL\", label = \"$nodeLabel\"]";
194
				}
195
			}
196
			$graphInput .= "; ";
197
		}
198
199
		foreach ( $this->nodes as $node ) {
200
201
			if ( count( $node->getParentNode() ) > 0 ) {
202
203
				$nodeName = $node->getID();
204
205
				foreach ( $node->getParentNode() as $parentNode ) {
206
207
					// handle parent/child switch (parentRelation)
208
					$graphInput .= $this->parentRelation ? " \"" . $parentNode['object'] . "\" -> \"" . $nodeName . "\""
209
						: " \"" . $nodeName . "\" -> \"" . $parentNode['object'] . "\" ";
210
211
					if ( $this->showGraphLabel || $this->showGraphColor ) {
212
						$graphInput .= ' [';
213
214
						// add legend item only if missing
215
						if ( array_search( $parentNode['predicate'], $this->legendItem, true ) === false ) {
216
							$this->legendItem[] = $parentNode['predicate'];
217
						}
218
219
						// assign color
220
						$color = $this->graphColors[array_search( $parentNode['predicate'], $this->legendItem, true )];
221
222
						// show arrow label (graphLabel is misleading but kept for compatibility reasons)
223
						if ( $this->showGraphLabel ) {
224
							$graphInput .= "label=\"" . $parentNode['predicate'] . "\"";
225
							if ( $this->showGraphColor ) {
226
								$graphInput .= ",fontcolor=$color,";
227
							}
228
						}
229
230
						// colorize arrow
231
						if ( $this->showGraphColor ) {
232
							$graphInput .= "color=$color";
233
						}
234
						$graphInput .= ']';
235
					}
236
				}
237
				$graphInput .= ';';
238
			}
239
		}
240
		$graphInput .= "}";
241
242
		// Calls graphvizParserHook function from MediaWiki GraphViz extension
243
		$result = $GLOBALS['wgParser']->recursiveTagParse( "<graphviz>$graphInput</graphviz>" );
244
245
		// append legend
246
		$result .= $this->getGraphLegend();
247
248
		return $result;
249
	}
250
251
	/**
252
	 * Creates the graph legend
253
	 *
254
	 * @since 3.1
255
	 *
256
	 * @return string Html::rawElement
257
	 *
258
	 */
259
	protected function getGraphLegend(){
260
		if ( $this->showGraphLegend && $this->showGraphColor ) {
261
			$itemsHtml = '';
262
			$colorCount = 0;
263
			$arraySize = count( $this->graphColors );
264
265
			foreach ( $this->legendItem as $legendLabel ) {
266
				if ( $colorCount >= $arraySize ) {
267
					$colorCount = 0;
268
				}
269
270
				$color = $this->graphColors[$colorCount];
271
				$itemsHtml .= Html::rawElement( 'div', [ 'class' => 'graphlegenditem', 'style' => "color: $color" ],
272
					"$color: $legendLabel" );
273
274
				$colorCount ++;
275
			}
276
277
			return Html::rawElement( 'div', [ 'class' => 'graphlegend' ], "$itemsHtml" );
278
		}
279
	}
280
281
	/**
282
	 * Process a result row and create SRF\GraphNodes
283
	 *
284
	 * @since 3.1
285
	 *
286
	 * @param array $row
287
	 *
288
	 */
289
	protected function processResultRow( array /* of SMWResultArray */ $row ) {
290
291
		// loop through all row fields
292
		foreach ( $row as $i => $resultArray ) {
293
294
			// loop through all values of a multivalue field
295
			while ( ( /* SMWWikiPageValue */
296
				$object = $resultArray->getNextDataValue() ) !== false ) {
297
298
				// create SRF\GraphNode for column 0
299
				if ( $i == 0 ) {
300
					$node = new GraphNode( $object->getShortWikiText() );
301
					$node->setLabel($object->getDisplayTitle());
302
					$this->nodes[] = $node;
303
				} else {
304
					$node->addParentNode( $resultArray->getPrintRequest()->getLabel(), $object->getShortWikiText() );
0 ignored issues
show
Bug introduced by
The variable $node 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...
305
				}
306
			}
307
		}
308
	}
309
310
	/**
311
	 * Returns the word wrapped version of the provided text.
312
	 *
313
	 * @since 1.5.4
314
	 *
315
	 * @param string $text
316
	 * @param integer $charLimit
317
	 *
318
	 * @return string
319
	 */
320
	protected function getWordWrappedText( $text, $charLimit ) {
321
		$charLimit = max( [ $charLimit, 1 ] );
322
		$segments = [];
323
324
		while ( strlen( $text ) > $charLimit ) {
325
			// Find the last space in the allowed range.
326
			$splitPosition = strrpos( substr( $text, 0, $charLimit ), ' ' );
327
328
			if ( $splitPosition === false ) {
329
				// If there is no space (lond word), find the next space.
330
				$splitPosition = strpos( $text, ' ' );
331
332
				if ( $splitPosition === false ) {
333
					// If there are no spaces, everything goes on one line.
334
					$splitPosition = strlen( $text ) - 1;
335
				}
336
			}
337
338
			$segments[] = substr( $text, 0, $splitPosition + 1 );
339
			$text = substr( $text, $splitPosition + 1 );
340
		}
341
342
		$segments[] = $text;
343
344
		return implode( '\n', $segments );
345
	}
346
347
348
	/**
349
	 * @see SMWResultPrinter::getParamDefinitions
350
	 *
351
	 * @since 1.8
352
	 *
353
	 * @param $definitions array of IParamDefinition
354
	 *
355
	 * @return array of IParamDefinition|array
356
	 */
357
	public function getParamDefinitions( array $definitions ) {
358
		$params = parent::getParamDefinitions( $definitions );
359
360
		$params['graphname'] = [
361
			'default' => 'QueryResult',
362
			'message' => 'srf-paramdesc-graphname',
363
		];
364
365
		$params['graphsize'] = [
366
			'type' => 'string',
367
			'default' => '',
368
			'message' => 'srf-paramdesc-graphsize',
369
			'manipulatedefault' => false,
370
		];
371
372
		$params['graphlegend'] = [
373
			'type' => 'boolean',
374
			'default' => false,
375
			'message' => 'srf-paramdesc-graphlegend',
376
		];
377
378
		$params['graphlabel'] = [
379
			'type' => 'boolean',
380
			'default' => false,
381
			'message' => 'srf-paramdesc-graphlabel',
382
		];
383
384
		$params['graphlink'] = [
385
			'type' => 'boolean',
386
			'default' => false,
387
			'message' => 'srf-paramdesc-graphlink',
388
		];
389
390
		$params['graphcolor'] = [
391
			'type' => 'boolean',
392
			'default' => false,
393
			'message' => 'srf-paramdesc-graphcolor',
394
		];
395
396
		$params['arrowdirection'] = [
397
			'aliases' => 'rankdir',
398
			'default' => 'LR',
399
			'message' => 'srf-paramdesc-rankdir',
400
			'values'  => [ 'LR', 'RL', 'TB', 'BT' ],
401
		];
402
403
		$params['nodeshape'] = [
404
			'default' => false,
405
			'message' => 'srf-paramdesc-graph-nodeshape',
406
			'manipulatedefault' => false,
407
			'values' => self::$NODE_SHAPES,
408
		];
409
410
		$params['relation'] = [
411
			'default' => 'child',
412
			'message' => 'srf-paramdesc-graph-relation',
413
			'manipulatedefault' => false,
414
			'values' => [ 'parent', 'child' ],
415
		];
416
417
		$params['nameproperty'] = [
418
			'default' => false,
419
			'message' => 'srf-paramdesc-graph-nameprop',
420
			'manipulatedefault' => false,
421
		];
422
423
		$params['wordwraplimit'] = [
424
			'type' => 'integer',
425
			'default' => 25,
426
			'message' => 'srf-paramdesc-graph-wwl',
427
			'manipulatedefault' => false,
428
		];
429
430
		$params['nodelabel'] = [
431
			'default' => '',
432
			'message' => 'srf-paramdesc-nodelabel',
433
			'values' => self::$NODE_LABELS,
434
		];
435
436
		return $params;
437
	}
438
}
439