Completed
Push — master ( 3184dc...186529 )
by mw
36:28
created

addConjunctionFromExtraDescriptions()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 26
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 13
nc 2
nop 2
dl 0
loc 26
rs 8.8571
c 0
b 0
f 0
1
<?php
2
3
namespace SMW\SQLStore\QueryEngine;
4
5
use SMW\DataValueFactory;
6
use SMW\Query\DescriptionFactory;
7
use SMW\Query\Language\Description;
8
use SMW\DataValues\PropertyChainValue;
9
use RuntimeException;
10
11
/**
12
 * Modifies a given query object at $qid to account for all ordering conditions
13
 * in the Query $query. It is always required that $qid is the id of a query
14
 * that joins with the SMW ID_TABELE so that the field alias.smw_title is
15
 * available for default sorting.
16
 *
17
 * @license GNU GPL v2+
18
 * @since 2.5
19
 *
20
 * @author mwjames
21
 * @author Markus Krötzsch
22
 */
23
class OrderConditionsComplementor {
24
25
	/**
26
	 * @var QuerySegmentListBuilder
27
	 */
28
	private $querySegmentListBuilder;
29
30
	/**
31
	 * @var DescriptionFactory
32
	 */
33
	private $descriptionFactory;
34
35
	/**
36
	 * Array of sorting requests ("Property_name" => "ASC"/"DESC"). Used during query
37
	 * processing (where these property names are searched while compiling the query
38
	 * conditions).
39
	 *
40
	 * @var string[]
41
	 */
42
	private $sortKeys = array();
43
44
	/**
45
	 * @var boolean
46
	 */
47
	private $isSupported = true;
48
49
	/**
50
	 * @since 2.5
51
	 *
52
	 * @param QuerySegmentListBuilder $querySegmentListBuilder
53
	 */
54
	public function __construct( QuerySegmentListBuilder $querySegmentListBuilder ) {
55
		$this->querySegmentListBuilder = $querySegmentListBuilder;
56
		$this->descriptionFactory = new DescriptionFactory();
57
	}
58
59
	/**
60
	 * @since 2.5
61
	 *
62
	 * @param array $sortKeys
63
	 */
64
	public function setSortKeys( $sortKeys ) {
65
		$this->sortKeys = $sortKeys;
66
	}
67
68
	/**
69
	 * @since 2.5
70
	 *
71
	 * @return string[]
72
	 */
73
	public function getSortKeys() {
74
		return $this->sortKeys;
75
	}
76
77
	/**
78
	 * @since 2.5
79
	 *
80
	 * @return array
81
	 */
82
	public function getErrors() {
83
		return $this->querySegmentListBuilder->getErrors();
84
	}
85
86
	/**
87
	 * @since 2.5
88
	 *
89
	 * @param boolean $isSupported
90
	 */
91
	public function isSupported( $isSupported ) {
92
		$this->isSupported = $isSupported;;
93
	}
94
95
	/**
96
	 * @since 2.5
97
	 *
98
	 * @param integer $qid
99
	 *
100
	 * @return QuerySegment[]
101
	 */
102
	public function applyOrderConditions( $qid ) {
103
104
		if ( !$this->isSupported ) {
105
			return $this->querySegmentListBuilder->getQuerySegmentList();
106
		}
107
108
		$querySegment = $this->querySegmentListBuilder->findQuerySegment(
109
			$qid
110
		);
111
112
		$extraDescriptions = $this->collectExtraDescriptionsFromSortKeys(
113
			$querySegment
114
		);
115
116
		if ( $extraDescriptions !== array() ) {
117
			$this->addConjunctionFromExtraDescriptions( $querySegment, $extraDescriptions );
118
		}
119
120
		return $this->querySegmentListBuilder->getQuerySegmentList();
121
	}
122
123
	private function collectExtraDescriptionsFromSortKeys( $querySegment ) {
124
125
		$extraDescriptions = array();
126
127
		foreach ( $this->sortKeys as $label => $order ) {
128
129
			if ( !is_string( $label ) ) {
130
				throw new RuntimeException( "Expected a string value as sortkey" );
131
			}
132
133
			if ( ( $description = $this->findExtraDescriptionBy( $querySegment, $label, $order ) ) instanceof Description ) {
134
				$extraDescriptions[] = $description;
135
			}
136
		}
137
138
		return $extraDescriptions;
139
	}
140
141
	private function findExtraDescriptionBy( $querySegment, $label, $order ) {
0 ignored issues
show
Unused Code introduced by
The parameter $order 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...
142
143
		$description = null;
144
145
		// Is assigned, leave ...
146
		if ( array_key_exists( $label, $querySegment->sortfields ) ) {
147
			return $description;
148
		}
149
150
		// Find missing property to sort by.
151
		if ( $label === '' ) { // Sort by first result column (page titles).
152
			$querySegment->sortfields[$label] = "$querySegment->alias.smw_sortkey";
153
		} elseif ( $label === '#' ) { // Sort by first result column (page titles).
154
			// PHP7 showed a rather erratic behaviour where in cases
155
			// the sortkey contains the same string for comparison, the
156
			// result returned from the DB was mixed in order therefore
157
			// using # as indicator to search for additional fields if
158
			// no specific property is given (see test cases in #1534)
159
			$querySegment->sortfields[$label] = "$querySegment->alias.smw_sortkey,$querySegment->alias.smw_title,$querySegment->alias.smw_subobject";
160
		} else { // Try to extend query.
161
			$sortprop = DataValueFactory::getInstance()->newPropertyValueByLabel( $label );
162
163
			if ( $sortprop->isValid() ) {
164
				$description = $this->descriptionFactory->newSomeProperty(
165
					$sortprop->getDataItem(),
0 ignored issues
show
Compatibility introduced by
$sortprop->getDataItem() of type object<SMWDataItem> is not a sub-type of object<SMW\DIProperty>. 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...
166
					$this->descriptionFactory->newThingDescription()
167
				);
168
			}
169
		}
170
171
		return $description;
172
	}
173
174
	private function addConjunctionFromExtraDescriptions( $querySegment, array $extraDescriptions ) {
175
176
		$this->querySegmentListBuilder->setSortKeys(
177
			$this->sortKeys
178
		);
179
180
		$this->querySegmentListBuilder->getQuerySegmentFrom(
181
			$this->descriptionFactory->newConjunction( $extraDescriptions )
182
		);
183
184
 		// This is always an QuerySegment::Q_CONJUNCTION ...
185
		$newQuerySegment = $this->querySegmentListBuilder->findQuerySegment(
186
			$this->querySegmentListBuilder->getLastQuerySegmentId()
187
		);
188
189
		 // ... so just re-wire its dependencies
190
		foreach ( $newQuerySegment->components as $cid => $field ) {
191
			$querySegment->components[$cid] = $querySegment->joinfield;
192
			$querySegment->sortfields = array_merge(
193
				$querySegment->sortfields,
194
				$this->querySegmentListBuilder->findQuerySegment( $cid )->sortfields
195
			);
196
		}
197
198
		$this->querySegmentListBuilder->addQuerySegment( $querySegment );
199
	}
200
201
}
202