TreeResultPrinter   A
last analyzed

Complexity

Total Complexity 41

Size/Duplication

Total Lines 357
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Test Coverage

Coverage 92.13%

Importance

Changes 0
Metric Value
wmc 41
lcom 1
cbo 4
dl 0
loc 357
ccs 117
cts 127
cp 0.9213
rs 9.1199
c 0
b 0
f 0

16 Methods

Rating   Name   Duplication   Size   Complexity  
A getName() 0 5 1
A getQueryResult() 0 8 2
A setQueryResult() 0 3 1
A postProcessParameters() 0 15 3
A getTemplateCall() 0 8 2
A getParamDefinitions() 0 36 1
A buildTreeFromQueryResult() 0 10 3
A getRootHash() 0 16 3
A getHashOfNodes() 0 16 2
A getLinker() 0 3 1
A getLinkerForColumn() 0 3 1
A initalizeStandardTemplateParameters() 0 12 2
A buildLinesFromTree() 0 13 1
A addError() 0 8 1
B getResultText() 0 53 8
B buildTreeFromNodeList() 0 44 9

How to fix   Complexity   

Complex Class

Complex classes like TreeResultPrinter often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use TreeResultPrinter, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace SRF\Formats\Tree;
4
5
/**
6
 * File holding the Tree class.
7
 *
8
 * @author Stephan Gambke
9
 */
10
11
use Exception;
12
use Html;
13
use SMW\DIProperty;
14
use SMW\DIWikiPage;
15
use SMW\ListResultPrinter;
16
use SMWQueryResult;
17
use Title;
18
19
/**
20
 * Result printer that prints query results as a tree (nested html lists).
21
 *
22
 * The available formats are 'tree', 'ultree', 'oltree'. 'tree' is an alias of
23
 * 'ultree'. In an #ask query the parameter 'parent' must be set to contain the
24
 * name of the property, that gives the parent page of the subject page.
25
 *
26
 */
27
class TreeResultPrinter extends ListResultPrinter {
28
29
	private $standardTemplateParameters;
30
31
	/**
32
	 * @var SMWQueryResult | null
33
	 */
34
	private $queryResult = null;
35
36
	/**
37
	 * (non-PHPdoc)
38
	 * @see SMWResultPrinter::getName()
39
	 */
40
	public function getName() {
41
		// Give grep a chance to find the usages:
42
		// srf-printername-tree, srf-printername-ultree, srf-printername-oltree
43
		return \Message::newFromKey( 'srf-printername-' . $this->mFormat )->text();
44
	}
45
46
	/**
47
	 * @return SMWQueryResult
48
	 * @throws Exception
49
	 */
50 5
	public function getQueryResult() {
51
52 5
		if ( $this->queryResult === null ) {
53
			throw new Exception( __METHOD__ . ' called outside of ' . __CLASS__ . '::getResultText().' );
54
		}
55
56 5
		return $this->queryResult;
57
	}
58
59
	/**
60
	 * @param SMWQueryResult | null $queryResult
61
	 */
62 7
	public function setQueryResult( $queryResult ) {
63 7
		$this->queryResult = $queryResult;
64 7
	}
65
66
	/**
67
	 * @see ResultPrinter::postProcessParameters()
68
	 */
69 8
	protected function postProcessParameters() {
70
71 8
		parent::postProcessParameters();
72
73
		// Don't support pagination in trees
74 8
		$this->mSearchlabel = null;
75
76
		// Allow "_" for encoding spaces, as documented
77 8
		$this->params['sep'] = str_replace( '_', ' ', $this->params['sep'] );
78
79 8
		if ( !ctype_digit( strval( $this->params['start level'] ) ) || $this->params['start level'] < 1 ) {
80
			$this->params['start level'] = 1;
81
		}
82
83 8
	}
84
85
	/**
86
	 * Return serialised results in specified format.
87
	 *
88
	 * @param SMWQueryResult $queryResult
89
	 * @param $outputmode
90
	 *
91
	 * @return string
92
	 */
93 7
	protected function getResultText( SMWQueryResult $queryResult, $outputmode ) {
94
95 7
		$this->setQueryResult( $queryResult );
96
97 7
		if ( $this->params['parent'] === '' ) {
98 2
			$this->addError( 'srf-tree-noparentprop' );
99 2
			return '';
100
		}
101
102 5
		$rootHash = $this->getRootHash();
103
104 5
		if ( $rootHash === false ) {
105
			$this->addError( 'srf-tree-rootinvalid', $this->params['root'] );
106
			return '';
107
		}
108
109 5
		$this->hasTemplates =
110 5
			$this->params['introtemplate'] !== '' ||
111 5
			$this->params['outrotemplate'] !== '' ||
112 5
			$this->params['template'] !== '';
113
114 5
		if ( $this->hasTemplates ) {
115 3
			$this->initalizeStandardTemplateParameters();
116
		}
117
118 5
		$tree = $this->buildTreeFromQueryResult( $rootHash );
119 5
		$lines = $this->buildLinesFromTree( $tree );
120
121
		// Display default if the result is empty
122 5
		if ( count( $lines ) === 0 ) {
123
			return $this->params['default'];
124
		}
125
126
		// FIXME: Linking to further events ($this->linkFurtherResults())
127
		// does not make sense for tree format. But maybe display a warning?
128
129 5
		$resultText = join(
130 5
			"\n",
131 5
			array_merge(
132 5
				[ $this->getTemplateCall( $this->params['introtemplate'] ) ],
133
				$lines,
134 5
				[ $this->getTemplateCall( $this->params['outrotemplate'] ) ]
135
			)
136
		);
137
138 5
		$this->setQueryResult( null );
139
140 5
		if ( trim( $this->params[ 'class' ] ) === '' ) {
141 5
			return $resultText;
142
		}
143
		
144 1
		return Html::rawElement( 'div', [ 'class' => $this->params[ 'class' ] ], $resultText );
145
	}
146
147
	/**
148
	 * @param string $templateName
149
	 * @param string[] $params
150
	 *
151
	 * @return string
152
	 */
153 5
	public function getTemplateCall( $templateName, $params = [] ) {
154
155 5
		if ( $templateName === '' ) {
156 5
			return '';
157
		}
158
159 3
		return '{{' . $templateName . '|' . join( '|', $params ) . $this->standardTemplateParameters . '}}';
160
	}
161
162
	/**
163
	 * @see SMWResultPrinter::getParamDefinitions
164
	 *
165
	 * @since 1.8
166
	 *
167
	 * @param $definitions array of IParamDefinition
168
	 *
169
	 * @return array of IParamDefinition|array
170
	 * @throws Exception
171
	 */
172 8
	public function getParamDefinitions( array $definitions ) {
173 8
		$params = parent::getParamDefinitions( $definitions );
174
175 8
		$params['parent'] = [
176
			'default' => '',
177
			'message' => 'srf-paramdesc-tree-parent',
178
		];
179
180 8
		$params['root'] = [
181
			'default' => '',
182
			'message' => 'srf-paramdesc-tree-root',
183
		];
184
185 8
		$params['start level'] = [
186
			'default' => 1,
187
			'message' => 'srf-paramdesc-tree-startlevel',
188
			'type' => 'integer',
189
		];
190
191 8
		$params['sep'] = [
192
			'default' => ', ',
193
			'message' => 'smw-paramdesc-sep',
194
		];
195
196 8
		$params['template arguments'] = [
197
			'default' => '',
198
			'message' => 'smw-paramdesc-template-arguments',
199
		];
200
201 8
		$params['class'] = [
202
			'default' => '',
203
			'message' => 'srf-paramdesc-class',
204
		];
205
206 8
		return $params;
207
	}
208
209
	/**
210
	 * @param string $rootHash
211
	 *
212
	 * @return TreeNode
213
	 */
214 5
	protected function buildTreeFromQueryResult( $rootHash ) {
215
216 5
		$nodes = $this->getHashOfNodes();
217
218 5
		if ( $rootHash !== '' && !array_key_exists( $rootHash, $nodes ) ) {
219
			return new TreeNode();
220
		}
221
222 5
		return $this->buildTreeFromNodeList( $rootHash, $nodes );
223
	}
224
225
	/**
226
	 * @return string | false
227
	 */
228 5
	protected function getRootHash() {
229
230 5
		if ( $this->params['root'] === '' ) {
231 5
			return '';
232
		}
233
234
		// get the title object of the root page
235 1
		$rootTitle = Title::newFromText( $this->params['root'] );
236
237 1
		if ( $rootTitle !== null ) {
238 1
			return DIWikiPage::newFromTitle( $rootTitle )->getSerialization();
239
		}
240
241
		return false;
242
243
	}
244
245
	/**
246
	 * @return TreeNode[]
247
	 */
248 5
	protected function getHashOfNodes() {
249
250
		/** @var TreeNode[] $nodes */
251 5
		$nodes = [];
252
253 5
		$queryResult = $this->getQueryResult();
254
255 5
		$row = $queryResult->getNext();
256 5
		while ( $row !== false ) {
257 5
			$node = new TreeNode( $row );
258 5
			$nodes[$node->getHash()] = $node;
259 5
			$row = $queryResult->getNext();
260
		}
261
262 5
		return $nodes;
263
	}
264
265
	/**
266
	 * Returns a linker object for making hyperlinks
267
	 *
268
	 * @return \Linker
269
	 */
270 1
	public function getLinker( $firstcol = false ) {
271 1
		return $this->mLinker;
272
	}
273
274
	/**
275
	 * Depending on current linking settings, returns a linker object
276
	 * for making hyperlinks or NULL if no links should be created.
277
	 *
278
	 * @param int $column Column number
279
	 *
280
	 * @return \Linker|null
281
	 */
282 5
	public function getLinkerForColumn( $column ) {
283 5
		return parent::getLinker( $column === 0 );
0 ignored issues
show
Comprehensibility Bug introduced by Stephan Gambke
It seems like you call parent on a different method (getLinker() instead of getLinkerForColumn()). Are you sure this is correct? If so, you might want to change this to $this->getLinker().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
284
	}
285
286 3
	private function initalizeStandardTemplateParameters() {
287
288 3
		$query = $this->getQueryResult()->getQuery();
289 3
		$userparam = trim( $this->params[ 'userparam' ] );
290
291 3
		$this->standardTemplateParameters =
292 3
			( $userparam !== '' ? ( '|userparam=' . $userparam ) : '' ) .
293 3
			'|smw-resultquerycondition=' . $query->getQueryString() .
294 3
			'|smw-resultquerylimit=' . $query->getLimit() .
295 3
			'|smw-resultqueryoffset=' . $query->getOffset();
296
297 3
	}
298
299
	/**
300
	 * @param string $rootHash
301
	 * @param TreeNode[] $nodes
302
	 *
303
	 * @return TreeNode
304
	 * @throws \Exception
305
	 */
306 5
	protected function buildTreeFromNodeList( $rootHash, $nodes ) {
307
308 5
		$isRootSpecified = $rootHash !== '';
309
310 5
		$root = new TreeNode();
311 5
		if ( $isRootSpecified ) {
312 1
			$root->addChild( $nodes[$rootHash] );
313
		}
314
315 5
		$store = $this->getQueryResult()->getStore();
316 5
		$parentPointerProperty = DIProperty::newFromUserLabel( $this->params['parent'] );
317
318 5
		foreach ( $nodes as $hash => $node ) {
319
320 5
			$parents = $store->getPropertyValues(
321 5
				$node->getResultSubject(),
322
				$parentPointerProperty
323
			);
324
325 5
			if ( empty( $parents ) && !$isRootSpecified ) {
326
327 5
				$root->addChild( $node );
328
329
			} else {
330
331 4
				foreach ( $parents as $parent ) {
332
333 4
					$parentHash = $parent->getSerialization();
334
335
					try {
336 4
						if ( array_key_exists( $parentHash, $nodes ) ) {
337 4
							$nodes[$parentHash]->addChild( $node );
338
						} elseif ( !$isRootSpecified ) {
339 4
							$root->addChild( $node );
340
						}
341
					}
342 1
					catch ( Exception $e ) {
343 1
						$this->addError( $e->getMessage(), $node->getResultSubject()->getTitle()->getPrefixedText() );
344
					}
345
				}
346
			}
347
		}
348 5
		return $root;
349
	}
350
351
	/**
352
	 * @param TreeNode $tree
353
	 *
354
	 * @return mixed
355
	 */
356 5
	protected function buildLinesFromTree( $tree ) {
357
		$nodePrinterConfiguration = [
358 5
			'format' => trim( $this->params['format'] ),
359 5
			'template' => trim( $this->params['template'] ),
360 5
			'headers' => $this->params['headers'],
361 5
			'named args' => $this->params['named args'],
362 5
			'sep' => $this->params['sep'],
363
		];
364
365 5
		$visitor = new TreeNodePrinter( $this, $nodePrinterConfiguration );
366 5
		$lines = $tree->accept( $visitor );
367 5
		return $lines;
368
	}
369
370
	/**
371
	 * @param string $msgkey
372
	 * @param string | string[] $params
373
	 */
374 3
	protected function addError( $msgkey, $params = [] ) {
375
376 3
		parent::addError(
377 3
			\Message::newFromKey( $msgkey )
378 3
				->params( $params )
379 3
				->inContentLanguage()->text()
380
		);
381 3
	}
382
383
}
384
385