1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Created by PhpStorm. |
4
|
|
|
* User: nazarenko |
5
|
|
|
* Date: 29.03.2016 |
6
|
|
|
* Time: 10:52 |
7
|
|
|
*/ |
8
|
|
|
namespace samsoncms\api\query; |
9
|
|
|
|
10
|
|
|
use samson\activerecord\dbQuery; |
11
|
|
|
use samsoncms\api\exception\WrongQueryConditionArgument; |
12
|
|
|
use samsonframework\orm\ArgumentInterface; |
13
|
|
|
use samsonframework\orm\Condition; |
14
|
|
|
use samsonframework\orm\ConditionInterface; |
15
|
|
|
use samsonframework\orm\QueryInterface; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* Generic real database entity query class. |
19
|
|
|
* |
20
|
|
|
* @package samsoncms\api\query |
21
|
|
|
*/ |
22
|
|
|
class Record |
23
|
|
|
{ |
24
|
|
|
/** @var string Table class name */ |
25
|
|
|
protected static $identifier; |
26
|
|
|
|
27
|
|
|
/** @var array Collection of all supported entity fields ids => names */ |
28
|
|
|
protected static $fieldIDs = array(); |
29
|
|
|
|
30
|
|
|
/** @var array Collection of all supported entity fields names => ids */ |
31
|
|
|
protected static $fieldNames = array(); |
32
|
|
|
|
33
|
|
|
/** @var string Table primary field name */ |
34
|
|
|
protected static $primaryFieldName; |
35
|
|
|
|
36
|
|
|
/** @var QueryInterface Database query instance */ |
37
|
|
|
protected $query; |
38
|
|
|
|
39
|
|
|
/** @var array Collection of entity fields to retrieved from database */ |
40
|
|
|
protected $selectedFields; |
41
|
|
|
|
42
|
|
|
/** @var ConditionInterface Query conditions */ |
43
|
|
|
protected $conditions; |
44
|
|
|
|
45
|
|
|
/** @var array Collection of ordering parameters */ |
46
|
|
|
protected $orderBy = array(); |
47
|
|
|
|
48
|
|
|
/** @var array Collection of limit parameters */ |
49
|
|
|
protected $limit = array(); |
50
|
|
|
|
51
|
|
|
/** @var array Collection of entity identifiers */ |
52
|
|
|
protected $entityIDs = array(); |
53
|
|
|
|
54
|
|
|
/** |
55
|
|
|
* Generic constructor. |
56
|
|
|
* |
57
|
|
|
* @param QueryInterface $query Database query instance |
58
|
|
|
*/ |
59
|
|
|
public function __construct(QueryInterface $query = null) |
60
|
|
|
{ |
61
|
|
|
$this->query = null === $query ? new dbQuery() : $query; |
62
|
|
|
$this->conditions = new Condition(); |
63
|
|
|
} |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* Select specified entity fields. |
67
|
|
|
* If this method is called then only selected entity fields |
68
|
|
|
* would be filled in entity instances. |
69
|
|
|
* |
70
|
|
|
* @param mixed $fieldNames Entity field name or collection of names |
71
|
|
|
* |
72
|
|
|
* @return $this Chaining |
73
|
|
|
*/ |
74
|
|
View Code Duplication |
public function select($fieldNames) |
|
|
|
|
75
|
|
|
{ |
76
|
|
|
// TODO: Query has no implementation for selecting needed fields |
77
|
|
|
|
78
|
|
|
// Convert argument to array and iterate |
79
|
|
|
foreach ((!is_array($fieldNames) ? array($fieldNames) : $fieldNames) as $fieldName) { |
80
|
|
|
// Try to find entity additional field |
81
|
|
|
$pointer = &static::$fieldNames[$fieldName]; |
82
|
|
|
if (null !== $pointer) { |
83
|
|
|
// Store selected additional field buy FieldID and Field name |
84
|
|
|
$this->selectedFields[$pointer] = $fieldName; |
85
|
|
|
} |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
return $this; |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
/** |
92
|
|
|
* Set field for sorting. |
93
|
|
|
* |
94
|
|
|
* @param string $fieldName Additional field name |
95
|
|
|
* @param string $order Sorting order |
96
|
|
|
* |
97
|
|
|
* @return $this Chaining |
98
|
|
|
*/ |
99
|
|
View Code Duplication |
public function orderBy($fieldName, $order = 'ASC') |
|
|
|
|
100
|
|
|
{ |
101
|
|
|
if (in_array($fieldName, static::$fieldIDs)) { |
102
|
|
|
$this->orderBy = array($fieldName, $order); |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
return $this; |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
/** |
109
|
|
|
* Set query results limitation. |
110
|
|
|
* |
111
|
|
|
* @param int $count Amount of entities to receive |
112
|
|
|
* @param int $offset Entities starting number |
113
|
|
|
* |
114
|
|
|
* @return $this Chaining |
115
|
|
|
*/ |
116
|
|
|
public function limit($count, $offset = 0) |
117
|
|
|
{ |
118
|
|
|
$this->limit = array($offset, $count); |
119
|
|
|
|
120
|
|
|
return $this; |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
/** |
124
|
|
|
* Perform internal query preparation. |
125
|
|
|
*/ |
126
|
|
|
protected function prepareQuery() |
127
|
|
|
{ |
128
|
|
|
$this->query->entity(static::$identifier); |
129
|
|
|
|
130
|
|
|
// Set entity primary keys if predefined |
131
|
|
|
if (count($this->entityIDs)) { |
132
|
|
|
$this->primary($this->entityIDs); |
|
|
|
|
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
// Add query sorting |
136
|
|
|
if (count($this->orderBy) === 2) { |
137
|
|
|
$this->query->orderBy($this->orderBy[0], $this->orderBy[1]); |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
// Add query limitation |
141
|
|
|
if (count($this->limit) === 2) { |
142
|
|
|
$this->query->limit($this->limit[0], $this->limit[1]); |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
// TODO: Add grouping |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
/** |
149
|
|
|
* Perform SamsonCMS query and get entities collection. |
150
|
|
|
* |
151
|
|
|
* @return \samsoncms\api\Entity[] Collection of found entities |
152
|
|
|
*/ |
153
|
|
|
public function find() |
154
|
|
|
{ |
155
|
|
|
$this->prepareQuery(); |
156
|
|
|
|
157
|
|
|
// Proxy to regular database query |
158
|
|
|
$return = $this->query |
159
|
|
|
->whereCondition($this->conditions) |
160
|
|
|
->exec(); |
161
|
|
|
|
162
|
|
|
// Reorder if entity identifiers collection was defined |
163
|
|
|
return $this->sortArrayByArray($return, $this->entityIDs); |
|
|
|
|
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
/** |
167
|
|
|
* Add primary field query condition. |
168
|
|
|
* |
169
|
|
|
* @param string $value Field value |
170
|
|
|
* @param string $fieldRelation |
171
|
|
|
* |
172
|
|
|
* @return $this Chaining |
173
|
|
|
* @see Material::where() |
174
|
|
|
*/ |
175
|
|
|
public function primary($value, $fieldRelation = ArgumentInterface::EQUAL) |
176
|
|
|
{ |
177
|
|
|
return $this->where(static::$primaryFieldName, $value, $fieldRelation); |
178
|
|
|
} |
179
|
|
|
|
180
|
|
|
/** |
181
|
|
|
* Add condition to current query. |
182
|
|
|
* |
183
|
|
|
* @param string $fieldName Entity field name |
184
|
|
|
* @param mixed $fieldValue Value |
185
|
|
|
* @param string $fieldRelation |
186
|
|
|
* |
187
|
|
|
* @return $this Chaining |
188
|
|
|
* |
189
|
|
|
* @throws WrongQueryConditionArgument |
190
|
|
|
*/ |
191
|
|
|
public function where($fieldName, $fieldValue = null, $fieldRelation = ArgumentInterface::EQUAL) |
192
|
|
|
{ |
193
|
|
|
// Ignore objects |
194
|
|
|
if (!is_object($fieldValue)) { |
195
|
|
|
// Get real table field name |
196
|
|
|
if (array_key_exists($fieldName, static::$fieldNames)) { |
197
|
|
|
$fieldName = static::$fieldNames[$fieldName]; |
198
|
|
|
} |
199
|
|
|
$this->conditions->add($fieldName, $fieldValue, $fieldRelation); |
200
|
|
|
} else { |
201
|
|
|
throw new WrongQueryConditionArgument('Object is passed to condition'); |
202
|
|
|
} |
203
|
|
|
|
204
|
|
|
return $this; |
205
|
|
|
} |
206
|
|
|
|
207
|
|
|
/** |
208
|
|
|
* Reorder elements in one array according to keys of another. |
209
|
|
|
* |
210
|
|
|
* @param array $array Source array |
211
|
|
|
* @param array $orderArray Ideal array |
212
|
|
|
* @return array Ordered array |
213
|
|
|
*/ |
214
|
|
|
protected function sortArrayByArray(array $array, array $orderArray) |
215
|
|
|
{ |
216
|
|
|
$ordered = array(); |
217
|
|
|
foreach ($orderArray as $key) { |
218
|
|
|
if (array_key_exists($key, $array)) { |
219
|
|
|
$ordered[$key] = $array[$key]; |
220
|
|
|
unset($array[$key]); |
221
|
|
|
} |
222
|
|
|
} |
223
|
|
|
return array_merge($ordered, $array); |
224
|
|
|
} |
225
|
|
|
|
226
|
|
|
/** |
227
|
|
|
* Perform SamsonCMS query and get collection of entities fields. |
228
|
|
|
* |
229
|
|
|
* @param string $fieldName Entity field name |
230
|
|
|
* |
231
|
|
|
* @return array Collection of entity fields |
232
|
|
|
*/ |
233
|
|
|
public function fields($fieldName) |
234
|
|
|
{ |
235
|
|
|
$this->prepareQuery(); |
236
|
|
|
|
237
|
|
|
// Proxy to regular database query |
238
|
|
|
return $this->query |
239
|
|
|
->whereCondition($this->conditions) |
240
|
|
|
->fields($fieldName); |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
/** |
244
|
|
|
* Perform SamsonCMS query and get first matching entity. |
245
|
|
|
* |
246
|
|
|
* @return \samsoncms\api\Entity First matching entity |
247
|
|
|
*/ |
248
|
|
|
public function first() |
249
|
|
|
{ |
250
|
|
|
$this->prepareQuery(); |
251
|
|
|
|
252
|
|
|
// Proxy to regular database query |
253
|
|
|
$return = $this->query |
254
|
|
|
->limit(1) |
255
|
|
|
->whereCondition($this->conditions) |
256
|
|
|
->exec(); |
257
|
|
|
|
258
|
|
|
return array_shift($return); |
259
|
|
|
} |
260
|
|
|
|
261
|
|
|
/** |
262
|
|
|
* Perform SamsonCMS query and get amount resulting entities. |
263
|
|
|
* |
264
|
|
|
* @return int Amount of resulting entities |
265
|
|
|
*/ |
266
|
|
|
public function count() |
267
|
|
|
{ |
268
|
|
|
// Proxy to regular database query |
269
|
|
|
return $this->query |
270
|
|
|
->entity(static::$identifier) |
271
|
|
|
->whereCondition($this->conditions) |
272
|
|
|
->count(); |
273
|
|
|
} |
274
|
|
|
|
275
|
|
|
/** |
276
|
|
|
* Convert date value to database format. |
277
|
|
|
* TODO: Must implement at database layer |
278
|
|
|
* |
279
|
|
|
* @param string $date Date value for conversion |
280
|
|
|
* |
281
|
|
|
* @return string Converted date to correct format |
282
|
|
|
*/ |
283
|
|
|
protected function convertToDateTime($date) |
284
|
|
|
{ |
285
|
|
|
return date('Y-m-d H:i:s', strtotime($date)); |
286
|
|
|
} |
287
|
|
|
|
288
|
|
|
/** |
289
|
|
|
* Add sorting to entity identifiers. |
290
|
|
|
* |
291
|
|
|
* @param array $entityIDs |
292
|
|
|
* @param string $fieldName Additional field name for sorting |
293
|
|
|
* @param string $order Sorting order(ASC|DESC) |
294
|
|
|
* |
295
|
|
|
* @return array Collection of entity identifiers ordered by additional field value |
296
|
|
|
*/ |
297
|
|
View Code Duplication |
protected function applySorting(array $entityIDs, $fieldName, $order = 'ASC') |
|
|
|
|
298
|
|
|
{ |
299
|
|
|
if (array_key_exists($fieldName, static::$fieldIDs)) { |
300
|
|
|
// Order by parent fields |
301
|
|
|
return $this->query |
302
|
|
|
->entity(static::$identifier) |
303
|
|
|
->where(static::$primaryFieldName, $entityIDs) |
304
|
|
|
->orderBy($fieldName, $order) |
305
|
|
|
->fields(static::$primaryFieldName); |
306
|
|
|
} else { // Nothing is changed |
307
|
|
|
return $entityIDs; |
308
|
|
|
} |
309
|
|
|
} |
310
|
|
|
} |
311
|
|
|
|
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.