Completed
Pull Request — master (#538)
by
unknown
12:27
created

GraphFormatter::buildGraph()   F

Complexity

Conditions 18
Paths 640

Size

Total Lines 99

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 43
CRAP Score 18.0036

Importance

Changes 0
Metric Value
dl 0
loc 99
ccs 43
cts 44
cp 0.9773
rs 0.9818
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 4
	public function __construct( $options ){
43 4
		$this->options = $options;
44 4
	}
45
46 1
	public function getGraph(){
47 1
		return $this->graph;
48
	}
49
50
	/*
51
	 * Add a single string to graph
52
	 *
53
	 * @param string $line
54
	 */
55 4
	private function add( $line ){
56 4
		$this->graph .= $line;
57 4
	}
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 4
	public function buildGraph($nodes){
68 4
		$this->add( "digraph " . $this->options->getGraphName() . " {" );
69
70
		// set fontsize and fontname of graph, nodes and edges
71 4
		$this->add( "graph [fontsize=10, fontname=\"Verdana\"]\n" );
72 4
		$this->add( "node [fontsize=10, fontname=\"Verdana\"];\n" );
73 4
		$this->add( "edge [fontsize=10, fontname=\"Verdana\"];\n" );
74
75
		// choose graphsize, nodeshapes and rank direction
76 4
		if ( $this->options->getGraphSize() != '' ) {
77 4
			$this->add("size=\"" . $this->options->getGraphSize() . "\";");
78
		}
79
80 4
		if ( $this->options->getNodeShape() != '' ) {
81 4
			$this->add( "node [shape=" . $this->options->getNodeShape() . "];" );
82
		}
83
84 4
		$this->add( "rankdir=" . $this->options->getRankDir() . ";" );
85
86
		/** @var \SRF\GraphNode $node */
87 4
		foreach ( $nodes as $node ) {
88
89
			// take "displaytitle" as node-label if it is set
90 4
			if ( $this->options->getNodeLabel() === GraphPrinter::NODELABEL_DISPLAYTITLE) {
91 4
				$objectDisplayTitle = $node->getLabel();
92 4
				if ( !empty( $objectDisplayTitle )) {
93 4
					$nodeLabel = $this->getWordWrappedText( $objectDisplayTitle,
94 4
						$this->options->getWordWrapLimit() );
95
				}
96
			}
97
98
			/**
99
			 * Add nodes to the graph
100
			 *
101
			 * @var \SRF\Graph\GraphNode $node
102
			 */
103 4
			$this->add( "\"" . $node->getID() . "\"" );
104
105 4
			if ( $this->options->isGraphLink() ) {
106
107 4
				$nodeLinkURL = "[[" . $node->getID() . "]]";
108
109 4
				if( $nodeLabel === '' ) {
110
					$this->add( " [URL = \"$nodeLinkURL\"]" );
111
				} else {
112 4
					$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 4
			$this->add( "; ");
116
		}
117
118
		/**
119
		 * Add edges to the graph
120
		 *
121
		 * @var \SRF\Graph\GraphNode $node
122
		 */
123 4
		foreach ( $nodes as $node ) {
124
125 4
			if ( count( $node->getParentNode() ) > 0 ) {
126
127 4
				foreach ( $node->getParentNode() as $parentNode ) {
128
129
					// handle parent/child switch (parentRelation)
130 4
					$this->add( $this->options->getParentRelation() ? " \"" . $parentNode['object']
131 4
						. "\" -> \"" . $node->getID() . "\""
132 4
						: " \"" . $node->getID() . "\" -> \"" . $parentNode['object'] . "\" " );
133
134 4
					if ( $this->options->isGraphLabel() || $this->options->isGraphColor()
135
					) {
136 4
						$this->add( ' [' );
137
138
						// add legend item only if missing
139 4
						if ( array_search( $parentNode['predicate'], $this->legendItem, true ) === false ) {
140 4
							$this->legendItem[] = $parentNode['predicate'];
141
						}
142
143
						// assign color
144 4
						$color = $this->graphColors[array_search( $parentNode['predicate'], $this->legendItem, true )];
145
146
						// show arrow label (graphLabel is misleading but kept for compatibility reasons)
147 4
						if ( $this->options->isGraphLabel() ) {
148 4
							$this->add( "label=\"" . $parentNode['predicate'] . "\"" );
149 4
							if ( $this->options->isGraphColor() ) {
150 4
								$this->add( ",fontcolor=$color," );
151
							}
152
						}
153
154
						// colorize arrow
155 4
						if ( $this->options->isGraphColor() ) {
156 4
							$this->add( "color=$color" );
157
						}
158 4
						$this->add( "]" );
159
					}
160 4
					$this->add( ";" );
161
				}
162
			}
163
		}
164 4
		$this->add( "}" );
165 4
	}
166
167
	/**
168
	 * Creates the graph legend
169
	 *
170
	 * @return string Html::rawElement
171
	 */
172 1
	public function getGraphLegend(){
173 1
		$itemsHtml = '';
174 1
		$colorCount = 0;
175 1
		$arraySize = count( $this->graphColors );
176
177 1
		if ( $this->options->isGraphLegend() && $this->options->isGraphColor() ) {
178 1
			foreach ( $this->legendItem as $legendLabel ) {
179 1
				if ( $colorCount >= $arraySize ) {
180
					$colorCount = 0;
181
				}
182
183 1
				$color = $this->graphColors[$colorCount];
184 1
				$itemsHtml .= Html::rawElement( 'div', [ 'class' => 'graphlegenditem', 'style' => "color: $color" ],
185 1
					"$color: $legendLabel" );
186
187 1
				$colorCount ++;
188
			}
189
		}
190
191 1
		return Html::rawElement( 'div', [ 'class' => 'graphlegend' ], "$itemsHtml");
192
	}
193
194
	/**
195
	 * Returns the word wrapped version of the provided text.
196
	 *
197
	 * @param string $text
198
	 * @param integer $charLimit
199
	 *
200
	 * @return string
201
	 */
202 4
	public static function getWordWrappedText( $text, $charLimit ) {
203 4
		$charLimit = max( [ $charLimit, 1 ] );
204 4
		$segments = [];
205
206 4
		while ( strlen( $text ) > $charLimit ) {
207
			// Find the last space in the allowed range.
208 1
			$splitPosition = strrpos( substr( $text, 0, $charLimit ), ' ' );
209
210 1
			if ( $splitPosition === false ) {
211
				// If there is no space (lond word), find the next space.
212
				$splitPosition = strpos( $text, ' ' );
213
214
				if ( $splitPosition === false ) {
215
					// If there are no spaces, everything goes on one line.
216
					$splitPosition = strlen( $text ) - 1;
217
				}
218
			}
219
220 1
			$segments[] = substr( $text, 0, $splitPosition + 1 );
221 1
			$text = substr( $text, $splitPosition + 1 );
222
		}
223
224 4
		$segments[] = $text;
225
226 4
		return implode( '\n', $segments );
227
	}
228
}