Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

Passed
Push — 0.11 ( a2cf95...c00a09 )
by Jérémiah
16:01
created

Paginator::forward()   A

Complexity

Conditions 5
Paths 2

Size

Total Lines 24

Duplication

Lines 6
Ratio 25 %

Code Coverage

Tests 13
CRAP Score 5

Importance

Changes 0
Metric Value
dl 6
loc 24
ccs 13
cts 13
cp 1
rs 9.2248
c 0
b 0
f 0
cc 5
nc 2
nop 1
crap 5
1
<?php
2
3
namespace Overblog\GraphQLBundle\Relay\Connection;
4
5
use Overblog\GraphQLBundle\Definition\Argument;
6
use Overblog\GraphQLBundle\Relay\Connection\Output\Connection;
7
use Overblog\GraphQLBundle\Relay\Connection\Output\ConnectionBuilder;
8
9
class Paginator
10
{
11
    const MODE_REGULAR = false;
12
    const MODE_PROMISE = true;
13
14
    /** @var callable */
15
    private $fetcher;
16
17
    /** @var bool */
18
    private $promise;
19
20
    /** @var int */
21
    private $totalCount;
22
23
    /**
24
     * @param callable $fetcher
25
     * @param bool     $promise
26
     */
27 14
    public function __construct(callable $fetcher, $promise = self::MODE_REGULAR)
28
    {
29 14
        $this->fetcher = $fetcher;
30 14
        $this->promise = $promise;
31 14
    }
32
33
    /**
34
     * @param Argument     $args
35
     * @param int|callable $total
36
     * @param array        $callableArgs
37
     *
38
     * @return Connection|object A connection or a promise
39
     */
40 7
    public function backward($args, $total, array $callableArgs = [])
41
    {
42 7
        $total = $this->computeTotalCount($total, $callableArgs);
0 ignored issues
show
Bug introduced by
It seems like $total defined by $this->computeTotalCount($total, $callableArgs) on line 42 can also be of type callable; however, Overblog\GraphQLBundle\R...or::computeTotalCount() does only seem to accept integer, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
43
44 7
        $args = $this->protectArgs($args);
45 7
        $limit = $args['last'];
46 7
        $offset = \max(0, ConnectionBuilder::getOffsetWithDefault($args['before'], $total) - $limit);
47
48 7
        $entities = \call_user_func($this->fetcher, $offset, $limit);
49
50 View Code Duplication
        return $this->handleEntities($entities, function ($entities) use ($args, $offset, $total) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
51 7
            return ConnectionBuilder::connectionFromArraySlice($entities, $args, [
52 7
                'sliceStart' => $offset,
53 7
                'arrayLength' => $total,
54
            ]);
55 7
        });
56
    }
57
58
    /**
59
     * @param Argument $args
60
     *
61
     * @return Connection|object A connection or a promise
62
     */
63 7
    public function forward($args)
64
    {
65 7
        $args = $this->protectArgs($args);
66 7
        $limit = $args['first'];
67 7
        $offset = ConnectionBuilder::getOffsetWithDefault($args['after'], 0);
68
69
        // If we don't have a cursor or if it's not valid, then we must not use the slice method
70 7
        if (!\is_numeric(ConnectionBuilder::cursorToOffset($args['after'])) || !$args['after']) {
71 4
            $entities = \call_user_func($this->fetcher, $offset, $limit ? $limit + 1 : $limit);
72
73
            return $this->handleEntities($entities, function ($entities) use ($args) {
74 3
                return ConnectionBuilder::connectionFromArray($entities, $args);
75 4
            });
76
        } else {
77 3
            $entities = \call_user_func($this->fetcher, $offset, $limit ? $limit + 2 : $limit);
78
79 View Code Duplication
            return $this->handleEntities($entities, function ($entities) use ($args, $offset) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
80 3
                return ConnectionBuilder::connectionFromArraySlice($entities, $args, [
81 3
                    'sliceStart' => $offset,
82 3
                    'arrayLength' => $offset + \count($entities),
83
                ]);
84 3
            });
85
        }
86
    }
87
88
    /**
89
     * @param Argument     $args
90
     * @param int|callable $total
91
     * @param array        $callableArgs
92
     *
93
     * @return Connection|object A connection or a promise
94
     */
95 5
    public function auto($args, $total, $callableArgs = [])
96
    {
97 5
        $args = $this->protectArgs($args);
98
99 5
        if ($args['last']) {
100 3
            $connection = $this->backward($args, $total, $callableArgs);
101
        } else {
102 2
            $connection = $this->forward($args);
103
        }
104
105 5
        if ($this->promise) {
106
            return $connection->then(function (Connection $connection) use ($total, $callableArgs) {
107
                $connection->totalCount = $this->computeTotalCount($total, $callableArgs);
0 ignored issues
show
Bug introduced by
It seems like $total defined by parameter $total on line 95 can also be of type callable; however, Overblog\GraphQLBundle\R...or::computeTotalCount() does only seem to accept integer, 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...
108
109
                return $connection;
110 1
            });
111
        } else {
112 4
            $connection->totalCount = $this->computeTotalCount($total, $callableArgs);
0 ignored issues
show
Bug introduced by
It seems like $total defined by parameter $total on line 95 can also be of type callable; however, Overblog\GraphQLBundle\R...or::computeTotalCount() does only seem to accept integer, 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...
113
114 4
            return $connection;
115
        }
116
    }
117
118
    /**
119
     * @param array|object $entities An array of entities to paginate or a promise
120
     * @param callable     $callback
121
     *
122
     * @return Connection|object A connection or a promise
123
     */
124 14
    private function handleEntities($entities, callable $callback)
125
    {
126 14
        if ($this->promise) {
127 1
            return $entities->then($callback);
128
        }
129
130 13
        return \call_user_func($callback, $entities);
131
    }
132
133
    /**
134
     * @param Argument|array $args
135
     *
136
     * @return Argument
137
     */
138 14
    private function protectArgs($args)
139
    {
140 14
        return $args instanceof Argument ? $args : new Argument($args);
141
    }
142
143
    /**
144
     * @param int   $total
145
     * @param array $callableArgs
146
     *
147
     * @return int|mixed
148
     */
149 8
    private function computeTotalCount($total, array $callableArgs = [])
150
    {
151 8
        if (null !== $this->totalCount) {
152 3
            return $this->totalCount;
153
        }
154
155 8
        $this->totalCount = \is_callable($total) ? \call_user_func_array($total, $callableArgs) : $total;
156
157 8
        return $this->totalCount;
158
    }
159
}
160