Completed
Push — master ( 07b59f...6d8143 )
by Nekrasov
02:49
created

BaseQuery::addItemToResultsUsingKeyBy()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 10
rs 9.2
cc 4
eloc 6
nc 8
nop 2
1
<?php
2
3
namespace Arrilot\BitrixModels\Queries;
4
5
use BadMethodCallException;
6
use Illuminate\Pagination\Paginator;
7
use Illuminate\Pagination\LengthAwarePaginator;
8
use Illuminate\Support\Collection;
9
10
/**
11
 * @method ElementQuery active()
12
 */
13
abstract class BaseQuery
14
{
15
    /**
16
     * Bitrix object to be queried.
17
     *
18
     * @var object
19
     */
20
    protected $bxObject;
21
22
    /**
23
     * Name of the model that calls the query.
24
     *
25
     * @var string
26
     */
27
    protected $modelName;
28
29
    /**
30
     * Model that calls the query.
31
     *
32
     * @var object
33
     */
34
    protected $model;
35
36
    /**
37
     * Query sort.
38
     *
39
     * @var array
40
     */
41
    public $sort = [];
42
43
    /**
44
     * Query filter.
45
     *
46
     * @var array
47
     */
48
    public $filter = [];
49
50
    /**
51
     * Query navigation.
52
     *
53
     * @var array|bool
54
     */
55
    public $navigation = false;
56
57
    /**
58
     * Query select.
59
     *
60
     * @var array
61
     */
62
    public $select = ['FIELDS', 'PROPS'];
63
64
    /**
65
     * The key to list items in array of results.
66
     * Set to false to have auto incrementing integer.
67
     *
68
     * @var string|bool
69
     */
70
    public $keyBy = false;
71
72
    /**
73
     * Indicates that the query should be stopped instead of touching the DB.
74
     * Can be set in query scopes or manually.
75
     *
76
     * @var bool
77
     */
78
    protected $queryShouldBeStopped = false;
79
80
    /**
81
     * Get count of users that match $filter.
82
     *
83
     * @return int
84
     */
85
    abstract public function count();
86
87
    /**
88
     * Get list of items.
89
     *
90
     * @return Collection
91
     */
92
    abstract public function getList();
93
94
    /**
95
     * Constructor.
96
     *
97
     * @param object $bxObject
98
     * @param string $modelName
99
     */
100
    public function __construct($bxObject, $modelName)
101
    {
102
        $this->bxObject = $bxObject;
103
        $this->modelName = $modelName;
104
        $this->model = new $modelName();
105
    }
106
107
    /**
108
     * Get the first item that matches query params.
109
     *
110
     * @return mixed
111
     */
112
    public function first()
113
    {
114
        return $this->limit(1)->getList()->first(null, false);
115
    }
116
117
    /**
118
     * Get item by its id.
119
     *
120
     * @param int $id
121
     *
122
     * @return mixed
123
     */
124
    public function getById($id)
125
    {
126
        if (!$id || $this->queryShouldBeStopped) {
127
            return false;
128
        }
129
130
        $this->sort = [];
131
        $this->keyBy = false;
132
        $this->filter['ID'] = $id;
133
134
        $items = $this->getList();
135
136
        return !empty($items) ? $items[0] : false;
137
    }
138
139
    /**
140
     * Setter for sort.
141
     *
142
     * @param mixed  $by
143
     * @param string $order
144
     *
145
     * @return $this
146
     */
147
    public function sort($by, $order = 'ASC')
148
    {
149
        $this->sort = is_array($by) ? $by : [$by => $order];
150
151
        return $this;
152
    }
153
154
    /**
155
     * Setter for filter.
156
     *
157
     * @param array $filter
158
     *
159
     * @return $this
160
     */
161
    public function filter($filter)
162
    {
163
        $this->filter = array_merge($this->filter, $filter);
164
165
        return $this;
166
    }
167
168
    /**
169
     * Reset filter.
170
     *
171
     * @return $this
172
     */
173
    public function resetFilter()
174
    {
175
        $this->filter = [];
176
177
        return $this;
178
    }
179
180
    /**
181
     * Add another filter to filters array.
182
     *
183
     * @param $filters
184
     *
185
     * @return $this
186
     */
187
    public function addFilter($filters)
188
    {
189
        foreach ($filters as $field => $value) {
190
            $this->filter[$field] = $value;
191
        }
192
193
        return $this;
194
    }
195
196
    /**
197
     * Setter for navigation.
198
     *
199
     * @param $value
200
     *
201
     * @return $this
202
     */
203
    public function navigation($value)
204
    {
205
        $this->navigation = $value;
206
207
        return $this;
208
    }
209
210
    /**
211
     * Setter for select.
212
     *
213
     * @param $value
214
     *
215
     * @return $this
216
     */
217
    public function select($value)
218
    {
219
        $this->select = is_array($value) ? $value : func_get_args();
220
221
        return $this;
222
    }
223
224
    /**
225
     * Setter for keyBy.
226
     *
227
     * @param $value
228
     *
229
     * @return $this
230
     */
231
    public function keyBy($value)
232
    {
233
        $this->keyBy = $value;
234
235
        return $this;
236
    }
237
238
    /**
239
     * Set the "limit" value of the query.
240
     *
241
     * @param int $value
242
     *
243
     * @return $this
244
     */
245
    public function limit($value)
246
    {
247
        $this->navigation['nPageSize'] = $value;
248
249
        return $this;
250
    }
251
252
    /**
253
     * Set the "page number" value of the query.
254
     *
255
     * @param int $num
256
     *
257
     * @return $this
258
     */
259
    public function page($num)
260
    {
261
        $this->navigation['iNumPage'] = $num;
262
263
        return $this;
264
    }
265
266
    /**
267
     * Alias for "limit".
268
     *
269
     * @param int $value
270
     *
271
     * @return $this
272
     */
273
    public function take($value)
274
    {
275
        return $this->limit($value);
276
    }
277
278
    /**
279
     * Set the limit and offset for a given page.
280
     *
281
     * @param  int  $page
282
     * @param  int  $perPage
283
     * @return $this
284
     */
285
    public function forPage($page, $perPage = 15)
286
    {
287
        return $this->page($page)->take($perPage);
288
    }
289
290
    /**
291
     * Paginate the given query into a paginator.
292
     *
293
     * @param  int  $perPage
294
     * @param  string  $pageName
295
     *
296
     * @return \Illuminate\Pagination\LengthAwarePaginator
297
     */
298 View Code Duplication
    public function paginate($perPage = 15, $pageName = 'page')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
299
    {
300
        $page = Paginator::resolveCurrentPage($pageName);
301
        $total = $this->count();
302
        $results = $this->forPage($page, $perPage)->getList();
303
304
        return new LengthAwarePaginator($results, $total, $perPage, $page, [
305
            'path' => Paginator::resolveCurrentPath(),
306
            'pageName' => $pageName,
307
        ]);
308
    }
309
310
    /**
311
     * Get a paginator only supporting simple next and previous links.
312
     *
313
     * This is more efficient on larger data-sets, etc.
314
     *
315
     * @param  int  $perPage
316
     * @param  string  $pageName
317
     *
318
     * @return \Illuminate\Pagination\Paginator
319
     */
320 View Code Duplication
    public function simplePaginate($perPage = 15, $pageName = 'page')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
321
    {
322
        $page = Paginator::resolveCurrentPage($pageName);
323
        $results = $this->forPage($page, $perPage + 1)->getList();
324
325
        return new Paginator($results, $perPage, $page, [
326
            'path' => Paginator::resolveCurrentPath(),
327
            'pageName' => $pageName,
328
        ]);
329
    }
330
331
    /**
332
     * Stop the query from touching DB.
333
     *
334
     * @return $this
335
     */
336
    public function stopQuery()
337
    {
338
        $this->queryShouldBeStopped = true;
339
340
        return $this;
341
    }
342
343
    /**
344
     * Adds $item to $results using keyBy value.
345
     *
346
     * @param $results
347
     * @param $item
348
     *
349
     * @return array
350
     */
351
    protected function addItemToResultsUsingKeyBy(&$results, $item)
352
    {
353
        $keyByValue = ($this->keyBy && isset($item[$this->keyBy])) ? $item[$this->keyBy] : false;
354
355
        if ($keyByValue) {
356
            $results[$keyByValue] = $item;
357
        } else {
358
            $results[] = $item;
359
        }
360
    }
361
362
    /**
363
     * Determine if all fields must be selected.
364
     *
365
     * @return bool
366
     */
367
    protected function fieldsMustBeSelected()
368
    {
369
        return in_array('FIELDS', $this->select);
370
    }
371
372
    /**
373
     * Determine if all fields must be selected.
374
     *
375
     * @return bool
376
     */
377
    protected function propsMustBeSelected()
378
    {
379
        return in_array('PROPS', $this->select)
380
            || in_array('PROPERTIES', $this->select)
381
            || in_array('PROPERTY_VALUES', $this->select);
382
    }
383
384
    /**
385
     * Set $array[$new] as $array[$old] and delete $array[$old].
386
     *
387
     * @param array $array
388
     * @param $old
389
     * @param $new
390
     *
391
     * return null
392
     */
393
    protected function substituteField(&$array, $old, $new)
394
    {
395
        if (isset($array[$old]) && !isset($array[$new])) {
396
            $array[$new] = $array[$old];
397
        }
398
399
        unset($array[$old]);
400
    }
401
402
    /**
403
     * Clear select array from duplication and additional fields.
404
     *
405
     * @return array
406
     */
407
    protected function clearSelectArray()
408
    {
409
        $strip = ['FIELDS', 'PROPS', 'PROPERTIES', 'PROPERTY_VALUES', 'GROUPS', 'GROUP_ID', 'GROUPS_ID'];
410
411
        return array_values(array_diff(array_unique($this->select), $strip));
412
    }
413
414
    /**
415
     * Handle dynamic method calls into the method.
416
     *
417
     * @param string $method
418
     * @param array  $parameters
419
     *
420
     * @throws BadMethodCallException
421
     *
422
     * @return $this
423
     */
424
    public function __call($method, $parameters)
425
    {
426
        if (method_exists($this->model, 'scope'.$method)) {
427
            array_unshift($parameters, $this);
428
429
            $query = call_user_func_array([$this->model, 'scope'.$method], $parameters);
430
431
            if ($query === false) {
432
                $this->stopQuery();
433
            }
434
435
            return $query instanceof static ? $query : $this;
436
        }
437
438
        $className = get_class($this);
439
440
        throw new BadMethodCallException("Call to undefined method {$className}::{$method}()");
441
    }
442
}
443