Completed
Push — master ( 93ccd7...3b27ab )
by Vladimir
27s queued 13s
created

Executor   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 167
Duplicated Lines 0 %

Test Coverage

Coverage 81.13%

Importance

Changes 0
Metric Value
wmc 18
eloc 44
dl 0
loc 167
ccs 43
cts 53
cp 0.8113
rs 10
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A setPromiseAdapter() 0 3 1
A getImplementationFactory() 0 3 1
A getDefaultFieldResolver() 0 3 1
A setImplementationFactory() 0 3 1
A setDefaultFieldResolver() 0 3 1
A promiseToExecute() 0 25 2
A getPromiseAdapter() 0 3 2
A execute() 0 29 2
B defaultFieldResolver() 0 18 7
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 216
    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 216
        $factory = self::$implementationFactory;
142
143
        /** @var ExecutorImplementation $executor */
144 216
        $executor = $factory(
145 216
            $promiseAdapter,
146 216
            $schema,
147 216
            $documentNode,
148 216
            $rootValue,
149 216
            $contextValue,
150 216
            $variableValues,
151 216
            $operationName,
152 216
            $fieldResolver ?: self::$defaultFieldResolver
153
        );
154
155 216
        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 118
    public static function defaultFieldResolver($source, $args, $context, ResolveInfo $info)
171
    {
172 118
        $fieldName = $info->fieldName;
173 118
        $property  = null;
174
175 118
        if (is_array($source) || $source instanceof ArrayAccess) {
176 76
            if (isset($source[$fieldName])) {
177 76
                $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 118
        return $property instanceof Closure
186 34
            ? $property($source, $args, $context, $info)
187 116
            : $property;
188
    }
189
}
190