Passed
Pull Request — master (#314)
by Jakub
08:46 queued 02:41
created

Executor::buildExecutionContext()   F

Complexity

Conditions 19
Paths 168

Size

Total Lines 77
Code Lines 48

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 47
CRAP Score 19

Importance

Changes 0
Metric Value
eloc 48
dl 0
loc 77
ccs 47
cts 47
cp 1
rs 3.95
c 0
b 0
f 0
cc 19
nc 168
nop 8
crap 19

How to fix   Long Method    Complexity    Many Parameters   

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:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace GraphQL\Executor;
6
7
use ArrayAccess;
8
use Closure;
9
use GraphQL\Executor\Promise\Adapter\SyncPromiseAdapter;
10
use GraphQL\Executor\Promise\Promise;
11
use GraphQL\Executor\Promise\PromiseAdapter;
12
use GraphQL\Language\AST\DocumentNode;
13
use GraphQL\Type\Definition\ResolveInfo;
14
use GraphQL\Type\Schema;
15
use function is_array;
16
use function is_object;
17
18
/**
19
 * Implements the "Evaluating requests" section of the GraphQL specification.
20
 */
21
class Executor
22
{
23
    /** @var callable|string[] */
24
    private static $defaultFieldResolver = [self::class, 'defaultFieldResolver'];
25
26
    /** @var PromiseAdapter */
27
    private static $defaultPromiseAdapter;
28
29
    /** @var callable */
30
    private static $implementationFactory = [ReferenceExecutor::class, 'create'];
31
32
    public static function getDefaultFieldResolver() : callable
33
    {
34
        return self::$defaultFieldResolver;
35
    }
36
37
    /**
38
     * Custom default resolve function.
39
     */
40
    public static function setDefaultFieldResolver(callable $fieldResolver)
41
    {
42
        self::$defaultFieldResolver = $fieldResolver;
43
    }
44
45 144
    public static function getPromiseAdapter() : PromiseAdapter
46
    {
47 144
        return self::$defaultPromiseAdapter ?: (self::$defaultPromiseAdapter = new SyncPromiseAdapter());
48
    }
49
50 24
    public static function setPromiseAdapter(?PromiseAdapter $defaultPromiseAdapter = null)
51
    {
52 24
        self::$defaultPromiseAdapter = $defaultPromiseAdapter;
53 24
    }
54
55
    public static function getImplementationFactory() : callable
56
    {
57
        return self::$implementationFactory;
58
    }
59
60
    /**
61
     * Custom executor implementation factory.
62
     *
63
     * Will be called with as
64
     */
65
    public static function setImplementationFactory(callable $implementationFactory)
66
    {
67
        self::$implementationFactory = $implementationFactory;
68
    }
69
70
    /**
71
     * Executes DocumentNode against given $schema.
72
     *
73
     * Always returns ExecutionResult and never throws. All errors which occur during operation
74
     * execution are collected in `$result->errors`.
75
     *
76
     * @param mixed|null               $rootValue
77
     * @param mixed[]|null             $contextValue
78
     * @param mixed[]|ArrayAccess|null $variableValues
79
     * @param string|null              $operationName
80
     *
81
     * @return ExecutionResult|Promise
82
     *
83
     * @api
84
     */
85 116
    public static function execute(
86
        Schema $schema,
87
        DocumentNode $documentNode,
88
        $rootValue = null,
89
        $contextValue = null,
90
        $variableValues = null,
91
        $operationName = null,
92
        ?callable $fieldResolver = null
93
    ) {
94
        // TODO: deprecate (just always use SyncAdapter here) and have `promiseToExecute()` for other cases
95
96 116
        $promiseAdapter = static::getPromiseAdapter();
97
98 116
        $result = static::promiseToExecute(
99 116
            $promiseAdapter,
100 116
            $schema,
101 116
            $documentNode,
102 116
            $rootValue,
103 116
            $contextValue,
104 116
            $variableValues,
0 ignored issues
show
Bug introduced by
It seems like $variableValues can also be of type ArrayAccess; however, parameter $variableValues of GraphQL\Executor\Executor::promiseToExecute() does only seem to accept array<mixed,mixed>|null, 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

104
            /** @scrutinizer ignore-type */ $variableValues,
Loading history...
105 116
            $operationName,
106 116
            $fieldResolver
107
        );
108
109 116
        if ($promiseAdapter instanceof SyncPromiseAdapter) {
110 116
            $result = $promiseAdapter->wait($result);
111
        }
112
113 116
        return $result;
114
    }
115
116
    /**
117
     * Same as execute(), but requires promise adapter and returns a promise which is always
118
     * fulfilled with an instance of ExecutionResult and never rejected.
119
     *
120
     * Useful for async PHP platforms.
121
     *
122
     * @param mixed[]|null $rootValue
123
     * @param mixed[]|null $contextValue
124
     * @param mixed[]|null $variableValues
125
     * @param string|null  $operationName
126
     *
127
     * @return Promise
128
     *
129
     * @api
130
     */
131 209
    public static function promiseToExecute(
132
        PromiseAdapter $promiseAdapter,
133
        Schema $schema,
134
        DocumentNode $documentNode,
135
        $rootValue = null,
136
        $contextValue = null,
137
        $variableValues = null,
138
        $operationName = null,
139
        ?callable $fieldResolver = null
140
    ) {
141 209
        $factory = self::$implementationFactory;
142
143
        /** @var ExecutorImplementation $executor */
144 209
        $executor = $factory(
145 209
            $promiseAdapter,
146 209
            $schema,
147 209
            $documentNode,
148 209
            $rootValue,
149 209
            $contextValue,
150 209
            $variableValues,
151 209
            $operationName,
152 209
            $fieldResolver ?: self::$defaultFieldResolver
153
        );
154
155 209
        return $executor->doExecute();
156
    }
157
158
    /**
159
     * If a resolve function is not given, then a default resolve behavior is used
160
     * which takes the property of the source object of the same name as the field
161
     * and returns it as the result, or if it's a function, returns the result
162
     * of calling that function while passing along args and context.
163
     *
164
     * @param mixed        $source
165
     * @param mixed[]      $args
166
     * @param mixed[]|null $context
167
     *
168
     * @return mixed|null
169
     */
170 116
    public static function defaultFieldResolver($source, $args, $context, ResolveInfo $info)
171
    {
172 116
        $fieldName = $info->fieldName;
173 116
        $property  = null;
174
175 116
        if (is_array($source) || $source instanceof ArrayAccess) {
176 74
            if (isset($source[$fieldName])) {
177 74
                $property = $source[$fieldName];
178
            }
179 42
        } elseif (is_object($source)) {
180 41
            if (isset($source->{$fieldName})) {
181 41
                $property = $source->{$fieldName};
182
            }
183
        }
184
185 116
        return $property instanceof Closure ? $property($source, $args, $context, $info) : $property;
186
    }
187
}
188