Passed
Push — 1.0.x ( 8353d5...3a2c37 )
by Julien
21:28
created

Query::average()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 4
ccs 0
cts 3
cp 0
crap 2
rs 10
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 initialize()
71
    {
72
        $this->initializeCache();
73
        $this->initializeBind();
74
        $this->initializeBindTypes();
75
        $this->initializeConditions();
76
        $this->initializeDistinct();
77
        $this->initializeFields();
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->getCache(),
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
        foreach ($find?->getIterator() as $key => $value) {
146
            if ($value instanceof Collection) {
147
                $subIgnoreKey = $ignoreKey || in_array($key, ['conditions', 'joins', 'group']);
148
                $sub = $this->prepareFind($value, $subIgnoreKey);
149
                if ($ignoreKey) {
150
                    $build = array_merge($build, $sub);
151
                } else {
152
                    $build[$key] = $sub;
153
                }
154
            } else {
155
                $build[$key] = $value;
156
            }
157
        }
158
        return array_filter($ignoreKey? array_values($build) : $build);
159
    }
160
    
161
    /**
162
     * Find records in the database using the specified criteria.
163
     *
164
     * @param array|null $find Optional. An array of criteria to determine the records to find.
165
     *                         If not provided, the default criteria from `getFind()` method
166
     *                         will be used. Defaults to `null`.
167
     *
168
     * @return ResultsetInterface The result of the find operation.
169
     */
170
    public function find(?array $find = null): ResultsetInterface
171
    {
172
        $find ??= $this->prepareFind();
173
        return $this->loadModel()::find($find);
174
    }
175
    
176
    /**
177
     * Find records in the database using the specified criteria and include related records.
178
     *
179
     * @param array|null $with Optional. An array of related models to include
180
     *                         with the found records. Defaults to `null`.
181
     * @param array|null $find Optional. An array of criteria to determine the records to find.
182
     *                         If not provided, the default criteria from `getFind()` method
183
     *                         will be used. Defaults to `null`.
184
     *
185
     * @return array The result of the find operation with loaded relationships.
186
     */
187
    public function findWith(?array $with = null, ?array $find = null): array
188
    {
189
        $find ??= $this->prepareFind();
190
        $with ??= $this->getWith()?->toArray() ?? [];
191
        $model = $this->loadModel();
192
        assert($model instanceof EagerLoadInterface);
193
        return $model::findWith($with, $find);
194
    }
195
    
196
    /**
197
     * Find the first record in the database using the specified criteria.
198
     *
199
     * @param array|null $find Optional. An array of criteria to determine the record to find.
200
     *                         If not provided, the default criteria from `getFind()` method
201
     *                         will be used to find the first record. Defaults to `null`.
202
     *
203
     * // @todo \Phalcon\Mvc\ModelInterface|\Phalcon\Mvc\Model\Row|null
204
     * @return mixed The result of the find operation, which is the first record that matches the criteria.
205
     */
206
    public function findFirst(?array $find = null): mixed
207
    {
208
        $find ??= $this->prepareFind();
209
        return $this->loadModel()::findFirst($find);
210
    }
211
    
212
    /**
213
     * Find the first record in the database using the specified criteria and relations.
214
     *
215
     * @param array|null $with Optional. An array of relations to eager load for the record.
216
     *                         If not provided, the default relations from `getWith()` method
217
     *                         will be used. Defaults to `null`.
218
     * @param array|null $find Optional. An array of criteria to determine the records to find.
219
     *                         If not provided, the default criteria from `getFind()` method
220
     *                         will be used. Defaults to `null`.
221
     *
222
     * @return mixed The result of the find operation for the first record.
223
     */
224
    public function findFirstWith(?array $with = null, ?array $find = null): mixed
225
    {
226
        $find ??= $this->prepareFind();
227
        $with ??= $this->getWith()?->toArray() ?? [];
228
        $model = $this->loadModel();
229
        assert($model instanceof EagerLoadInterface);
230
        return $model::findFirstWith($with, $find);
231
    }
232
    
233
    /**
234
     * Calculates the average value based on a given set of criteria.
235
     *
236
     * @param array|null $find The criteria to filter the records by (optional).
237
     * @return float|ResultsetInterface The average value or a result set containing the average value.
238
     */
239
    public function average(?array $find = null): float|ResultsetInterface
240
    {
241
        $find ??= $this->prepareFind();
242
        return $this->loadModel()::average($this->getCalculationFind($find));
243
    }
244
    
245
    /**
246
     * Retrieves the total count of items based on the specified model name and find criteria.
247
     * Note: limit and offset are removed from the parameters in order to retrieve the total count
248
     *
249
     * @param array|null $find An array of find criteria to filter the results. If null, the default criteria will be applied.
250
     *
251
     * @return int|ResultsetInterface The total count of items that match the specified criteria.
252
     * @throws \Exception
253
     */
254
    public function count(?array $find = null): int|ResultsetInterface
255
    {
256
        $find ??= $this->prepareFind();
257
        return $this->loadModel()::count($this->getCalculationFind($find));
258
    }
259
    
260
    /**
261
     * Calculates the sum of values based on a given search criteria.
262
     *
263
     * @param array|null $find Optional: The criteria to find the maximum value from.
264
     *                         Default: null (will retrieve the `find` from $this->getFind())
265
     *
266
     * @return float|ResultsetInterface The calculated sum of values.
267
     */
268
    public function sum(?array $find = null): float|ResultsetInterface
269
    {
270
        $find ??= $this->prepareFind();
271
        return $this->loadModel()::sum($this->getCalculationFind($find));
272
    }
273
    
274
    /**
275
     * Retrieves the minimum value.
276
     *
277
     * @param array|null $find Optional: The criteria to find the maximum value from.
278
     *                         Default: null (will retrieve the `find` from $this->getFind())
279
     *
280
     * @return float|ResultsetInterface The maximum value from the dataset
281
     *                                  or a `ResultsetInterface` that represents the grouped maximum values.
282
     */
283
    public function maximum(?array $find = null): float|ResultsetInterface
284
    {
285
        $find ??= $this->prepareFind();
286
        return $this->loadModel()::maximum($this->getCalculationFind($find));
287
    }
288
    
289
    /**
290
     * Retrieves the minimum value.
291
     *
292
     * @param array|null $find Optional: The criteria to find the minimum value from.
293
     *                         Default: null (will retrieve the `find` from $this->getFind())
294
     *
295
     * @return float|ResultsetInterface The minimum value from the dataset
296
     *                                  or a `ResultsetInterface` that represents the grouped minimum values.
297
     */
298
    public function minimum(?array $find = null): float|ResultsetInterface
299
    {
300
        $find ??= $this->prepareFind();
301
        return $this->loadModel()::minimum($this->getCalculationFind($find));
302
    }
303
    
304
    /**
305
     * Retrieves the count criteria based on the specified find criteria.
306
     *
307
     * @param array|null $find An array of find criteria to filter the results. If null, the default criteria will be used.
308
     *
309
     * @return array An array of filtered find criteria without the 'limit' and 'offset' keys.
310
     */
311
    protected function getCalculationFind(?array $find = null): array
312
    {
313
        $find ??= $this->getFind()?->toArray() ?? [];
314
        
315
        if (isset($find['limit'])) {
316
            unset($find['limit']);
317
        }
318
        
319
        if (isset($find['offset'])) {
320
            unset($find['offset']);
321
        }
322
        
323
        return array_filter($find);
324
    }
325
    
326
    /**
327
     * Generates a unique bind key with the given prefix.
328
     *
329
     * @param string $prefix The prefix to be used in the bind key.
330
     *
331
     * @return string The generated bind key.
332
     */
333
    public function generateBindKey(string $prefix): string
334
    {
335
        return '_' . uniqid($prefix . '_') . '_';
336
    }
337
}
338