Passed
Branch 2.0 (df9ab3)
by Kirill
02:40
created

QueryLimit::paginate()   C

Complexity

Conditions 7
Paths 15

Size

Total Lines 29
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 18
nc 15
nop 2
dl 0
loc 29
rs 6.7272
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * This file is part of laravel.su package.
5
 * For the full copyright and license information, please view the LICENSE
6
 * file that was distributed with this source code.
7
 */
8
declare(strict_types=1);
9
10
namespace App\GraphQL\Queries\Support;
11
12
use GraphQL\Type\Definition\Type;
13
use Illuminate\Database\Query\Builder as QBuilder;
14
use Illuminate\Database\Eloquent\Builder as EBuilder;
15
16
/**
17
 * Class QueryLimit.
18
 */
19
trait QueryLimit
20
{
21
    /**
22
     * @param  array $args
23
     * @return array
24
     */
25
    protected function argumentsWithLimit(array $args): array
26
    {
27
        return array_merge($args, [
28
            '_limit' => [
29
                'type'        => Type::int(),
30
                'description' => 'Items per page: in 1...1000 range',
31
            ],
32
33
            '_page'   => [
34
                'type'        => Type::int(),
35
                'description' => 'Current page number (Usage without "_limit" argument gives no effect)',
36
            ],
37
            '_after'  => [
38
                'type'        => Type::int(),
39
                'description' => 'Items after target ID',
40
            ],
41
            '_before' => [
42
                'type'        => Type::int(),
43
                'description' => 'Items before target ID',
44
            ],
45
        ]);
46
    }
47
48
    /**
49
     * @param  EBuilder|QBuilder $builder
50
     * @param  array $args
51
     * @return EBuilder
52
     */
53
    protected function queryWithLimit($builder, array &$args = [])
54
    {
55
        return $this->paginate($builder, $args);
56
    }
57
58
    /**
59
     * @param  EBuilder|QBuilder $builder
60
     * @param  array $args
61
     * @return EBuilder
62
     */
63
    protected function paginate($builder, array &$args = [])
64
    {
65
        $queryArgs = ['_after', '_before', '_limit', '_page'];
66
67
        switch (true) {
68
            case isset($args['_after']):
69
                $builder = $builder->where('id', '>', (int)$args['_after']);
70
                break;
71
72
            case isset($args['_before']):
73
                $builder = $builder->where('id', '<', (int)$args['_before']);
74
                break;
75
76
            case isset($args['_limit']):
77
                $builder = $builder->take($this->limit($args));
0 ignored issues
show
Bug introduced by
The method take does only exist in Illuminate\Database\Query\Builder, but not in Illuminate\Database\Eloquent\Builder.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
78
                if (isset($args['_page'])) {
79
                    $builder = $this->checkPageAndLimit($builder, $args);
80
                }
81
                break;
82
        }
83
84
        foreach ($queryArgs as $arg) {
85
            if (isset($args[$arg])) {
86
                unset($args[$arg]);
87
            }
88
        }
89
90
        return $builder;
91
    }
92
93
    /**
94
     * @param array $args
95
     * @return int
96
     */
97
    private function limit(array $args = []): int
98
    {
99
        return max(1, min(1000, (int)$args['_limit']));
100
    }
101
102
    /**
103
     * @param $builder
104
     * @param array $args
105
     * @return mixed
106
     */
107
    private function checkPageAndLimit($builder, array $args = [])
108
    {
109
        $page = max(1, (int)$args['_page']);
110
111
        $builder = $builder->skip(($page - 1) * $this->limit($args));
112
113
        return $builder;
114
    }
115
}
116