Completed
Push — master ( ce8ca0...29d6b0 )
by Renato
05:34
created

AbstractRepository::orderDown()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 3
dl 0
loc 6
ccs 0
cts 4
cp 0
crap 2
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace NwLaravel\Repositories\Eloquent;
4
5
use Illuminate\Database\Eloquent\Builder;
6
use Prettus\Repository\Eloquent\BaseRepository;
7
use NwLaravel\Repositories\RepositoryInterface;
8
use NwLaravel\Repositories\Criterias\InputCriteria;
9
use NwLaravel\Resultset\BuilderResultset;
10
use Prettus\Validator\Contracts\ValidatorInterface;
11
use Prettus\Repository\Events\RepositoryEntityCreated;
12
use Prettus\Repository\Events\RepositoryEntityUpdated;
13
use Prettus\Repository\Events\RepositoryEntityDeleted;
14
use Illuminate\Database\Query\Expression;
15
use Illuminate\Database\Query\Grammars;
16
use BadMethodCallException;
17
use RuntimeException;
18
19
/**
20
 * Class AbstractRepository
21
 *
22
 * @abstract
23
 */
24
abstract class AbstractRepository extends BaseRepository implements RepositoryInterface
25
{
26
    /**
27
     * @var string
28
     */
29
    protected $orderBy;
30
31
    /**
32
     * @var bool
33
     */
34
    protected $skipPresenter = true;
35
36
    /**
37
     * Reset Model
38
     *
39
     * @return AbstractRepository
40
     * @throws RepositoryException
41
     */
42 11
    public function resetModel()
43
    {
44 11
        parent::resetModel();
45 11
        return $this;
46
    }
47
48
    /**
49
     * Get Query
50
     *
51
     * @return Builder
52
     */
53 2
    public function getQuery()
54
    {
55 2
        $this->applyCriteria();
56 2
        $this->applyScope();
57
58 2
        return ($this->model instanceof Builder) ? $this->model : $this->model->newQuery();
59
    }
60
61
    /**
62
     * Search All
63
     *
64
     * @param array  $input         Array Imput
65
     * @param string $orderBy       String Order By
66
     * @param int    $limit         Integer Limit
67
     * @param bool   $skipPresenter Boolean Skip Presenter
68
     *
69
     * @return BuilderResultset
70
     */
71 1
    public function searchAll(array $input, $orderBy = '', $limit = null, $skipPresenter = true)
72
    {
73 1
        $orderBy = $orderBy?:$this->orderBy;
74
75 1
        $query = $this
76 1
            ->whereInputCriteria($input)
77 1
            ->orderBy($orderBy)
78 1
            ->skipPresenter($skipPresenter)
79 1
            ->getQuery()
80 1
            ->limit($limit);
81
82 1
        $this->resetModel();
83 1
        return app(BuilderResultset::class, [$query]);
84
    }
85
86
    /**
87
     * Search Paginator
88
     *
89
     * @param array    $input         Array Input
90
     * @param string   $orderBy       String Order By
91
     * @param int|null $limit         Integer Limit
92
     * @param bool     $skipPresenter Boolean Skip Presenter
93
     *
94
     * @return Paginator
95
     */
96 1
    public function search(array $input, $orderBy = '', $limit = null, $skipPresenter = true)
97
    {
98 1
        $orderBy = $orderBy?:$this->orderBy;
99
100 1
        return $this
101 1
            ->whereInputCriteria($input)
102 1
            ->orderBy($orderBy)
103 1
            ->skipPresenter($skipPresenter)
104 1
            ->paginate($limit);
0 ignored issues
show
Bug introduced by
It seems like $limit defined by parameter $limit on line 96 can also be of type integer; however, Prettus\Repository\Contr...ryInterface::paginate() does only seem to accept null, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
105
    }
106
107
    /**
108
     * Get an array with the values of a given column.
109
     *
110
     * @param  string $column String Column
111
     * @param  string $key    String Key
112
     *
113
     * @return \Illuminate\Support\Collection
114
     */
115 1
    public function pluck($column, $key = null)
116
    {
117 1
        $this->applyCriteria();
118 1
        $this->applyScope();
119
120 1
        $lists = $this->model->pluck($column, $key);
121
122 1
        $this->resetModel();
123 1
        return $lists;
124
    }
125
126
    /**
127
     * Add an "order by" clause to the query.
128
     *
129
     * @param  string $columns   String Columns
130
     * @param  string $direction String Direction
131
     *
132
     * @return RepositoryInterface
133
     */
134 3
    public function orderBy($columns, $direction = 'asc')
135
    {
136 3
        if (!empty($columns)) {
137 3
            $columns = explode(',', $columns);
138 3
            foreach ($columns as $key => $column) {
139 3
                $column = explode(' ', $column);
140 3
                $column = array_filter($column);
141 3
                $column = array_pad($column, 2, '');
142 3
                list($field, $sort) = array_values($column);
143 3
                if (!empty($sort)) {
144 2
                    $direction = $sort;
145 2
                }
146 3
                $direction = strtoupper($direction);
147 3
                $direction = in_array($direction, ['ASC', 'DESC']) ? $direction : 'ASC';
148 3
                $this->model = $this->model->orderBy($field, $direction);
149 3
            }
150 3
        }
151
152 3
        return $this;
153
    }
154
155
    /**
156
     * Random
157
     *
158
     * @return RepositoryInterface
159
     */
160 4
    public function random()
161
    {
162 4
        $grammar = $this->model->getConnection()->getQueryGrammar();
163
164 4
        switch (true) {
165 4
            case $grammar instanceof Grammars\MySqlGrammar:
166 4
            case $grammar instanceof Grammars\SqlServerGrammar:
167 2
                $random = 'RAND()';
168 2
                break;
169 2
            case $grammar instanceof Grammars\PostgresGrammar:
170 2
            case $grammar instanceof Grammars\SQLiteGrammar:
171 2
                $random = 'RANDOM()';
172 2
        }
173
174 4
        $this->model = $this->model->orderBy(new Expression($random));
0 ignored issues
show
Bug introduced by
The variable $random does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
175
176 4
        return $this;
177
    }
178
    
179
    /**
180
     * Count
181
     *
182
     * @param array $input Array Input
183
     *
184
     * @return int
185
     */
186 1
    public function count(array $input = array())
187
    {
188 1
        $this->applyCriteria();
189 1
        $this->applyScope();
190
        
191 1
        $this->whereInputCriteria($input);
192
        
193 1
        $count = $this->model->count();
194
        
195 1
        $this->resetModel();
196 1
        return $count;
197
    }
198
    
199
    /**
200
     * Max
201
     *
202
     * @param mixed $field Mixed Field
203
     * @param array $input Array Input
204
     *
205
     * @return mixed
206
     */
207 1
    public function max($field, array $input = array())
208
    {
209 1
        $this->applyCriteria();
210 1
        $this->applyScope();
211
    
212 1
        $this->whereInputCriteria($input);
213
    
214 1
        $max = $this->model->max($field);
215
    
216 1
        $this->resetModel();
217 1
        return $max;
218
    }
219
220
    /**
221
     * Min
222
     *
223
     * @param mixed $field Mixed Field
224
     * @param array $input Array Input
225
     *
226
     * @return mixed
227
     */
228 1
    public function min($field, array $input = array())
229
    {
230 1
        $this->applyCriteria();
231 1
        $this->applyScope();
232
    
233 1
        $this->whereInputCriteria($input);
234
    
235 1
        $max = $this->model->min($field);
236
    
237 1
        $this->resetModel();
238 1
        return $max;
239
    }
240
241
    /**
242
     * Sum
243
     *
244
     * @param mixed $field Mixed Field
245
     * @param array $input Array Input
246
     *
247
     * @return float
248
     */
249 1
    public function sum($field, array $input = array())
250
    {
251 1
        $this->applyCriteria();
252 1
        $this->applyScope();
253
    
254 1
        $this->whereInputCriteria($input);
255
    
256 1
        $max = $this->model->sum($field);
257
    
258 1
        $this->resetModel();
259 1
        return $max;
260
    }
261
262
    /**
263
     * Average
264
     *
265
     * @param mixed $field Mixed Field
266
     * @param array $input Array Input
267
     *
268
     * @return int
269
     */
270 1
    public function avg($field, array $input = array())
271
    {
272 1
        $this->applyCriteria();
273 1
        $this->applyScope();
274
    
275 1
        $this->whereInputCriteria($input);
276
    
277 1
        $avg = $this->model->avg($field);
278
    
279 1
        $this->resetModel();
280 1
        return $avg;
281
    }
282
283
    /**
284
     * Order Up
285
     *
286
     * @param Model  $model
287
     * @param string $field Field Order
288
     * @param array  $input Array Where
289
     *
290
     * @return boolean
291
     */
292
    public function orderUp($model, $field, array $input = [])
293
    {
294
        $input["{$field} <= ?"] = $model->{$field};
295
        $input["id != ?"] = $model->id;
296
        return $this->reorder($model, $field, $input, 'DESC');
297
    }
298
299
    /**
300
     * Order Down
301
     *
302
     * @param Model  $model
303
     * @param string $field Field Order
304
     * @param array  $input Array Where
305
     *
306
     * @return boolean
307
     */
308
    public function orderDown($model, $field, array $input = [])
309
    {
310
        $input["{$field} >= ?"] = $model->{$field};
311
        $input["id != ?"] = $model->id;
312
        return $this->reorder($model, $field, $input, 'ASC');
313
    }
314
315
    /**
316
     * Reorder
317
     *
318
     * @param Model  $model
319
     * @param string $field Field Order
320
     * @param array  $input Array Where
321
     * @param string $sort  Sort
322
     *
323
     * @return boolean
324
     */
325
    protected function reorder($model, $field, array $input, $sort)
326
    {
327
        if (!$model->exists) {
328
            return false;
329
        }
330
331
        $order = $model->{$field};
332
333
        $anterior = $this->whereInputCriteria($input)->orderBy($field, $sort)->first();
334
335
        if ($anterior) {
336
            $model->{$field} = $anterior->{$field};
337
            $model->save();
338
339
            $anterior->{$field} = $order;
340
            $anterior->save();
341
        }
342
343
        return true;
344
    }
345
346
    /**
347
     * Where InputCriteria
348
     *
349
     * @param array $input Array Input
350
     *
351
     * @return RepositoryInterface
352
     */
353 8
    public function whereInputCriteria(array $input = array())
354
    {
355 8
        if (count($input)) {
356 8
            $criteria = app(InputCriteria::class, [$input]);
357 8
            $this->model = $criteria->apply($this->model, $this);
358 8
        }
359
360 8
        return $this;
361
    }
362
    
363
    /**
364
     * Validar
365
     *
366
     * @param array  $attributes
367
     * @param string $action
368
     * @param string $id
369
     *
370
     * @return bool
371
     */
372 2
    public function validar(array $attributes, $action, $id = null)
373
    {
374 2
        $return = false;
375
376 2
        if (!is_null($this->validator)) {
377
            // we should pass data that has been casts by the model
378
            // to make sure data type are same because validator may need to use
379
            // this data to compare with data that fetch from database.
380 2
            $model = $this->model->newInstance()->forceFill($attributes);
381 2
            $attributes = array_merge($attributes, $model->toArray());
382
383 2
            $validator = $this->validator->with($attributes);
384
385 2
            if ($id) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $id of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
386 1
                $validator->setId($id);
387 1
            }
388
389 2
            $return = $validator->passesOrFail($action);
390 2
        }
391
392 2
        return $return;
393
    }
394
395
    /**
396
     * Save a new model in repository
397
     *
398
     * @throws ValidatorException
399
     * @param array $attributes Array Attributes
400
     * @return mixed
401
     */
402 1
    public function create(array $attributes)
403
    {
404 1
        $this->validar($attributes, ValidatorInterface::RULE_CREATE);
405
406 1
        $model = $this->model->newInstance($attributes);
407 1
        $model->save();
408 1
        $this->resetModel();
409
410 1
        event(new RepositoryEntityCreated($this, $model));
411
412 1
        return $this->parserResult($model);
413
    }
414
415
    /**
416
     * Update a model in repository by id
417
     *
418
     * @throws ValidatorException
419
     * @param array $attributes Array Attributes
420
     * @param int   $id         Integer Id
421
     * @return mixed
422
     */
423 1
    public function update(array $attributes, $id)
424
    {
425 1
        $this->applyScope();
426
427 1
        $this->validar($attributes, ValidatorInterface::RULE_UPDATE, $id);
428
429 1
        $temporarySkipPresenter = $this->skipPresenter;
430
431 1
        $this->skipPresenter(true);
432
433 1
        $model = $this->model->findOrFail($id);
434 1
        $model->fill($attributes);
435 1
        $model->save();
436
437 1
        $this->skipPresenter($temporarySkipPresenter);
438 1
        $this->resetModel();
439
440 1
        event(new RepositoryEntityUpdated($this, $model));
441
442 1
        return $this->parserResult($model);
443
    }
444
445
    /**
446
     * Delete multiple entities by given criteria.
447
     *
448
     * @param array $where
449
     *
450
     * @return boolean|null
451
     */
452 1
    public function deleteWhere(array $where)
453
    {
454 1
        $this->applyCriteria();
455 1
        $this->applyScope();
456
        
457 1
        $temporarySkipPresenter = $this->skipPresenter;
458 1
        $this->skipPresenter(true);
459
460 1
        $this->whereInputCriteria($where);
461
462 1
        $deleted = $this->model->delete();
463
464 1
        event(new RepositoryEntityDeleted($this, $this->model));
465
466 1
        $this->skipPresenter($temporarySkipPresenter);
467 1
        $this->resetModel();
468
469 1
        return $deleted;
470
    }
471
472
    /**
473
     * Update multiple entities by given criteria.
474
     *
475
     * @param array $where
476
     *
477
     * @return boolean|null
478
     */
479 1
    public function updateWhere(array $attributes, array $where)
480
    {
481 1
        $this->applyCriteria();
482 1
        $this->applyScope();
483
484 1
        $temporarySkipPresenter = $this->skipPresenter;
485 1
        $this->skipPresenter(true);
486
487 1
        $this->whereInputCriteria($where);
488
489 1
        $updated = $this->model->update($attributes);
490
491 1
        event(new RepositoryEntityUpdated($this, $this->model));
492
493 1
        $this->skipPresenter($temporarySkipPresenter);
494 1
        $this->resetModel();
495
496 1
        return $updated;
497
    }
498
499
    /**
500
     * Handle dynamic method calls into the method.
501
     *
502
     * @param  string  $method
503
     * @param  array   $parameters
504
     *
505
     * @return AbstractRepository
506
     *
507
     * @throws BadMethodCallException
508
     */
509 7
    public function __call($method, $parameters)
510
    {
511 7
        $pattern = '/^(((where|orWhere).*)|limit|groupBy|join|leftJoin|rightJoin|crossJoin)$/';
512 7
        if (preg_match($pattern, $method)) {
513 6
            $this->model = call_user_func_array([$this->model, $method], $parameters);
514 6
            return $this;
515
        }
516
517 1
        $className = static::class;
518 1
        throw new BadMethodCallException("Call to undefined method {$className}::{$method}()");
519
    }
520
}
521