Completed
Push — master ( dd6e74...158651 )
by Karsten
06:23
created

TreeResultPrinter::buildTreeFromQueryResult()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3.072

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 4
cts 5
cp 0.8
rs 9.9332
c 0
b 0
f 0
cc 3
nc 2
nop 1
crap 3.072
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 5
				$lines,
134 5
				[ $this->getTemplateCall( $this->params['outrotemplate'] ) ]
135
			)
136
		);
137
138 5
		$this->setQueryResult( null );
139
140 5
		return Html::rawElement( 'div', [ 'class' => 'srf-tree' ], $resultText );
141
	}
142
143
	/**
144
	 * @param string $templateName
145
	 * @param string[] $params
146
	 *
147
	 * @return string
148
	 */
149 5
	public function getTemplateCall( $templateName, $params = [] ) {
150
151 5
		if ( $templateName === '' ) {
152 5
			return '';
153
		}
154
155 3
		return '{{' . $templateName . '|' . join( '|', $params ) . $this->standardTemplateParameters . '}}';
156
	}
157
158
	/**
159
	 * @see SMWResultPrinter::getParamDefinitions
160
	 *
161
	 * @since 1.8
162
	 *
163
	 * @param $definitions array of IParamDefinition
164
	 *
165
	 * @return array of IParamDefinition|array
166
	 * @throws Exception
167
	 */
168 8
	public function getParamDefinitions( array $definitions ) {
169 8
		$params = parent::getParamDefinitions( $definitions );
170
171 8
		$params['parent'] = [
172
			'default' => '',
173
			'message' => 'srf-paramdesc-tree-parent',
174
		];
175
176 8
		$params['root'] = [
177
			'default' => '',
178
			'message' => 'srf-paramdesc-tree-root',
179
		];
180
181 8
		$params['start level'] = [
182
			'default' => 1,
183
			'message' => 'srf-paramdesc-tree-startlevel',
184
			'type' => 'integer',
185
		];
186
187 8
		$params['sep'] = [
188
			'default' => ', ',
189
			'message' => 'smw-paramdesc-sep',
190
		];
191
192 8
		$params['template arguments'] = [
193
			'default' => '',
194
			'message' => 'smw-paramdesc-template-arguments',
195
		];
196
197 8
		return $params;
198
	}
199
200
	/**
201
	 * @param string $rootHash
202
	 *
203
	 * @return TreeNode
204
	 */
205 5
	protected function buildTreeFromQueryResult( $rootHash ) {
206
207 5
		$nodes = $this->getHashOfNodes();
208
209 5
		if ( $rootHash !== '' && !array_key_exists( $rootHash, $nodes ) ) {
210
			return new TreeNode();
211
		}
212
213 5
		return $this->buildTreeFromNodeList( $rootHash, $nodes );
214
	}
215
216
	/**
217
	 * @return string | false
218
	 */
219 5
	protected function getRootHash() {
220
221 5
		if ( $this->params['root'] === '' ) {
222 5
			return '';
223
		}
224
225
		// get the title object of the root page
226 1
		$rootTitle = Title::newFromText( $this->params['root'] );
227
228 1
		if ( $rootTitle !== null ) {
229 1
			return DIWikiPage::newFromTitle( $rootTitle )->getSerialization();
230
		}
231
232
		return false;
233
234
	}
235
236
	/**
237
	 * @return TreeNode[]
238
	 */
239 5
	protected function getHashOfNodes() {
240
241
		/** @var TreeNode[] $nodes */
242 5
		$nodes = [];
243
244 5
		$queryResult = $this->getQueryResult();
245
246 5
		$row = $queryResult->getNext();
247 5
		while ( $row !== false ) {
248 5
			$node = new TreeNode( $row );
249 5
			$nodes[$node->getHash()] = $node;
250 5
			$row = $queryResult->getNext();
251
		}
252
253 5
		return $nodes;
254
	}
255
256
	/**
257
	 * Returns a linker object for making hyperlinks
258
	 *
259
	 * @return \Linker
260
	 */
261 1
	public function getLinker( $firstcol = false ) {
262 1
		return $this->mLinker;
263
	}
264
265
	/**
266
	 * Depending on current linking settings, returns a linker object
267
	 * for making hyperlinks or NULL if no links should be created.
268
	 *
269
	 * @param int $column Column number
270
	 *
271
	 * @return \Linker|null
272
	 */
273 5
	public function getLinkerForColumn( $column ) {
274 5
		return parent::getLinker( $column === 0 );
0 ignored issues
show
Comprehensibility Bug introduced by
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...
275
	}
276
277 3
	private function initalizeStandardTemplateParameters() {
278
279 3
		$query = $this->getQueryResult()->getQuery();
280 3
		$userparam = trim( $this->params[ 'userparam' ] );
281
282 3
		$this->standardTemplateParameters =
283 3
			( $userparam !== '' ? ( '|userparam=' . $userparam ) : '' ) .
284 3
			'|smw-resultquerycondition=' . $query->getQueryString() .
285 3
			'|smw-resultquerylimit=' . $query->getLimit() .
286 3
			'|smw-resultqueryoffset=' . $query->getOffset();
287
288 3
	}
289
290
	/**
291
	 * @param string $rootHash
292
	 * @param TreeNode[] $nodes
293
	 *
294
	 * @return TreeNode
295
	 * @throws \Exception
296
	 */
297 5
	protected function buildTreeFromNodeList( $rootHash, $nodes ) {
298
299 5
		$isRootSpecified = $rootHash !== '';
300
301 5
		$root = new TreeNode();
302 5
		if ( $isRootSpecified ) {
303 1
			$root->addChild( $nodes[$rootHash] );
304
		}
305
306 5
		$store = $this->getQueryResult()->getStore();
307 5
		$parentPointerProperty = DIProperty::newFromUserLabel( $this->params['parent'] );
308
309 5
		foreach ( $nodes as $hash => $node ) {
310
311 5
			$parents = $store->getPropertyValues(
312 5
				$node->getResultSubject(),
313 5
				$parentPointerProperty
314
			);
315
316 5
			if ( empty( $parents ) && !$isRootSpecified ) {
317
318 5
				$root->addChild( $node );
319
320
			} else {
321
322 4
				foreach ( $parents as $parent ) {
323
324 4
					$parentHash = $parent->getSerialization();
325
326
					try {
327 4
						if ( array_key_exists( $parentHash, $nodes ) ) {
328 4
							$nodes[$parentHash]->addChild( $node );
329
						} elseif ( !$isRootSpecified ) {
330 4
							$root->addChild( $node );
331
						}
332
					}
333 1
					catch ( Exception $e ) {
334 5
						$this->addError( $e->getMessage(), $node->getResultSubject()->getTitle()->getPrefixedText() );
335
					}
336
				}
337
			}
338
		}
339 5
		return $root;
340
	}
341
342
	/**
343
	 * @param TreeNode $tree
344
	 *
345
	 * @return mixed
346
	 */
347 5
	protected function buildLinesFromTree( $tree ) {
348
		$nodePrinterConfiguration = [
349 5
			'format' => trim( $this->params['format'] ),
350 5
			'template' => trim( $this->params['template'] ),
351 5
			'headers' => $this->params['headers'],
352 5
			'named args' => $this->params['named args'],
353 5
			'sep' => $this->params['sep'],
354
		];
355
356 5
		$visitor = new TreeNodePrinter( $this, $nodePrinterConfiguration );
357 5
		$lines = $tree->accept( $visitor );
358 5
		return $lines;
359
	}
360
361
	/**
362
	 * @param string $msgkey
363
	 * @param string | string[] $params
364
	 */
365 3
	protected function addError( $msgkey, $params = [] ) {
366
367 3
		parent::addError(
368 3
			\Message::newFromKey( $msgkey )
369 3
				->params( $params )
370 3
				->inContentLanguage()->text()
371
		);
372 3
	}
373
374
}
375
376