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
Pull Request — master (#208)
by Renato
07:25
created

Executor::execute()   C

Complexity

Conditions 11
Paths 34

Size

Total Lines 52
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 31
CRAP Score 11

Importance

Changes 0
Metric Value
dl 0
loc 52
ccs 31
cts 31
cp 1
rs 5.9999
c 0
b 0
f 0
cc 11
eloc 31
nc 34
nop 3
crap 11

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/*
4
 * This file is part of the OverblogGraphQLBundle package.
5
 *
6
 * (c) Overblog <http://github.com/overblog/>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Overblog\GraphQLBundle\Request;
13
14
use GraphQL\Executor\ExecutionResult;
15
use GraphQL\Executor\Promise\PromiseAdapter;
16
use GraphQL\Type\Schema;
17
use GraphQL\Validator\DocumentValidator;
18
use GraphQL\Validator\Rules\QueryComplexity;
19
use GraphQL\Validator\Rules\QueryDepth;
20
use Overblog\GraphQLBundle\Error\ErrorHandler;
21
use Overblog\GraphQLBundle\Event\Events;
22
use Overblog\GraphQLBundle\Event\ExecutorContextEvent;
23
use Overblog\GraphQLBundle\Executor\ExecutorInterface;
24
use Overblog\GraphQLBundle\Executor\Promise\PromiseAdapterInterface;
25
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
26
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
27
28
class Executor
29
{
30
    const PROMISE_ADAPTER_SERVICE_ID = 'overblog_graphql.promise_adapter';
31
32
    /** @var Schema[] */
33
    private $schemas;
34
35
    /** @var EventDispatcherInterface|null */
36
    private $dispatcher;
37
38
    /** @var bool */
39
    private $throwException;
40
41
    /** @var ErrorHandler|null */
42
    private $errorHandler;
43
44
    /** @var bool */
45
    private $hasDebugInfo;
46
47
    /** @var ExecutorInterface */
48
    private $executor;
49
50
    /** @var PromiseAdapter */
51
    private $promiseAdapter;
52
53
    /** @var callable|null */
54
    private $defaultFieldResolver;
55
56 14
    public function __construct(
57
        ExecutorInterface $executor,
58
        EventDispatcherInterface $dispatcher = null,
59
        $throwException = false,
60
        ErrorHandler $errorHandler = null,
61
        $hasDebugInfo = false,
62
        PromiseAdapter $promiseAdapter = null,
63
        callable $defaultFieldResolver = null
64
    ) {
65 14
        $this->executor = $executor;
66 14
        $this->dispatcher = $dispatcher;
67 14
        $this->throwException = (bool) $throwException;
68 14
        $this->errorHandler = $errorHandler;
69 14
        $hasDebugInfo ? $this->enabledDebugInfo() : $this->disabledDebugInfo();
70 14
        $this->promiseAdapter = $promiseAdapter;
71 14
        $this->defaultFieldResolver = $defaultFieldResolver;
72 14
    }
73
74 2
    public function setExecutor(ExecutorInterface $executor)
75
    {
76 2
        $this->executor = $executor;
77
78 2
        return $this;
79
    }
80
81 1
    public function setPromiseAdapter(PromiseAdapter $promiseAdapter = null)
82
    {
83 1
        $this->promiseAdapter = $promiseAdapter;
84
85 1
        return $this;
86
    }
87
88 14
    public function addSchema($name, Schema $schema)
89
    {
90 14
        $this->schemas[$name] = $schema;
91
92 14
        return $this;
93
    }
94
95 1
    public function enabledDebugInfo()
96
    {
97 1
        $this->hasDebugInfo = true;
98
99 1
        return $this;
100
    }
101
102 14
    public function disabledDebugInfo()
103
    {
104 14
        $this->hasDebugInfo = false;
105
106 14
        return $this;
107
    }
108
109 34
    public function hasDebugInfo()
110
    {
111 34
        return $this->hasDebugInfo;
112
    }
113
114 8
    public function setMaxQueryDepth($maxQueryDepth)
115
    {
116
        /** @var QueryDepth $queryDepth */
117 8
        $queryDepth = DocumentValidator::getRule('QueryDepth');
118 8
        $queryDepth->setMaxQueryDepth($maxQueryDepth);
119 8
    }
120
121 8
    public function setMaxQueryComplexity($maxQueryComplexity)
122
    {
123
        /** @var QueryComplexity $queryComplexity */
124 8
        $queryComplexity = DocumentValidator::getRule('QueryComplexity');
125 8
        $queryComplexity->setMaxQueryComplexity($maxQueryComplexity);
126 8
    }
127
128
    /**
129
     * @param bool $throwException
130
     *
131
     * @return $this
132
     */
133 28
    public function setThrowException($throwException)
134
    {
135 28
        $this->throwException = (bool) $throwException;
136
137 28
        return $this;
138
    }
139
140 37
    public function execute(array $data, array $context = [], $schemaName = null)
141
    {
142 37
        if (null !== $this->dispatcher) {
143 32
            $event = new ExecutorContextEvent($context);
144 32
            $this->dispatcher->dispatch(Events::EXECUTOR_CONTEXT, $event);
145 32
            $context = $event->getExecutorContext();
146
        }
147
148 37
        if ($this->promiseAdapter) {
149 33
            if (!$this->promiseAdapter instanceof PromiseAdapterInterface && !is_callable([$this->promiseAdapter, 'wait'])) {
150 1
                throw new \RuntimeException(
151 1
                    sprintf(
152 1
                        'PromiseAdapter should be an object instantiating "%s" or "%s" with a "wait" method.',
153 1
                        PromiseAdapterInterface::class,
154 1
                        PromiseAdapter::class
155
                    )
156
                );
157
            }
158
        }
159
160 36
        $schema = $this->getSchema($schemaName);
161
162 36
        $startTime = microtime(true);
163 36
        $startMemoryUsage = memory_get_usage(true);
164
165 36
        $this->executor->setPromiseAdapter($this->promiseAdapter);
166
        // this is needed when not using only generated types
167 36
        if ($this->defaultFieldResolver) {
168 32
            $this->executor->setDefaultFieldResolver($this->defaultFieldResolver);
169
        }
170
171 36
        $result = $this->executor->execute(
172 36
            $schema,
173 36
            isset($data[ParserInterface::PARAM_QUERY]) ? $data[ParserInterface::PARAM_QUERY] : null,
174 36
            $context,
175 36
            $context,
176 36
            $data[ParserInterface::PARAM_VARIABLES],
177 36
            isset($data[ParserInterface::PARAM_OPERATION_NAME]) ? $data[ParserInterface::PARAM_OPERATION_NAME] : null
178
        );
179
180 36
        if ($this->promiseAdapter) {
181 32
            $result = $this->promiseAdapter->wait($result);
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface GraphQL\Executor\Promise\PromiseAdapter as the method wait() does only exist in the following implementations of said interface: GraphQL\Executor\Promise...pter\SyncPromiseAdapter, Overblog\GraphQLBundle\E...ter\ReactPromiseAdapter.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
182
        }
183
184 36
        if (!is_object($result) || !$result instanceof ExecutionResult) {
185 2
            throw new \RuntimeException(
186 2
                sprintf('Execution result should be an object instantiating "%s".', ExecutionResult::class)
187
            );
188
        }
189
190 34
        return $this->prepareResult($result, $startTime, $startMemoryUsage);
191
    }
192
193
    /**
194
     * @param ExecutionResult $result
195
     * @param int             $startTime
196
     * @param int             $startMemoryUsage
197
     *
198
     * @return ExecutionResult
199
     */
200 34
    private function prepareResult($result, $startTime, $startMemoryUsage)
201
    {
202 34
        if ($this->hasDebugInfo()) {
203 1
            $result->extensions['debug'] = [
204 1
                'executionTime' => sprintf('%d ms', round(microtime(true) - $startTime, 3) * 1000),
205 1
                'memoryUsage' => sprintf('%.2F MiB', (memory_get_usage(true) - $startMemoryUsage) / 1024 / 1024),
206
            ];
207
        }
208
209 34
        if (null !== $this->errorHandler) {
210 32
            $this->errorHandler->handleErrors($result, $this->throwException);
211
        }
212
213 34
        return $result;
214
    }
215
216
    /**
217
     * @param string|null $name
218
     *
219
     * @return Schema
220
     */
221 38
    public function getSchema($name = null)
222
    {
223 38
        if (empty($this->schemas)) {
224 1
            throw new \RuntimeException('At least one schema should be declare.');
225
        }
226
227 37
        if (null === $name) {
228 37
            $schema = array_values($this->schemas)[0];
229
        } else {
230
            if (!isset($this->schemas[$name])) {
231
                throw new NotFoundHttpException(sprintf('Could not found "%s" schema.', $name));
232
            }
233
            $schema = $this->schemas[$name];
234
        }
235
236 37
        return $schema;
237
    }
238
}
239