CompositeQuery.php
4.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
<?php
namespace WPML\TM\Jobs\Query;
use \InvalidArgumentException;
use \WPML_TM_Jobs_Search_Params;
use \RuntimeException;
class CompositeQuery implements Query {
const METHOD_UNION = 'union';
const METHOD_COUNT = 'count';
/**
* Job queries
*
* @var Query[]
*/
private $queries;
/**
* Limit query helper
*
* @var LimitQueryHelper
*/
private $limit_query_helper;
/**
* Order query helper
*
* @var OrderQueryHelper
*/
private $order_query_helper;
/**
* @param Query[] $queries Job queries.
* @param LimitQueryHelper $limit_helper Limit helper.
* @param OrderQueryHelper $order_helper Order helper.
*
* @throws InvalidArgumentException In case of error.
*/
public function __construct(
array $queries,
LimitQueryHelper $limit_helper,
OrderQueryHelper $order_helper
) {
$queries = array_filter( $queries, array( $this, 'is_query_valid' ) );
if ( empty( $queries ) ) {
throw new InvalidArgumentException( 'Collection of sub-queries is empty or contains only invalid elements' );
}
$this->queries = $queries;
$this->limit_query_helper = $limit_helper;
$this->order_query_helper = $order_helper;
}
/**
* Get data query
*
* @param WPML_TM_Jobs_Search_Params $params Job search params.
*
* @throws InvalidArgumentException In case of error.
* @return string
*/
public function get_data_query( WPML_TM_Jobs_Search_Params $params ) {
if ( ! $params->get_job_types() ) {
// We are merging subqueries here, that's why LIMIT must be applied to final query.
$params_without_pagination_and_sorting = clone $params;
$params_without_pagination_and_sorting->set_limit( 0 )->set_offset( 0 );
$params_without_pagination_and_sorting->set_sorting( array() );
$query = $this->get_sql( $params_without_pagination_and_sorting, self::METHOD_UNION );
$order = $this->order_query_helper->get_order( $params );
if ( $order ) {
$query .= ' ' . $order;
}
$limit = $this->limit_query_helper->get_limit( $params );
if ( $limit ) {
$query .= ' ' . $limit;
}
return $query;
} else {
return $this->get_sql( $params, self::METHOD_UNION );
}
}
/**
* Get count query
*
* @param WPML_TM_Jobs_Search_Params $params Job search params.
*
* @return int|string
*/
public function get_count_query( WPML_TM_Jobs_Search_Params $params ) {
$params_without_pagination_and_sorting = clone $params;
$params_without_pagination_and_sorting->set_limit( 0 )->set_offset( 0 );
$params_without_pagination_and_sorting->set_sorting( array() );
return $this->get_sql( $params_without_pagination_and_sorting, self::METHOD_COUNT );
}
/**
* Get SQL request string
*
* @param WPML_TM_Jobs_Search_Params $params Job search params.
* @param string $method Query method.
*
* @throws InvalidArgumentException In case of error.
* @throws RuntimeException In case of error.
* @return string
*/
private function get_sql( WPML_TM_Jobs_Search_Params $params, $method ) {
switch ( $method ) {
case self::METHOD_UNION:
$query_method = 'get_data_query';
break;
case self::METHOD_COUNT:
$query_method = 'get_count_query';
break;
default:
throw new InvalidArgumentException( 'Invalid method argument: ' . $method );
}
$parts = array();
foreach ( $this->queries as $query ) {
$query_string = $query->$query_method( $params );
if ( $query_string ) {
$parts[] = $query_string;
}
}
if ( ! $parts ) {
throw new RuntimeException( 'None of subqueries matches to specified search parameters' );
}
if ( 1 === count( $parts ) ) {
return current( $parts );
}
switch ( $method ) {
case self::METHOD_UNION:
return $this->get_union( $parts );
case self::METHOD_COUNT:
return $this->get_count( $parts );
}
return null;
}
/**
* Get union
*
* @param array $parts Query parts.
*
* @return string
*/
private function get_union( array $parts ) {
return '( ' . implode( ' ) UNION ( ', $parts ) . ' )';
}
/**
* Get count
*
* @param array $parts Query parts.
*
* @return string
*/
private function get_count( array $parts ) {
return 'SELECT ( ' . implode( ' ) + ( ', $parts ) . ' )';
}
/**
* Is query valid
*
* @param mixed $query SQL query.
*
* @return bool
*/
private function is_query_valid( $query ) {
return $query instanceof Query;
}
}