CategoryResultPrinter::getResultText()   D
last analyzed

Complexity

Conditions 21
Paths 55

Size

Total Lines 126
Code Lines 69

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 59
CRAP Score 21.21

Importance

Changes 0
Metric Value
cc 21
eloc 69
nc 55
nop 2
dl 0
loc 126
ccs 59
cts 64
cp 0.9219
crap 21.21
rs 4.6955
c 0
b 0
f 0

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 SMW;
4
5
use SMW\MediaWiki\ByLanguageCollationMapper;
6
use SMWDataItem;
7
use SMWQueryResult;
8
9
/**
10
 * Print query results in alphabetic groups displayed in columns, a la the
11
 * standard Category pages and the default view in Semantic Drilldown.
12
 * Based on SMW_QP_List by Markus Krötzsch.
13
 *
14
 * @ingroup SMWQuery
15
 *
16
 * @author David Loomer
17
 * @author Yaron Koren
18
 * @author Jeroen De Dauw < [email protected] >
19
 */
20
class CategoryResultPrinter extends ResultPrinter {
21
22
	protected $mDelim;
23
	protected $mTemplate;
24
	protected $mUserParam;
25
	protected $mNumColumns;
26
27
	/**
28
	 * @see SMWResultPrinter::handleParameters
29
	 *
30
	 * @since 1.6.2
31
	 *
32
	 * @param array $params
33
	 * @param $outputmode
34
	 */
35 3
	protected function handleParameters( array $params, $outputmode ) {
36 3
		parent::handleParameters( $params, $outputmode );
37
38 3
		$this->mUserParam = trim( $params['userparam'] );
39 3
		$this->mDelim = trim( $params['delim'] );
40 3
		$this->mNumColumns = $params['columns'];
41 3
		$this->mTemplate = $params['template'];
42 3
	}
43
44 1
	public function getName() {
45 1
		return wfMessage( 'smw_printername_' . $this->mFormat )->text();
46
	}
47
48 3
	protected function getResultText( SMWQueryResult $res, $outputMode ) {
49 3
		$contentsByIndex = array();
50
51
		// Print all result rows:
52 3
		$rowindex = 0;
53 3
		$row = $res->getNext();
54
55 3
		$mwCollaboratorFactory = ApplicationFactory::getInstance()->newMwCollaboratorFactory();
56
57 3
		$htmlColumnListRenderer = $mwCollaboratorFactory->newHtmlColumnListRenderer();
58 3
		$templateRenderer = $mwCollaboratorFactory->newWikitextTemplateRenderer();
59
60 3
		while ( $row !== false ) {
61 3
			$nextrow = $res->getNext(); // look ahead
62
63 3
			if ( !isset( $row[0] ) ) {
64
				$row = $nextrow;
65
				continue;
66
			}
67
68 3
			$content = $row[0]->getContent();
69
70 3
			if ( !isset( $content[0] ) || !( $content[0] instanceof SMWDataItem ) ) {
71 1
				$row = $nextrow;
72 1
				continue;
73
			}
74
75 3
			$columnIndex = $this->getFirstLetterForCategory( $res, $content[0] );
76
77 3
			if ( !isset( $contentsByIndex[$columnIndex] ) ) {
78 3
				$contentsByIndex[$columnIndex] = array();
79 3
				$lastColumnIndex = $columnIndex;
80
			}
81
82 3
			if ( $this->mTemplate !== '' ) { // build template code
83
84 2
				$first_col = true;
85 2
				$this->hasTemplates = true;
86
87 2
				if ( $this->mUserParam ) {
88
					$templateRenderer->addField( 'userparam', $this->mUserParam );
89
				}
90
91 2
				$this->addRowFieldsToTemplate(
92
					$res,
93
					$row,
94
					$first_col,
95
					$templateRenderer
96
				);
97
98 2
				$templateRenderer->addField( '#', $rowindex );
99 2
				$templateRenderer->packFieldsForTemplate( $this->mTemplate );
100
101
				// str_replace('|', '&#x007C;', // encode '|' for use in templates (templates fail otherwise) --
0 ignored issues
show
Unused Code Comprehensibility introduced by
56% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
102
				// this is not the place for doing this, since even DV-Wikitexts contain proper "|"!
103 2
				$contentsByIndex[$columnIndex][] = $templateRenderer->render();
104
			} else {  // build simple list
105 3
				$first_col = true;
106 3
				$found_values = false; // has anything but the first column been printed?
107 3
				$result = '';
108
109 3
				foreach ( $row as $field ) {
110 3
					$first_value = true;
111 3
					$fieldValues = array();
112
113 3
					while ( ( $text = $field->getNextText( SMW_OUTPUT_WIKI, $this->getLinker( $first_col ) ) ) !== false ) {
114
115 3
						if ( !$first_col && !$found_values ) { // first values after first column
116 3
							$result .= '(';
117 3
							$found_values = true;
118
						}
119
120 3
						if ( $first_value ) { // first value in any column, print header
121 3
							$first_value = false;
122
123 3
							if ( $this->mShowHeaders && ( $field->getPrintRequest()->getLabel() !== '' ) ) {
124 2
								$result .= $field->getPrintRequest()->getText( SMW_OUTPUT_WIKI, ( $this->mShowHeaders == SMW_HEADERS_PLAIN ? null : $this->mLinker ) ) . ' ';
125
							}
126
						}
127
128 3
						$fieldValues[] = $text;
129
					}
130
131 3
					$first_col = false;
132
133
					// Always sort the column value list in the same order
134 3
					natsort( $fieldValues );
135 3
					$result .= implode( ( $this->mDelim ? $this->mDelim : ',' ) . ' ', $fieldValues ) . ' ';
136
				}
137
138 3
				if ( $found_values ) {
139 3
					$result = trim( $result ) . ')';
140
				}
141
142 3
				$contentsByIndex[$columnIndex][] = $result;
143
			}
144
145 3
			$row = $nextrow;
146 3
			$rowindex++;
147
		}
148
149 3
		if ( $contentsByIndex === array() ) {
150
151 1
			$res->addErrors( array(
152 1
				$this->msg( 'smw-qp-empty-data' )->inContentLanguage()->text()
153
			) );
154
155 1
			return '';
156
		}
157
158
		// Make label for finding further results
159 3
		if ( $this->linkFurtherResults( $res ) ) {
160 1
			$contentsByIndex[$lastColumnIndex][] = $this->getFurtherResultsLink( $res, $outputMode )->getText( SMW_OUTPUT_WIKI, $this->mLinker );
0 ignored issues
show
Bug introduced by
The variable $lastColumnIndex 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...
161
		}
162
163 3
		$htmlColumnListRenderer->setNumberOfColumns( $this->mNumColumns );
164 3
		$htmlColumnListRenderer->addContentsByIndex( $contentsByIndex );
165
166
		// Per convention, an explicit 0 setting forces the columns to behave responsive
167 3
		if ( $this->params['columns'] == 0 ) {
168
			$htmlColumnListRenderer->setColumnClass( 'smw-column-responsive' );
169
			$htmlColumnListRenderer->setNumberOfColumns( 1 );
170
		}
171
172 3
		return $htmlColumnListRenderer->getHtml();
173
	}
174
175 3
	public function getParameters() {
176 3
		return array_merge( parent::getParameters(), array(
0 ignored issues
show
Deprecated Code introduced by
The method SMW\ResultPrinter::getParameters() has been deprecated with message: since 1.8, use getParamDefinitions instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
177
			array(
178
				'name' => 'columns',
179
				'type' => 'integer',
180
				'message' => 'smw-paramdesc-columns',
181
				'default' => 3,
182 3
			),
183
			array(
184
				'name' => 'delim',
185
				'message' => 'smw-paramdesc-category-delim',
186
				'default' => '',
187
			),
188
			array(
189
				'name' => 'template',
190
				'message' => 'smw-paramdesc-category-template',
191
				'default' => '',
192
			),
193
			array(
194
				'name' => 'userparam',
195
				'message' => 'smw-paramdesc-category-userparam',
196
				'default' => '',
197
			),
198
199
			array(
200
				'name' => 'named args',
201
				'type' => 'boolean',
202
				'message' => 'smw-paramdesc-named_args',
203
				'default' => false,
204
			),
205
206
			array(
207
				'name' => 'import-annotation',
208
				'type' => 'boolean',
209
				'message' => 'smw-paramdesc-import-annotation',
210
				'default' => false,
211
			)
212
		) );
213
	}
214
215 3
	private function getFirstLetterForCategory( SMWQueryResult $res, SMWDataItem $dataItem ) {
216
217 3
		$sortKey = $dataItem->getSortKey();
218
219 3
		if ( $dataItem->getDIType() == SMWDataItem::TYPE_WIKIPAGE ) {
220 3
			$sortKey = $res->getStore()->getWikiPageSortKey( $dataItem );
0 ignored issues
show
Compatibility introduced by
$dataItem of type object<SMWDataItem> is not a sub-type of object<SMW\DIWikiPage>. It seems like you assume a child class of the class SMWDataItem to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
221
222
		}
223
224 3
		return ByLanguageCollationMapper::getInstance()->findFirstLetterForCategory( $sortKey );
225
	}
226
227 2
	private function addRowFieldsToTemplate( $res, $row, &$first_col, $templateRenderer ) {
228
229
		// explicitly number parameters for more robust parsing (values may contain "=")
230 2
		$i = 0;
231
232 2
		foreach ( $row as $field ) {
233 2
			$i++;
234
235 2
			$fieldName = '';
236
237 2
			if ( $this->params['named args'] ) {
238 1
				$fieldName = $field->getPrintRequest()->getLabel();
239
			}
240
241 2
			if ( $fieldName === '' || $fieldName === '?' ) {
242 2
				$fieldName = $fieldName . $i;
243
			}
244
245 2
			$fieldValues = array();
246
247 2
			while ( ( $text = $field->getNextText( SMW_OUTPUT_WIKI, $this->getLinker( $first_col ) ) ) !== false ) {
248 2
				$fieldValues[] = $text;
249
			}
250
251 2
			natsort( $fieldValues );
252
253 2
			$templateRenderer->addField( $fieldName, implode( $this->mDelim . ' ', $fieldValues ) );
254 2
			$first_col = false;
255
		}
256 2
	}
257
258
}
259