Completed
Push — master ( 0e466a...c81f6c )
by mw
06:27
created

SRFOutlineTree::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 4
cts 4
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
use SRF\Outline\TemplateBuilder;
4
5
/**
6
 * A class to print query results in an outline format, along with some
7
 * helper classes to handle the aggregation
8
 */
9
10
/**
11
 * Represents a single item, or page, in the outline - contains both the
12
 * SMWResultArray and an array of some of its values, for easier aggregation
13
 */
14
class SRFOutlineItem {
15
16
	var $mRow;
17
	var $mVals;
18
19 1
	function __construct( $row ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Comprehensibility Best Practice introduced by
It is recommend to declare an explicit visibility for __construct.

Generally, we recommend to declare visibility for all methods in your source code. This has the advantage of clearly communication to other developers, and also yourself, how this method should be consumed.

If you are not sure which visibility to choose, it is a good idea to start with the most restrictive visibility, and then raise visibility as needed, i.e. start with private, and only raise it to protected if a sub-class needs to have access, or public if an external class needs access.

Loading history...
20 1
		$this->mRow = $row;
21 1
		$this->mVals = [];
22 1
	}
23
24 1
	function addFieldValue( $field_name, $field_val ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Comprehensibility Best Practice introduced by
It is recommend to declare an explicit visibility for addFieldValue.

Generally, we recommend to declare visibility for all methods in your source code. This has the advantage of clearly communication to other developers, and also yourself, how this method should be consumed.

If you are not sure which visibility to choose, it is a good idea to start with the most restrictive visibility, and then raise visibility as needed, i.e. start with private, and only raise it to protected if a sub-class needs to have access, or public if an external class needs access.

Loading history...
25 1
		if ( array_key_exists( $field_name, $this->mVals ) ) {
26
			$this->mVals[$field_name][] = $field_val;
27
		} else {
28 1
			$this->mVals[$field_name] = [ $field_val ];
29
		}
30 1
	}
31
32 1
	function getFieldValues( $field_name ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Comprehensibility Best Practice introduced by
It is recommend to declare an explicit visibility for getFieldValues.

Generally, we recommend to declare visibility for all methods in your source code. This has the advantage of clearly communication to other developers, and also yourself, how this method should be consumed.

If you are not sure which visibility to choose, it is a good idea to start with the most restrictive visibility, and then raise visibility as needed, i.e. start with private, and only raise it to protected if a sub-class needs to have access, or public if an external class needs access.

Loading history...
33 1
		if ( array_key_exists( $field_name, $this->mVals ) ) {
34 1
			return $this->mVals[$field_name];
35
		} else {
36
			return [ wfMessage( 'srf_outline_novalue' )->text() ];
37
		}
38
	}
39
}
40
41
/**
42
 * A tree structure for holding the outline data
43
 */
44
class SRFOutlineTree {
45
46
	var $mTree;
47
	var $mUnsortedItems;
48
	var $itemCount = 0;
49
	var $leafCount = 0;
50
51 1
	function __construct( $items = [] ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Comprehensibility Best Practice introduced by
It is recommend to declare an explicit visibility for __construct.

Generally, we recommend to declare visibility for all methods in your source code. This has the advantage of clearly communication to other developers, and also yourself, how this method should be consumed.

If you are not sure which visibility to choose, it is a good idea to start with the most restrictive visibility, and then raise visibility as needed, i.e. start with private, and only raise it to protected if a sub-class needs to have access, or public if an external class needs access.

Loading history...
52 1
		$this->mTree = [];
53 1
		$this->mUnsortedItems = $items;
54 1
	}
55
56 1
	function addItem( $item ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Comprehensibility Best Practice introduced by
It is recommend to declare an explicit visibility for addItem.

Generally, we recommend to declare visibility for all methods in your source code. This has the advantage of clearly communication to other developers, and also yourself, how this method should be consumed.

If you are not sure which visibility to choose, it is a good idea to start with the most restrictive visibility, and then raise visibility as needed, i.e. start with private, and only raise it to protected if a sub-class needs to have access, or public if an external class needs access.

Loading history...
57 1
		$this->mUnsortedItems[] = $item;
58 1
		$this->itemCount++;
59 1
	}
60
61 1
	function categorizeItem( $vals, $item ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Comprehensibility Best Practice introduced by
It is recommend to declare an explicit visibility for categorizeItem.

Generally, we recommend to declare visibility for all methods in your source code. This has the advantage of clearly communication to other developers, and also yourself, how this method should be consumed.

If you are not sure which visibility to choose, it is a good idea to start with the most restrictive visibility, and then raise visibility as needed, i.e. start with private, and only raise it to protected if a sub-class needs to have access, or public if an external class needs access.

Loading history...
62 1
		foreach ( $vals as $val ) {
63 1
			if ( array_key_exists( $val, $this->mTree ) ) {
64 1
				$this->mTree[$val]->mUnsortedItems[] = $item;
65 1
				$this->mTree[$val]->leafCount++;
66
			} else {
67 1
				$this->mTree[$val] = new SRFOutlineTree( [ $item ] );
68 1
				$this->mTree[$val]->leafCount++;
69
			}
70
		}
71 1
	}
72
73 1
	function addProperty( $property ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Comprehensibility Best Practice introduced by
It is recommend to declare an explicit visibility for addProperty.

Generally, we recommend to declare visibility for all methods in your source code. This has the advantage of clearly communication to other developers, and also yourself, how this method should be consumed.

If you are not sure which visibility to choose, it is a good idea to start with the most restrictive visibility, and then raise visibility as needed, i.e. start with private, and only raise it to protected if a sub-class needs to have access, or public if an external class needs access.

Loading history...
74 1
		if ( count( $this->mUnsortedItems ) > 0 ) {
75 1
			foreach ( $this->mUnsortedItems as $item ) {
76 1
				$cur_vals = $item->getFieldValues( $property );
77 1
				$this->categorizeItem( $cur_vals, $item );
78
			}
79 1
			$this->mUnsortedItems = null;
80
		} else {
81 1
			foreach ( $this->mTree as $i => $node ) {
82 1
				$this->mTree[$i]->addProperty( $property );
83
			}
84
		}
85 1
	}
86
}
87
88
class SRFOutline extends SMWResultPrinter {
89
90
	protected $mOutlineProperties = [];
91
	protected $mInnerFormat = '';
92
93
	public function getName() {
94
		return wfMessage( 'srf_printername_outline' )->text();
95
	}
96
97
	/**
98
	 * Code mostly copied from SMW's SMWListResultPrinter::getResultText()
99
	 */
100
	function printItem( $item ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Comprehensibility Best Practice introduced by
It is recommend to declare an explicit visibility for printItem.

Generally, we recommend to declare visibility for all methods in your source code. This has the advantage of clearly communication to other developers, and also yourself, how this method should be consumed.

If you are not sure which visibility to choose, it is a good idea to start with the most restrictive visibility, and then raise visibility as needed, i.e. start with private, and only raise it to protected if a sub-class needs to have access, or public if an external class needs access.

Loading history...
101
		$first_col = true;
102
		$found_values = false; // has anything but the first column been printed?
103
		$result = "";
104
		foreach ( $item->mRow as $orig_ra ) {
105
			// handling is somewhat simpler for SMW 1.5+
106
			$realFunction = [ 'SMWQueryResult', 'getResults' ];
107
			if ( is_callable( $realFunction ) ) {
108
				// make a new copy of this, so that the call to
109
				// getNextText() will work again
110
				$ra = clone ( $orig_ra );
111
			} else {
112
				// make a new copy of this, so that the call to
113
				// getNextText() will work again
114
				$ra = new SMWResultArray( $orig_ra->getContent(), $orig_ra->getPrintRequest() );
0 ignored issues
show
Bug introduced by
The call to SMWResultArray::__construct() misses a required argument $store.

This check looks for function calls that miss required arguments.

Loading history...
115
			}
116
			$val = $ra->getPrintRequest()->getText( SMW_OUTPUT_WIKI, null );
117
			if ( in_array( $val, $this->params['outlineproperties'] ) ) {
118
				continue;
119
			}
120
			$first_value = true;
121
			while ( ( $text = $ra->getNextText( SMW_OUTPUT_WIKI, $this->mLinker ) ) !== false ) {
122
				if ( !$first_col && !$found_values ) { // first values after first column
123
					$result .= ' (';
124
					$found_values = true;
125
				} elseif ( $found_values || !$first_value ) {
126
					// any value after '(' or non-first values on first column
127
					$result .= ', ';
128
				}
129
				if ( $first_value ) { // first value in any column, print header
130
					$first_value = false;
131
					if ( $this->mShowHeaders && ( '' != $ra->getPrintRequest()->getLabel() ) ) {
132
						$result .= $ra->getPrintRequest()->getText( SMW_OUTPUT_WIKI, $this->mLinker ) . ' ';
133
					}
134
				}
135
				$result .= $text; // actual output value
136
			}
137
			$first_col = false;
138
		}
139
		if ( $found_values ) {
140
			$result .= ')';
141
		}
142
		return $result;
143
	}
144
145
	function printTree( $outline_tree, $level = 0 ) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
Comprehensibility Best Practice introduced by
It is recommend to declare an explicit visibility for printTree.

Generally, we recommend to declare visibility for all methods in your source code. This has the advantage of clearly communication to other developers, and also yourself, how this method should be consumed.

If you are not sure which visibility to choose, it is a good idea to start with the most restrictive visibility, and then raise visibility as needed, i.e. start with private, and only raise it to protected if a sub-class needs to have access, or public if an external class needs access.

Loading history...
146
		$text = "";
147
		if ( !is_null( $outline_tree->mUnsortedItems ) ) {
148
			$text .= "<ul>\n";
149
			foreach ( $outline_tree->mUnsortedItems as $item ) {
150
				$text .= "<li>{$this->printItem($item)}</li>\n";
151
			}
152
			$text .= "</ul>\n";
153
		}
154
		if ( $level > 0 ) {
155
			$text .= "<ul>\n";
156
		}
157
		$num_levels = count( $this->params['outlineproperties'] );
158
		// set font size and weight depending on level we're at
159
		$font_level = $level;
160
		if ( $num_levels < 4 ) {
161
			$font_level += ( 4 - $num_levels );
162
		}
163
		if ( $font_level == 0 ) {
164
			$font_size = 'x-large';
165
		} elseif ( $font_level == 1 ) {
166
			$font_size = 'large';
167
		} elseif ( $font_level == 2 ) {
168
			$font_size = 'medium';
169
		} else {
170
			$font_size = 'small';
171
		}
172
		if ( $font_level == 3 ) {
173
			$font_weight = 'bold';
174
		} else {
175
			$font_weight = 'regular';
176
		}
177
		foreach ( $outline_tree->mTree as $key => $node ) {
178
			$text .= "<p style=\"font-size: $font_size; font-weight: $font_weight;\">$key</p>\n";
179
			$text .= $this->printTree( $node, $level + 1 );
180
		}
181
		if ( $level > 0 ) {
182
			$text .= "</ul>\n";
183
		}
184
		return $text;
185
	}
186
187 1
	protected function getResultText( SMWQueryResult $res, $outputmode ) {
188 1
		$print_fields = [];
189 1
		foreach ( $res->getPrintRequests() as $pr ) {
190 1
			$field_name = $pr->getText( $outputmode, $this->mLinker );
191
			// only print it if it's not already part of the
192
			// outline
193 1
			if ( !in_array( $field_name, $this->params['outlineproperties'] ) ) {
194 1
				$print_fields[] = $field_name;
195
			}
196
		}
197
198
		// for each result row, create an array of the row itself
199
		// and all its sorted-on fields, and add it to the initial
200
		// 'tree'
201 1
		$outline_tree = new SRFOutlineTree();
202 1
		while ( $row = $res->getNext() ) {
203 1
			$item = new SRFOutlineItem( $row );
204 1
			foreach ( $row as $field ) {
205 1
				$field_name = $field->getPrintRequest()->getText( SMW_OUTPUT_HTML );
206 1
				if ( in_array( $field_name, $this->params['outlineproperties'] ) ) {
207 1
					while ( ( $object = $field->getNextDataValue() ) !== false ) {
208 1
						$field_val = $object->getLongWikiText( $this->mLinker );
209 1
						$item->addFieldValue( $field_name, $field_val );
210
					}
211
				}
212
			}
213 1
			$outline_tree->addItem( $item );
214
		}
215
216
		// now, cycle through the outline properties, creating the
217
		// tree
218 1
		foreach ( $this->params['outlineproperties'] as $outline_prop ) {
219 1
			$outline_tree->addProperty( $outline_prop );
220
		}
221
222 1
		if ( $this->params['template'] !== '' ) {
223 1
			$this->hasTemplates = true;
224 1
			$templateBuilder = new TemplateBuilder(
225 1
				$this->params
226
			);
227
228 1
			$templateBuilder->setLinker( $this->mLinker );
229 1
			$result = $templateBuilder->build( $outline_tree );
0 ignored issues
show
Documentation introduced by
$outline_tree is of type object<SRFOutlineTree>, but the function expects a object<SRF\Outline\OutlineTree>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
230
		} else {
231
			$result = $this->printTree( $outline_tree );
232
		}
233
234 1
		if ( $this->linkFurtherResults( $res ) ) {
235
			$link = $this->getFurtherResultsLink( $res, $outputmode );
236
237
			$result .= $link->getText( $outputmode, $this->mLinker ) . "\n";
238
		}
239
240 1
		return $result;
241
	}
242
243
	/**
244
	 * @see SMWResultPrinter::getParamDefinitions
245
	 *
246
	 * @since 1.8
247
	 *
248
	 * @param $definitions array of IParamDefinition
249
	 *
250
	 * @return array of IParamDefinition|array
251
	 */
252 1
	public function getParamDefinitions( array $definitions ) {
253 1
		$params = parent::getParamDefinitions( $definitions );
254
255 1
		$params['outlineproperties'] = [
256
			'islist' => true,
257
			'default' => [],
258
			'message' => 'srf_paramdesc_outlineproperties',
259
		];
260
261 1
		$params[] = [
262
			'name' => 'template',
263
			'message' => 'smw-paramdesc-template',
264
			'default' => '',
265
		];
266
267 1
		$params[] = [
268
			'name' => 'userparam',
269
			'message' => 'smw-paramdesc-userparam',
270
			'default' => '',
271
		];
272
273 1
		$params[] = [
274
			'name' => 'named args',
275
			'type' => 'boolean',
276
			'message' => 'smw-paramdesc-named_args',
277
			'default' => true,
278
		];
279
280 1
		return $params;
281
	}
282
283
}
284