Completed
Pull Request — master (#538)
by
unknown
13:29
created

GraphFormatter::buildGraph()   F

Complexity

Conditions 18
Paths 640

Size

Total Lines 98

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 43
CRAP Score 18.0036

Importance

Changes 0
Metric Value
dl 0
loc 98
ccs 43
cts 44
cp 0.9773
rs 1.0036
c 0
b 0
f 0
cc 18
nc 640
nop 1
crap 18.0036

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 Html;
6
7
/**
8
 *
9
 *
10
 * @see https://www.semantic-mediawiki.org/wiki/Help:Graph_format
11
 *
12
 * @license GNU GPL v2+
13
 * @since 3.2
14
 *
15
 * @author Sebastian Schmid (gesinn.it)
16
 *
17
 */
18
19
class GraphFormatter {
20
21
	private $graph = "";
22
23
	protected $graphColors = [
24
		'black',
25
		'red',
26
		'green',
27
		'blue',
28
		'darkviolet',
29
		'gold',
30
		'deeppink',
31
		'brown',
32
		'bisque',
33
		'darkgreen',
34
		'yellow',
35
		'darkblue',
36
		'magenta',
37
		'steelblue2'
38
	];
39
	private $legendItem = [];
40
	private $options = [];
41
42 3
	public function __construct( $options ){
43 3
		$this->options = $options;
44 3
	}
45
46
	public function getGraph(){
47
		return $this->graph;
48
	}
49
50
	/*
51
	 * Add a single string to graph
52
	 *
53
	 * @param string $line
54
	 */
55 3
	private function add( $line ){
56 3
		$this->graph .= $line;
57 3
	}
58
59
	/*
60
	* Creates the DOT (graph description language) which can be processed by the graphviz lib
61
	*
62
	* @see https://www.graphviz.org/
63
	* @since 3.2
64
	*
65
	* @param SRF\Graph\GraphNodes[] $nodes
66
	*/
67 3
	public function buildGraph($nodes){
68 3
		$this->add( "digraph " . $this->options['graphName'] . " {" );
69
70
		// set fontsize and fontname of graph, nodes and edges
71 3
		$this->add( "graph [fontsize=10, fontname=\"Verdana\"]\n" );
72 3
		$this->add( "node [fontsize=10, fontname=\"Verdana\"];\n" );
73 3
		$this->add( "edge [fontsize=10, fontname=\"Verdana\"];\n" );
74
75
		// choose graphsize, nodeshapes and rank direction
76 3
		if ( $this->options['graphSize'] != '' ) {
77 3
			$this->add("size=\"" . $this->options['graphSize'] . "\";");
78
		}
79
80 3
		if ( $this->options['nodeShape'] != '' ) {
81 3
			$this->add( "node [shape=" . $this->options['nodeShape'] . "];" );
82
		}
83
84 3
		$this->add( "rankdir=" . $this->options['rankDir'] . ";" );
85
86
		/** @var \SRF\GraphNode $node */
87 3
		foreach ( $nodes as $node ) {
88
89
			// take "displaytitle" as node-label if it is set
90 3
			if ( $this->options['nodeLabel'] === GraphPrinter::NODELABEL_DISPLAYTITLE) {
91 3
				$objectDisplayTitle = $node->getLabel();
92 3
				if ( !empty( $objectDisplayTitle )) {
93 3
					$nodeLabel = $this->getWordWrappedText( $objectDisplayTitle,
94 3
						$this->options['wordWrapLimit'] );
95
				}
96
			}
97
98
			/**
99
			 * Add nodes to the graph
100
			 *
101
			 * @var \SRF\Graph\GraphNode $node
102
			 */
103 3
			$this->add( "\"" . $node->getID() . "\"" );
104
105 3
			if ( $this->options['enableGraphLink'] ) {
106
107 3
				$nodeLinkURL = "[[" . $node->getID() . "]]";
108
109 3
				if( $nodeLabel === '' ) {
110
					$this->add( " [URL = \"$nodeLinkURL\"]" );
111
				} else {
112 3
					$this->add( " [URL = \"$nodeLinkURL\", label = \"$nodeLabel\"]" );
0 ignored issues
show
Bug introduced by
The variable $nodeLabel 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...
113
				}
114
			}
115 3
			$this->add( "; ");
116
		}
117
118
		/**
119
		 * Add edges to the graph
120
		 *
121
		 * @var \SRF\Graph\GraphNode $node
122
		 */
123 3
		foreach ( $nodes as $node ) {
124
125 3
			if ( count( $node->getParentNode() ) > 0 ) {
126
127 3
				foreach ( $node->getParentNode() as $parentNode ) {
128
129
					// handle parent/child switch (parentRelation)
130 3
					$this->add( $this->options['parentRelation'] ? " \"" . $parentNode['object']
131 3
						. "\" -> \"" . $node->getID() . "\""
132 3
						: " \"" . $node->getID() . "\" -> \"" . $parentNode['object'] . "\" " );
133
134 3
					if ( $this->options['showGraphLabel'] || $this->options['showGraphColor'] ) {
135 3
						$this->add( ' [' );
136
137
						// add legend item only if missing
138 3
						if ( array_search( $parentNode['predicate'], $this->legendItem, true ) === false ) {
139 3
							$this->legendItem[] = $parentNode['predicate'];
140
						}
141
142
						// assign color
143 3
						$color = $this->graphColors[array_search( $parentNode['predicate'], $this->legendItem, true )];
144
145
						// show arrow label (graphLabel is misleading but kept for compatibility reasons)
146 3
						if ( $this->options['showGraphLabel'] ) {
147 3
							$this->add( "label=\"" . $parentNode['predicate'] . "\"" );
148 3
							if ( $this->options['showGraphColor'] ) {
149 3
								$this->add( ",fontcolor=$color," );
150
							}
151
						}
152
153
						// colorize arrow
154 3
						if ( $this->options['showGraphColor'] ) {
155 3
							$this->add( "color=$color" );
156
						}
157 3
						$this->add( "]" );
158
					}
159 3
					$this->add( ";" );
160
				}
161
			}
162
		}
163 3
		$this->add( "}" );
164 3
	}
165
166
	/**
167
	 * Creates the graph legend
168
	 *
169
	 * @return string Html::rawElement
170
	 */
171 1
	public function getGraphLegend(){
172 1
		$itemsHtml = '';
173 1
		$colorCount = 0;
174 1
		$arraySize = count( $this->graphColors );
175
176 1
		if ( $this->options['showGraphLegend'] && $this->options['showGraphColor'] ) {
177 1
			foreach ( $this->legendItem as $legendLabel ) {
178 1
				if ( $colorCount >= $arraySize ) {
179
					$colorCount = 0;
180
				}
181
182 1
				$color = $this->graphColors[$colorCount];
183 1
				$itemsHtml .= Html::rawElement( 'div', [ 'class' => 'graphlegenditem', 'style' => "color: $color" ],
184 1
					"$color: $legendLabel" );
185
186 1
				$colorCount ++;
187
			}
188
		}
189
190 1
		return Html::rawElement( 'div', [ 'class' => 'graphlegend' ], "$itemsHtml");
191
	}
192
193
	/**
194
	 * Returns the word wrapped version of the provided text.
195
	 *
196
	 * @param string $text
197
	 * @param integer $charLimit
198
	 *
199
	 * @return string
200
	 */
201 3
	public static function getWordWrappedText( $text, $charLimit ) {
202 3
		$charLimit = max( [ $charLimit, 1 ] );
203 3
		$segments = [];
204
205 3
		while ( strlen( $text ) > $charLimit ) {
206
			// Find the last space in the allowed range.
207 1
			$splitPosition = strrpos( substr( $text, 0, $charLimit ), ' ' );
208
209 1
			if ( $splitPosition === false ) {
210
				// If there is no space (lond word), find the next space.
211
				$splitPosition = strpos( $text, ' ' );
212
213
				if ( $splitPosition === false ) {
214
					// If there are no spaces, everything goes on one line.
215
					$splitPosition = strlen( $text ) - 1;
216
				}
217
			}
218
219 1
			$segments[] = substr( $text, 0, $splitPosition + 1 );
220 1
			$text = substr( $text, $splitPosition + 1 );
221
		}
222
223 3
		$segments[] = $text;
224
225 3
		return implode( '\n', $segments );
226
	}
227
}