Completed
Push — master ( dc1683...3e9aec )
by mw
07:38 queued 05:33
created

CompoundQueryProcessor::mergeSMWQueryResults()   B

Complexity

Conditions 5
Paths 7

Size

Total Lines 19
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 19
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 11
nc 7
nop 2
1
<?php
2
3
namespace SCQ;
4
5
use SMWQueryProcessor as QueryProcessor;
6
use SMWQuery as Query;
7
use Parser;
8
9
/**
10
 * Class that holds static functions for handling compound queries.
11
 * This class inherits from Semantic MediaWiki's QueryProcessor.
12
 *
13
 * @license GNU GPL v2+
14
 * @since 1.0
15
 *
16
 * @author Yaron Koren
17
 * @author Peter Grassberger < [email protected] >
18
 */
19
class CompoundQueryProcessor extends QueryProcessor {
20
21
	/**
22
	 * Comparison helper function, used in sorting results.
23
	 */
24
	public static function compareQueryResults( $a, $b ) {
25
26
		if ( $a->getSerialization() == $b->getSerialization() ) {
27
			return 0;
28
		}
29
30
		return ( $a->getSerialization() < $b->getSerialization() ) ? -1 : 1;
31
	}
32
33
	/**
34
	 * Handler for the #compound_query parser function.
35
	 *
36
	 * @param Parser $parser
37
	 *
38
	 * @return string
39
	 */
40
	public static function doCompoundQuery( Parser &$parser ) {
0 ignored issues
show
Unused Code introduced by
The parameter $parser is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
41
		global $smwgQEnabled, $smwgIQRunningNumber;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
42
43
		if ( !$smwgQEnabled ) {
44
			return smwfEncodeMessages( array( wfMessage( 'smw_iq_disabled' )->inContentLanguage()->text() ) );
45
		}
46
47
		$smwgIQRunningNumber++;
48
49
		$params = func_get_args();
50
		array_shift( $params ); // We already know the $parser.
51
52
		list( $queryParams, $otherParams ) = self::separateParams( $params );
53
		list( $queryResult, $otherParams ) = self::queryAndMergeResults( $queryParams, $otherParams );
54
55
		return self::getResultFromQueryResult(
56
			$queryResult,
57
			$otherParams,
58
			SMW_OUTPUT_WIKI
59
		);
60
	}
61
62
	/**
63
	 * Separates $queryParams from $otherParams.
64
	 *
65
	 * @param $params
66
	 * @return array
67
	 */
68
	public static function separateParams( $params ) {
69
		$queryParams = array();
70
		$otherParams = array();
71
72
		foreach ( $params as $param ) {
73
			// Very primitive heuristic - if the parameter
74
			// includes a square bracket, then it's a
75
			// sub-query; otherwise it's a regular parameter.
76
			if ( strpos( $param, '[' ) !== false ) {
77
				$queryParams[] = $param;
78
			} else {
79
				$parts = explode( '=', $param, 2 );
80
81
				if ( count( $parts ) >= 2 ) {
82
					$otherParams[strtolower( trim( $parts[0] ) )] = $parts[1]; // don't trim here, some params care for " "
83
				}
84
			}
85
		}
86
		return array( $queryParams, $otherParams );
87
	}
88
89
	/**
90
	 * Query and merge results of subqueries.
91
	 *
92
	 * @param $queryParams
93
	 * @param $otherParams
94
	 * @return array
95
	 */
96
	public static function queryAndMergeResults( $queryParams, $otherParams ) {
97
		$results = array();
98
		$printRequests = array();
99
100
		foreach ( $queryParams as $param ) {
101
			$subQueryParams = self::getSubParams( $param );
102
103
			if ( array_key_exists( 'format', $otherParams ) && !array_key_exists( 'format', $subQueryParams ) ) {
104
				$subQueryParams['format'] = $otherParams['format'];
105
			}
106
107
			$nextResult = self::getQueryResultFromFunctionParams($subQueryParams);
108
109
			$results = self::mergeSMWQueryResults( $results, $nextResult->getResults() );
110
			$printRequests = self::mergeSMWPrintRequests( $printRequests, $nextResult->getPrintRequests() );
111
		}
112
113
		// Sort results so that they'll show up by page name
114
		if( !isset($otherParams['unsorted']) || !strcmp( $otherParams['unsorted'], 'on' ) ) {
115
			uasort( $results, array( '\SCQ\CompoundQueryProcessor', 'compareQueryResults' ) );
116
		}
117
118
		$queryResult = new CompoundQueryResult( $printRequests, new Query(), $results, smwfGetStore() );
119
120 View Code Duplication
		if ( version_compare( SMW_VERSION, '1.6.1', '>' ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
121
			self::addThisPrintout( $printRequests, $otherParams );
122
			$otherParams = self::getProcessedParams( $otherParams, $printRequests );
123
		}
124
125
		return array( $queryResult, $otherParams );
126
	}
127
128
	/**
129
	 * An alternative to explode() - that function won't work here,
130
	 * because we don't want to split the string on all semicolons, just
131
	 * the ones that aren't contained within square brackets
132
	 *
133
	 * @param string $param
134
	 *
135
	 * @return array
136
	 */
137
	protected static function getSubParams( $param ) {
138
		$sub_params = array();
139
		$sub_param = '';
140
		$uncompleted_square_brackets = 0;
141
142
		for ( $i = 0; $i < strlen( $param ); $i++ ) {
143
			$c = $param[$i];
144
145
			if ( ( $c == ';' ) && ( $uncompleted_square_brackets <= 0 ) ) {
146
				$sub_params[] = trim( $sub_param );
147
				$sub_param = '';
148
			} else {
149
				$sub_param .= $c;
150
151
				if ( $c == '[' ) {
152
					$uncompleted_square_brackets++;
153
				}
154
155
				elseif ( $c == ']' ) {
156
					$uncompleted_square_brackets--;
157
				}
158
			}
159
		}
160
161
		$sub_params[] = trim( $sub_param );
162
163
		return $sub_params;
164
	}
165
166
	/**
167
	 * @param $rawparams
168
	 * @param $context
169
	 * @param $showmode
170
	 *
171
	 * @return SMWQueryResult
172
	 */
173
	protected static function getQueryResultFromFunctionParams( $rawparams, $context = QueryProcessor::INLINE_QUERY, $showmode = false ) {
174
		$printouts = array();
175
		self::processFunctionParams( $rawparams, $querystring, $params, $printouts, $showmode );
0 ignored issues
show
Deprecated Code introduced by
The method SMWQueryProcessor::processFunctionParams() has been deprecated with message: Will vanish after SMW 1.8 is released.
Use getComponentsFromFunctionParams which has a cleaner interface.

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...
176
		return self::getQueryResultFromQueryString( $querystring, $params, $printouts, $context );
177
	}
178
179
	/**
180
	 * Combine two arrays of SMWWikiPageValue objects into one
181
	 *
182
	 * @param array $result1
183
	 * @param array $result2
184
	 *
185
	 * @return array
186
	 */
187
	protected static function mergeSMWQueryResults( $result1, $result2 ) {
188
		if ( $result1 == null ) {
189
			return $result2;
190
		}
191
192
		$existing_page_names = array();
193
		foreach ( $result1 as $r1 ) {
194
			$existing_page_names[] = $r1->getSerialization();
195
		}
196
197
		foreach ( $result2 as $r2 ) {
198
			$page_name = $r2->getSerialization();
199
			if ( ! in_array( $page_name, $existing_page_names ) ) {
200
				$result1[] = $r2;
201
			}
202
		}
203
204
		return $result1;
205
	}
206
207
	protected static function mergeSMWPrintRequests( $printRequests1, $printRequests2 ) {
208
		$existingPrintoutLabels = array();
209
		foreach ( $printRequests1 as $p1 ) {
210
			$existingPrintoutLabels[] = $p1->getLabel();
211
		}
212
213
		foreach ( $printRequests2 as $p2 ) {
214
			$label = $p2->getLabel();
215
			if ( ! in_array( $label, $existingPrintoutLabels ) ) {
216
				$printRequests1[] = $p2;
217
			}
218
		}
219
		return $printRequests1;
220
	}
221
222
	/**
223
	 * @param $querystring
224
	 * @param array $params
225
	 * @param $extraPrintouts
226
	 * @param $outputMode
227
	 * @param $context
228
	 *
229
	 * @return SMWQueryResult
230
	 */
231
	protected static function getQueryResultFromQueryString( $querystring, array $params, $extraPrintouts, $context = QueryProcessor::INLINE_QUERY ) {
232
233 View Code Duplication
		if ( version_compare( SMW_VERSION, '1.6.1', '>' ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
234
			QueryProcessor::addThisPrintout( $extraPrintouts, $params );
235
			$params = self::getProcessedParams( $params, $extraPrintouts, false );
236
		}
237
238
		$query = self::createQuery( $querystring, $params, $context, null, $extraPrintouts );
239
		$queryResult = smwfGetStore()->getQueryResult( $query );
240
241
		$parameters = array();
242
243
		if ( version_compare( SMW_VERSION, '1.7.2', '>' ) ) {
244
			foreach ( $params as $param ) {
245
				$parameters[$param->getName()] = $param->getValue();
246
			}
247
		}
248
		else {
249
			$parameters = $params;
250
		}
251
252
		foreach ( $queryResult->getResults() as $wikiPage ) {
253
			$wikiPage->display_options = $parameters;
254
		}
255
256
		return $queryResult;
257
	}
258
259
	/**
260
	 * Matches getResultFromQueryResult() from SMWQueryProcessor,
261
	 * except that formats of type 'debug' and 'count' aren't handled.
262
	 *
263
	 * @param CompoundQueryResult $res
264
	 * @param array $params These need to be the result of a list fed to getProcessedParams as of SMW 1.6.2
265
	 * @param $outputmode
266
	 * @param $context
267
	 * @param string $format
268
	 *
269
	 * @return string
270
	 */
271
	protected static function getResultFromQueryResult( CompoundQueryResult $res, array $params, $outputmode, $context = QueryProcessor::INLINE_QUERY, $format = '' ) {
0 ignored issues
show
Unused Code introduced by
The parameter $format is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
272
273
		if ( version_compare( SMW_VERSION, '1.6.1', '>' ) ) {
274
			$format = $params['format'];
275
276
			if ( version_compare( SMW_VERSION, '1.7.2', '>' ) ) {
277
				$format = $format->getValue();
278
			}
279
		} else {
280
			$format = self::getResultFormat( $params );
0 ignored issues
show
Bug introduced by
The method getResultFormat() does not seem to exist on object<SCQ\CompoundQueryProcessor>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
281
		}
282
283
		$printer = self::getResultPrinter( $format, $context );
284
		$result = $printer->getResult( $res, $params, $outputmode );
285
286
		return $result;
287
	}
288
289
}
290