Test Failed
Push — master ( 507036...762659 )
by Julien
21:33
created

Query::prepareFind()   A

Complexity

Conditions 6
Paths 6

Size

Total Lines 19
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 14
c 1
b 0
f 0
nc 6
nop 2
dl 0
loc 19
ccs 0
cts 13
cp 0
crap 42
rs 9.2222
1
<?php
2
3
/**
4
 * This file is part of the Zemit Framework.
5
 *
6
 * (c) Zemit Team <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE.txt
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Zemit\Mvc\Controller\Traits;
13
14
use Phalcon\Filter\Exception;
15
use Phalcon\Support\Collection;
16
use Phalcon\Mvc\Model\ResultsetInterface;
17
use Zemit\Mvc\Controller\Traits\Abstracts\AbstractModel;
18
use Zemit\Mvc\Controller\Traits\Abstracts\AbstractQuery;
19
use Zemit\Mvc\Controller\Traits\Query\Bind;
20
use Zemit\Mvc\Controller\Traits\Query\Cache;
21
use Zemit\Mvc\Controller\Traits\Query\Column;
22
use Zemit\Mvc\Controller\Traits\Query\Conditions;
23
use Zemit\Mvc\Controller\Traits\Query\Distinct;
24
use Zemit\Mvc\Controller\Traits\Query\Fields;
25
use Zemit\Mvc\Controller\Traits\Query\Group;
26
use Zemit\Mvc\Controller\Traits\Query\Having;
27
use Zemit\Mvc\Controller\Traits\Query\Joins;
28
use Zemit\Mvc\Controller\Traits\Query\Limit;
29
use Zemit\Mvc\Controller\Traits\Query\Offset;
30
use Zemit\Mvc\Controller\Traits\Query\Order;
31
use Zemit\Mvc\Controller\Traits\Query\Save;
32
use Zemit\Mvc\Controller\Traits\Query\With;
33
use Zemit\Mvc\Model\Interfaces\EagerLoadInterface;
34
use Zemit\Mvc\Model\Interfaces\RelationshipInterface;
35
36
/**
37
 * Class Query
38
 *
39
 * This class provides methods for building and executing database queries.
40
 * It is used as a trait in other classes that need query building capabilities.
41
 */
42
trait Query
43
{
44
    use AbstractQuery;
45
    
46
    use AbstractModel;
47
    
48
    use Bind;
49
    use Cache;
50
    use Column;
51
    use Conditions;
52
    use Distinct;
53
    use Fields;
54
    use Group;
55
    use Having;
56
    use Joins;
57
    use Limit;
58
    use Offset;
59
    use Order;
60
    use Save;
61
    use With;
62
    
63
    protected ?Collection $find;
64
    
65
    /**
66
     * Initializes the query builder with default values for various properties.
67
     * @throws Exception
68
     * @throws \Exception
69
     */
70
    public function initializeQuery()
71
    {
72
        $this->initializeCacheConfig();
73
        $this->initializeFields();
74
        $this->initializeBind();
75
        $this->initializeBindTypes();
76
        $this->initializeConditions();
77
        $this->initializeDistinct();
78
        $this->initializeGroup();
79
        $this->initializeHaving();
80
        $this->initializeJoins();
81
        $this->initializeLimit();
82
        $this->initializeOffset();
83
        $this->initializeOrder();
84
//        $this->initializeSave();
85
        $this->initializeWith();
86
        $this->initializeFind();
87
    }
88
    
89
    /**
90
     * Initializes the `find` property with a new Collection object.
91
     * The values of various properties are assigned to the corresponding keys of the Collection object.
92
     *
93
     * @return void
94
     */
95
    public function initializeFind(): void
96
    {
97
        $this->setFind(new Collection([
98
            'conditions' => $this->getConditions(),
99
            'bind' => $this->getBind(),
100
            'bindTypes' => $this->getBindTypes(),
101
            'limit' => $this->getLimit(),
102
            'offset' => $this->getOffset(),
103
            'order' => $this->getOrder(),
104
//            'columns' => $this->getColumns(),
105
            'distinct' => $this->getDistinct(),
106
            'joins' => $this->getJoins(),
107
            'group' => $this->getGroup(),
108
            'having' => $this->getHaving(),
109
            'cache' => $this->getCacheConfig(),
110
        ]));
111
    }
112
    
113
    /**
114
     * Sets the value of the `find` property.
115
     *
116
     * @param Collection|null $find The new value for the `find` property.
117
     * @return void
118
     */
119
    public function setFind(?Collection $find): void
120
    {
121
        $this->find = $find;
122
    }
123
    
124
    /**
125
     * Retrieves the value of the `find` property.
126
     *
127
     * @return Collection|null The value of the `find` property.
128
     */
129
    public function getFind(): ?Collection
130
    {
131
        return $this->find;
132
    }
133
    
134
    /**
135
     * Builds the `find` array for a query.
136
     *
137
     * @param Collection|null $find The collection to build the find array from. Defaults to null.
138
     * @param bool $ignoreKey Whether to ignore the keys in the collection. Defaults to false.
139
     * @return array The built find array.
140
     */
141
    public function prepareFind(?Collection $find = null, bool $ignoreKey = false): array
142
    {
143
        $build = [];
144
        $find ??= $this->getFind();
145
        $iterator = $find?->getIterator() ?? [];
146
        foreach ($iterator as $key => $value) {
147
            if ($value instanceof Collection) {
148
                $subIgnoreKey = $ignoreKey || in_array($key, ['conditions', 'joins', 'group']);
149
                $sub = $this->prepareFind($value, $subIgnoreKey);
150
                if ($ignoreKey) {
151
                    $build = array_merge($build, $sub);
152
                } else {
153
                    $build[$key] = $sub;
154
                }
155
            } else {
156
                $build[$key] = $value;
157
            }
158
        }
159
        return array_filter($ignoreKey? array_values($build) : $build);
160
    }
161
    
162
    /**
163
     * Find records in the database using the specified criteria.
164
     *
165
     * @param array|null $find Optional. An array of criteria to determine the records to find.
166
     *                         If not provided, the default criteria from `getFind()` method
167
     *                         will be used. Defaults to `null`.
168
     *
169
     * @return ResultsetInterface The result of the find operation.
170
     */
171
    public function find(?array $find = null)
172
    {
173
        $find ??= $this->prepareFind();
174
        return $this->loadModel()::find($find);
175
    }
176
    
177
    /**
178
     * Find records in the database using the specified criteria and include related records.
179
     *
180
     * @param array|null $with Optional. An array of related models to include
181
     *                         with the found records. Defaults to `null`.
182
     * @param array|null $find Optional. An array of criteria to determine the records to find.
183
     *                         If not provided, the default criteria from `getFind()` method
184
     *                         will be used. Defaults to `null`.
185
     *
186
     * @return array The result of the find operation with loaded relationships.
187
     */
188
    public function findWith(?array $with = null, ?array $find = null): array
189
    {
190
        $find ??= $this->prepareFind();
191
        $with ??= $this->getWith()?->toArray() ?? [];
192
        $model = $this->loadModel();
193
        assert($model instanceof EagerLoadInterface);
194
        return $model::findWith($with, $find);
195
    }
196
    
197
    /**
198
     * Find the first record in the database using the specified criteria.
199
     *
200
     * @param array|null $find Optional. An array of criteria to determine the record to find.
201
     *                         If not provided, the default criteria from `getFind()` method
202
     *                         will be used to find the first record. Defaults to `null`.
203
     *
204
     * // @todo \Phalcon\Mvc\ModelInterface|\Phalcon\Mvc\Model\Row|null
205
     * @return mixed The result of the find operation, which is the first record that matches the criteria.
206
     */
207
    public function findFirst(?array $find = null): mixed
208
    {
209
        $find ??= $this->prepareFind();
210
        return $this->loadModel()::findFirst($find);
211
    }
212
    
213
    /**
214
     * Find the first record in the database using the specified criteria and relations.
215
     *
216
     * @param array|null $with Optional. An array of relations to eager load for the record.
217
     *                         If not provided, the default relations from `getWith()` method
218
     *                         will be used. Defaults to `null`.
219
     * @param array|null $find Optional. An array of criteria to determine the records to find.
220
     *                         If not provided, the default criteria from `getFind()` method
221
     *                         will be used. Defaults to `null`.
222
     *
223
     * @return mixed The result of the find operation for the first record.
224
     */
225
    public function findFirstWith(?array $with = null, ?array $find = null): mixed
226
    {
227
        $find ??= $this->prepareFind();
228
        $with ??= $this->getWith()?->toArray() ?? [];
229
        $model = $this->loadModel();
230
        assert($model instanceof EagerLoadInterface);
231
        return $model::findFirstWith($with, $find);
232
    }
233
    
234
    /**
235
     * Calculates the average value based on a given set of criteria.
236
     *
237
     * @param array|null $find The criteria to filter the records by (optional).
238
     * @return float|ResultsetInterface The average value or a result set containing the average value.
239
     */
240
    public function average(?array $find = null): float|ResultsetInterface
241
    {
242
        $find ??= $this->prepareFind();
243
        return $this->loadModel()::average($this->getCalculationFind($find));
244
    }
245
    
246
    /**
247
     * Retrieves the total count of items based on the specified model name and find criteria.
248
     * Note: limit and offset are removed from the parameters in order to retrieve the total count
249
     *
250
     * @param array|null $find An array of find criteria to filter the results. If null, the default criteria will be applied.
251
     *
252
     * @return int|ResultsetInterface The total count of items that match the specified criteria.
253
     * @throws \Exception
254
     */
255
    public function count(?array $find = null): int|ResultsetInterface
256
    {
257
        $find ??= $this->prepareFind();
258
        return $this->loadModel()::count($this->getCalculationFind($find));
259
    }
260
    
261
    /**
262
     * Calculates the sum of values based on a given search criteria.
263
     *
264
     * @param array|null $find Optional: The criteria to find the maximum value from.
265
     *                         Default: null (will retrieve the `find` from $this->getFind())
266
     *
267
     * @return float|ResultsetInterface The calculated sum of values.
268
     */
269
    public function sum(?array $find = null): float|ResultsetInterface
270
    {
271
        $find ??= $this->prepareFind();
272
        return $this->loadModel()::sum($this->getCalculationFind($find));
273
    }
274
    
275
    /**
276
     * Retrieves the minimum value.
277
     *
278
     * @param array|null $find Optional: The criteria to find the maximum value from.
279
     *                         Default: null (will retrieve the `find` from $this->getFind())
280
     *
281
     * @return float|ResultsetInterface The maximum value from the dataset
282
     *                                  or a `ResultsetInterface` that represents the grouped maximum values.
283
     */
284
    public function maximum(?array $find = null): float|ResultsetInterface
285
    {
286
        $find ??= $this->prepareFind();
287
        return $this->loadModel()::maximum($this->getCalculationFind($find));
288
    }
289
    
290
    /**
291
     * Retrieves the minimum value.
292
     *
293
     * @param array|null $find Optional: The criteria to find the minimum value from.
294
     *                         Default: null (will retrieve the `find` from $this->getFind())
295
     *
296
     * @return float|ResultsetInterface The minimum value from the dataset
297
     *                                  or a `ResultsetInterface` that represents the grouped minimum values.
298
     */
299
    public function minimum(?array $find = null): float|ResultsetInterface
300
    {
301
        $find ??= $this->prepareFind();
302
        return $this->loadModel()::minimum($this->getCalculationFind($find));
303
    }
304
    
305
    /**
306
     * Retrieves the count criteria based on the specified find criteria.
307
     *
308
     * @param array|null $find An array of find criteria to filter the results. If null, the default criteria will be used.
309
     *
310
     * @return array An array of filtered find criteria without the 'limit' and 'offset' keys.
311
     */
312
    protected function getCalculationFind(?array $find = null): array
313
    {
314
        $find ??= $this->getFind()?->toArray() ?? [];
315
        
316
        if (isset($find['limit'])) {
317
            unset($find['limit']);
318
        }
319
        
320
        if (isset($find['offset'])) {
321
            unset($find['offset']);
322
        }
323
        
324
        return array_filter($find);
325
    }
326
    
327
    /**
328
     * Generates a unique bind key with the given prefix.
329
     *
330
     * @param string $prefix The prefix to be used in the bind key.
331
     *
332
     * @return string The generated bind key.
333
     */
334
    public function generateBindKey(string $prefix): string
335
    {
336
        return '_' . uniqid($prefix . '_') . '_';
337
    }
338
}
339