Completed
Pull Request — master (#496)
by
unknown
32:41 queued 12:40
created

SRFGraph::getGVForDataValue()   F

Complexity

Conditions 15
Paths 486

Size

Total Lines 58

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 240

Importance

Changes 0
Metric Value
dl 0
loc 58
ccs 0
cts 24
cp 0
rs 2.4638
c 0
b 0
f 0
cc 15
nc 486
nop 5
crap 240

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
/**
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
	const NODELABEL_DISPLAYTITLE = 'displaytitle';
19
20
	public static $NODE_LABELS = [
21
		self::NODELABEL_DISPLAYTITLE,
22
	];
23
24
	public static $NODE_SHAPES = [
25
		'box',
26
		'box3d',
27
		'circle',
28
		'component',
29
		'diamond',
30
		'doublecircle',
31
		'doubleoctagon',
32
		'egg',
33
		'ellipse',
34
		'folder',
35
		'hexagon',
36
		'house',
37
		'invhouse',
38
		'invtrapezium',
39
		'invtriangle',
40
		'Mcircle',
41
		'Mdiamond',
42
		'Msquare',
43
		'none',
44
		'note',
45
		'octagon',
46
		'parallelogram',
47
		'pentagon ',
48
		'plaintext',
49
		'point',
50
		'polygon',
51
		'rect',
52
		'rectangle',
53
		'septagon',
54
		'square',
55
		'tab',
56
		'trapezium',
57
		'triangle',
58
		'tripleoctagon',
59
	];
60
61
	protected $m_graphName;
62
	protected $m_graphLabel;
63
	protected $m_graphColor;
64
	protected $m_graphLegend;
65
	protected $m_graphLink;
66
	protected $m_rankdir;
67
	protected $m_graphSize;
68
	protected $m_labelArray = [];
69
	protected $m_graphColors = [
70
		'black',
71
		'red',
72
		'green',
73
		'blue',
74
		'darkviolet',
75
		'gold',
76
		'deeppink',
77
		'brown',
78
		'bisque',
79
		'darkgreen',
80
		'yellow',
81
		'darkblue',
82
		'magenta',
83
		'steelblue2' ];
84
	protected $m_nameProperty;
85
	protected $m_nodeShape;
86
	protected $m_parentRelation;
87
	protected $m_wordWrapLimit;
88
	protected $m_nodeLabel;
89
90
	/**
91
	 * (non-PHPdoc)
92
	 * @see SMWResultPrinter::handleParameters()
93
	 */
94
	protected function handleParameters( array $params, $outputmode ) {
95
		parent::handleParameters( $params, $outputmode );
96
97
		$this->m_graphName = trim( $params['graphname'] );
98
		$this->m_graphSize = trim( $params['graphsize'] );
99
100
		$this->m_graphLegend = $params['graphlegend'];
101
		$this->m_graphLabel = $params['graphlabel'];
102
103
		$this->m_rankdir = strtoupper( trim( $params['arrowdirection'] ) );
104
105
		$this->m_graphLink = $params['graphlink'];
106
		$this->m_graphColor = $params['graphcolor'];
107
108
		$this->m_nameProperty = $params['nameproperty'] === false ? false : trim( $params['nameproperty'] );
109
110
		$this->m_parentRelation = strtolower( trim( $params['relation'] ) ) == 'parent';
111
112
		$this->m_nodeShape = $params['nodeshape'];
113
		$this->m_wordWrapLimit = $params['wordwraplimit'];
114
115
		$this->m_nodeLabel = $params['nodelabel'];
116
	}
117
118
	protected function getResultText( SMWQueryResult $res, $outputmode ) {
119
120
		if ( !class_exists( 'GraphViz' )
121
			&& !class_exists( '\\MediaWiki\\Extension\\GraphViz\\GraphViz' )
122
		) {
123
			wfWarn( 'The SRF Graph printer needs the GraphViz extension to be installed.' );
124
			return '';
125
		}
126
127
		$this->isHTML = true;
128
129
		$graphInput = "digraph $this->m_graphName {";
130
		if ( $this->m_graphSize != '' ) {
131
			$graphInput .= "size=\"$this->m_graphSize\";";
132
		}
133
		if ( $this->m_nodeShape ) {
134
			$graphInput .= "node [shape=$this->m_nodeShape];";
135
		}
136
		$graphInput .= "rankdir=$this->m_rankdir;";
137
138
		while ( $row = $res->getNext() ) {
139
			$graphInput .= $this->getGVForItem( $row, $outputmode );
140
		}
141
142
		$graphInput .= "}";
143
144
		// Calls graphvizParserHook function from MediaWiki GraphViz extension
145
		$result = $GLOBALS['wgParser']->recursiveTagParse( "<graphviz>$graphInput</graphviz>" );
146
147
		if ( $this->m_graphLegend && $this->m_graphColor ) {
148
			$arrayCount = 0;
149
			$arraySize = count( $this->m_graphColors );
150
			$result .= "<P>";
151
152
			foreach ( $this->m_labelArray as $m_label ) {
153
				if ( $arrayCount >= $arraySize ) {
154
					$arrayCount = 0;
155
				}
156
157
				$color = $this->m_graphColors[$arrayCount];
158
				$result .= "<font color=$color>$color: $m_label </font><br />";
159
160
				$arrayCount += 1;
161
			}
162
163
			$result .= "</P>";
164
		}
165
166
		return $result;
167
	}
168
169
	/**
170
	 * Returns the GV for a single subject.
171
	 *
172
	 * @since 1.5.4
173
	 *
174
	 * @param array $row
175
	 * @param $outputmode
176
	 *
177
	 * @return string
178
	 */
179
	protected function getGVForItem( array /* of SMWResultArray */
180
	$row, $outputmode ) {
181
		$segments = [];
182
183
		// Loop throught all fields of the record.
184
		foreach ( $row as $i => $resultArray ) {
185
186
			// Loop throught all the parts of the field value.
187
			while ( ( $object = $resultArray->getNextDataValue() ) !== false ) {
188
				$propName = $resultArray->getPrintRequest()->getLabel();
189
				$isName = $this->m_nameProperty ? ( $i != 0 && $this->m_nameProperty === $propName ) : $i == 0;
190
191
				if ( $isName ) {
192
					$name = $this->getWordWrappedText( $object->getShortText( $outputmode ), $this->m_wordWrapLimit );
193
				}
194
195
				if ( !( $this->m_nameProperty && $i == 0 ) ) {
196
					$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...
197
				}
198
			}
199
		}
200
201
		return implode( "\n", $segments );
202
	}
203
204
	/**
205
	 * Returns the GV for a single SMWDataValue.
206
	 *
207
	 * @since 1.5.4
208
	 *
209
	 * @param SMWDataValue $object
210
	 * @param $outputmode
211
	 * @param boolean $isName Is this the name that should be used for the node?
212
	 * @param string $name
213
	 * @param string $labelName
214
	 *
215
	 * @return string
216
	 */
217
	protected function getGVForDataValue( SMWDataValue $object, $outputmode, $isName, $name, $labelName ) {
218
		$graphInput = '';
219
		$nodeLabel = '';
220
		$text = $object->getShortText( $outputmode );
221
222
		if ( $this->m_graphLink ) {
223
			$nodeLinkURL = "[[" . $text . "]]";
224
		}
225
226
		$text = $this->getWordWrappedText( $text, $this->m_wordWrapLimit );
227
228
		if ( $this->m_nodeLabel === self::NODELABEL_DISPLAYTITLE && $object instanceof SMWWikiPageValue ) {
229
			$objectDisplayTitle = $object->getDisplayTitle();
230
			if ( !empty( $objectDisplayTitle )) {
231
				$nodeLabel = $this->getWordWrappedText( $objectDisplayTitle, $this->m_wordWrapLimit );
232
			}
233
		}
234
235
		if ( $this->m_graphLink ) {
236
			if( $nodeLabel === '' ) {
237
				$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...
238
			} else {
239
				$graphInput .= " \"$text\" [URL = \"$nodeLinkURL\", label = \"$nodeLabel\"]; ";
240
			}
241
		}
242
243
		if ( !$isName ) {
244
			$graphInput .= $this->m_parentRelation ? " \"$text\" -> \"$name\" " : " \"$name\" -> \"$text\" ";
245
246
			if ( $this->m_graphLabel || $this->m_graphColor ) {
247
				$graphInput .= ' [';
248
249
				if ( array_search( $labelName, $this->m_labelArray, true ) === false ) {
250
					$this->m_labelArray[] = $labelName;
251
				}
252
253
				$color = $this->m_graphColors[array_search( $labelName, $this->m_labelArray, true )];
254
255
				if ( $this->m_graphLabel ) {
256
					$graphInput .= "label=\"$labelName\"";
257
					if ( $this->m_graphColor ) {
258
						$graphInput .= ",fontcolor=$color,";
259
					}
260
				}
261
262
				if ( $this->m_graphColor ) {
263
					$graphInput .= "color=$color";
264
				}
265
266
				$graphInput .= ']';
267
268
			}
269
270
			$graphInput .= ';';
271
		}
272
273
		return $graphInput;
274
	}
275
276
	/**
277
	 * Returns the word wrapped version of the provided text.
278
	 *
279
	 * @since 1.5.4
280
	 *
281
	 * @param string $text
282
	 * @param integer $charLimit
283
	 *
284
	 * @return string
285
	 */
286
	protected function getWordWrappedText( $text, $charLimit ) {
287
		$charLimit = max( [ $charLimit, 1 ] );
288
		$segments = [];
289
290
		while ( strlen( $text ) > $charLimit ) {
291
			// Find the last space in the allowed range.
292
			$splitPosition = strrpos( substr( $text, 0, $charLimit ), ' ' );
293
294
			if ( $splitPosition === false ) {
295
				// If there is no space (lond word), find the next space.
296
				$splitPosition = strpos( $text, ' ' );
297
298
				if ( $splitPosition === false ) {
299
					// If there are no spaces, everything goes on one line.
300
					$splitPosition = strlen( $text ) - 1;
301
				}
302
			}
303
304
			$segments[] = substr( $text, 0, $splitPosition + 1 );
305
			$text = substr( $text, $splitPosition + 1 );
306
		}
307
308
		$segments[] = $text;
309
310
		return implode( '\n', $segments );
311
	}
312
313
	/**
314
	 * (non-PHPdoc)
315
	 * @see SMWResultPrinter::getName()
316
	 */
317
	public function getName() {
318
		return wfMessage( 'srf-printername-graph' )->text();
319
	}
320
321
	/**
322
	 * @see SMWResultPrinter::getParamDefinitions
323
	 *
324
	 * @since 1.8
325
	 *
326
	 * @param $definitions array of IParamDefinition
327
	 *
328
	 * @return array of IParamDefinition|array
329
	 */
330
	public function getParamDefinitions( array $definitions ) {
331
		$params = parent::getParamDefinitions( $definitions );
332
333
		$params['graphname'] = [
334
			'default' => 'QueryResult',
335
			'message' => 'srf-paramdesc-graphname',
336
		];
337
338
		$params['graphsize'] = [
339
			'type' => 'string',
340
			'default' => '',
341
			'message' => 'srf-paramdesc-graphsize',
342
			'manipulatedefault' => false,
343
		];
344
345
		$params['graphlegend'] = [
346
			'type' => 'boolean',
347
			'default' => false,
348
			'message' => 'srf-paramdesc-graphlegend',
349
		];
350
351
		$params['graphlabel'] = [
352
			'type' => 'boolean',
353
			'default' => false,
354
			'message' => 'srf-paramdesc-graphlabel',
355
		];
356
357
		$params['graphlink'] = [
358
			'type' => 'boolean',
359
			'default' => false,
360
			'message' => 'srf-paramdesc-graphlink',
361
		];
362
363
		$params['graphcolor'] = [
364
			'type' => 'boolean',
365
			'default' => false,
366
			'message' => 'srf-paramdesc-graphcolor',
367
		];
368
369
		$params['arrowdirection'] = [
370
			'aliases' => 'rankdir',
371
			'default' => 'LR',
372
			'message' => 'srf-paramdesc-rankdir',
373
			'values' => [ 'LR', 'RL', 'TB', 'BT' ],
374
		];
375
376
		$params['nodeshape'] = [
377
			'default' => false,
378
			'message' => 'srf-paramdesc-graph-nodeshape',
379
			'manipulatedefault' => false,
380
			'values' => self::$NODE_SHAPES,
381
		];
382
383
		$params['relation'] = [
384
			'default' => 'child',
385
			'message' => 'srf-paramdesc-graph-relation',
386
			'manipulatedefault' => false,
387
			'values' => [ 'parent', 'child' ],
388
		];
389
390
		$params['nameproperty'] = [
391
			'default' => false,
392
			'message' => 'srf-paramdesc-graph-nameprop',
393
			'manipulatedefault' => false,
394
		];
395
396
		$params['wordwraplimit'] = [
397
			'type' => 'integer',
398
			'default' => 25,
399
			'message' => 'srf-paramdesc-graph-wwl',
400
			'manipulatedefault' => false,
401
		];
402
403
		$params['nodelabel'] = [
404
			'default' => [],
405
			'message' => 'srf-paramdesc-nodelabel',
406
			'values' => self::$NODE_LABELS,
407
		];
408
409
		return $params;
410
	}
411
412
}
413