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

Completed
Pull Request — master (#494)
by Jérémiah
18:56
created

Paginator::protectArgs()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Overblog\GraphQLBundle\Relay\Connection;
6
7
use Overblog\GraphQLBundle\Definition\ArgumentInterface;
8
9
class Paginator
10
{
11
    public const MODE_REGULAR = false;
12
    public 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
    /** @var ConnectionBuilder */
24
    private $connectionBuilder;
25
26
    /**
27
     * @param callable $fetcher
28
     * @param bool     $promise
29
     */
30 14
    public function __construct(callable $fetcher, bool $promise = self::MODE_REGULAR, ConnectionBuilder $connectionBuilder = null)
31
    {
32 14
        $this->fetcher = $fetcher;
33 14
        $this->promise = $promise;
34 14
        $this->connectionBuilder = $connectionBuilder ?: new ConnectionBuilder();
35 14
    }
36
37
    /**
38
     * @param ArgumentInterface $args
39
     * @param int|callable      $total
40
     * @param array             $callableArgs
41
     *
42
     * @return ConnectionInterface|object A connection or a promise
43
     */
44 7
    public function backward(ArgumentInterface $args, $total, array $callableArgs = [])
45
    {
46 7
        $total = $this->computeTotalCount($total, $callableArgs);
47 7
        $limit = $args['last'] ?? null;
48 7
        $before = $args['before'] ?? null;
49 7
        $offset = \max(0, $this->connectionBuilder->getOffsetWithDefault($before, $total) - $limit);
50
51 7
        $entities = \call_user_func($this->fetcher, $offset, $limit);
52
53
        return $this->handleEntities($entities, function ($entities) use ($args, $offset, $total) {
54 7
            return $this->connectionBuilder->connectionFromArraySlice($entities, $args, [
55 7
                'sliceStart' => $offset,
56 7
                'arrayLength' => $total,
57
            ]);
58 7
        });
59
    }
60
61
    /**
62
     * @param ArgumentInterface $args
63
     *
64
     * @return ConnectionInterface|object A connection or a promise
65
     */
66 7
    public function forward(ArgumentInterface $args)
67
    {
68 7
        $limit = $args['first'] ?? null;
69 7
        $after = $args['after'] ?? null;
70 7
        $offset = $this->connectionBuilder->getOffsetWithDefault($after, 0);
71
72
        // If we don't have a cursor or if it's not valid, then we must not use the slice method
73 7
        if (!\is_numeric($this->connectionBuilder->cursorToOffset($after)) || !$after) {
74 4
            $entities = \call_user_func($this->fetcher, $offset, $limit ? $limit + 1 : $limit);
75
76
            return $this->handleEntities($entities, function ($entities) use ($args) {
77 3
                return $this->connectionBuilder->connectionFromArray($entities, $args);
78 4
            });
79
        } else {
80 3
            $entities = \call_user_func($this->fetcher, $offset, $limit ? $limit + 2 : $limit);
81
82
            return $this->handleEntities($entities, function ($entities) use ($args, $offset) {
83 3
                return $this->connectionBuilder->connectionFromArraySlice($entities, $args, [
84 3
                    'sliceStart' => $offset,
85 3
                    'arrayLength' => $offset + \count($entities),
86
                ]);
87 3
            });
88
        }
89
    }
90
91
    /**
92
     * @param ArgumentInterface $args
93
     * @param int|callable      $total
94
     * @param array             $callableArgs
95
     *
96
     * @return ConnectionInterface|object A connection or a promise
97
     */
98 5
    public function auto(ArgumentInterface $args, $total, array $callableArgs = [])
99
    {
100 5
        if (isset($args['last'])) {
101 3
            $connection = $this->backward($args, $total, $callableArgs);
102
        } else {
103 2
            $connection = $this->forward($args);
104
        }
105
106 5
        if ($this->promise) {
107
            return $connection->then(function (ConnectionInterface $connection) use ($total, $callableArgs) {
0 ignored issues
show
Bug introduced by
The method then() does not exist on Overblog\GraphQLBundle\R...ion\ConnectionInterface. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

107
            return $connection->/** @scrutinizer ignore-call */ then(function (ConnectionInterface $connection) use ($total, $callableArgs) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
108
                $connection->setTotalCount($this->computeTotalCount($total, $callableArgs));
109
110
                return $connection;
111 1
            });
112
        } else {
113 4
            $connection->setTotalCount($this->computeTotalCount($total, $callableArgs));
114
115 4
            return $connection;
116
        }
117
    }
118
119
    /**
120
     * @param array|object $entities An array of entities to paginate or a promise
121
     * @param callable     $callback
122
     *
123
     * @return ConnectionInterface|object A connection or a promise
124
     */
125 14
    private function handleEntities($entities, callable $callback)
126
    {
127 14
        if ($this->promise) {
128 1
            return $entities->then($callback);
129
        }
130
131 13
        return \call_user_func($callback, $entities);
132
    }
133
134
    /**
135
     * @param int|callable $total
136
     * @param array        $callableArgs
137
     *
138
     * @return int|mixed
139
     */
140 8
    private function computeTotalCount($total, array $callableArgs = [])
141
    {
142 8
        if (null !== $this->totalCount) {
143 3
            return $this->totalCount;
144
        }
145
146 8
        $this->totalCount = \is_callable($total) ? \call_user_func_array($total, $callableArgs) : $total;
0 ignored issues
show
Documentation Bug introduced by
It seems like is_callable($total) ? ca...$callableArgs) : $total can also be of type callable. However, the property $totalCount is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
Bug introduced by
It seems like $total can also be of type integer; however, parameter $function of call_user_func_array() does only seem to accept callable, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

146
        $this->totalCount = \is_callable($total) ? \call_user_func_array(/** @scrutinizer ignore-type */ $total, $callableArgs) : $total;
Loading history...
147
148 8
        return $this->totalCount;
149
    }
150
}
151