Failed Conditions
Pull Request — master (#333)
by Jérémiah
04:09
created

SyncPromiseAdapter::createRejected()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 2
dl 0
loc 5
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace GraphQL\Executor\Promise\Adapter;
6
7
use GraphQL\Deferred;
8
use GraphQL\Error\InvariantViolation;
9
use GraphQL\Executor\ExecutionResult;
10
use GraphQL\Executor\Promise\Promise;
11
use GraphQL\Executor\Promise\PromiseAdapter;
12
use GraphQL\Utils\Utils;
13
use function count;
14
15
/**
16
 * Allows changing order of field resolution even in sync environments
17
 * (by leveraging queue of deferreds and promises)
18
 */
19
class SyncPromiseAdapter implements PromiseAdapter
20
{
21
    /**
22
     * @inheritdoc
23
     */
24 193
    public function isThenable($value)
25
    {
26 193
        return $value instanceof Deferred;
27
    }
28
29
    /**
30
     * @inheritdoc
31
     */
32 42
    public function convertThenable($thenable)
33
    {
34 42
        if (! $thenable instanceof Deferred) {
35 1
            throw new InvariantViolation('Expected instance of GraphQL\Deferred, got ' . Utils::printSafe($thenable));
36
        }
37
38 42
        return new Promise($thenable->promise, $this);
39
    }
40
41
    /**
42
     * @inheritdoc
43
     */
44 68
    public function then(Promise $promise, ?callable $onFulfilled = null, ?callable $onRejected = null)
45
    {
46
        /** @var SyncPromise $adoptedPromise */
47 68
        $adoptedPromise = $promise->adoptedPromise;
48
49 68
        return new Promise($adoptedPromise->then($onFulfilled, $onRejected), $this);
50
    }
51
52
    /**
53
     * @inheritdoc
54
     */
55 1
    public function create(callable $resolver)
56
    {
57 1
        $promise = new SyncPromise();
58
59
        try {
60 1
            $resolver(
61
                [
62 1
                    $promise,
63 1
                    'resolve',
64
                ],
65
                [
66 1
                    $promise,
67 1
                    'reject',
68
                ]
69
            );
70
        } catch (\Exception $e) {
71
            $promise->reject($e);
72
        } catch (\Throwable $e) {
73
            $promise->reject($e);
74
        }
75
76 1
        return new Promise($promise, $this);
77
    }
78
79
    /**
80
     * @inheritdoc
81
     */
82 210
    public function createFulfilled($value = null)
83
    {
84 210
        $promise = new SyncPromise();
85
86 210
        return new Promise($promise->resolve($value), $this);
87
    }
88
89
    /**
90
     * @inheritdoc
91
     */
92 27
    public function createRejected($reason)
93
    {
94 27
        $promise = new SyncPromise();
95
96 27
        return new Promise($promise->reject($reason), $this);
97
    }
98
99
    /**
100
     * @inheritdoc
101
     */
102 41
    public function all(array $promisesOrValues)
103
    {
104 41
        $all = new SyncPromise();
105
106 41
        $total  = count($promisesOrValues);
107 41
        $count  = 0;
108 41
        $result = [];
109
110 41
        foreach ($promisesOrValues as $index => $promiseOrValue) {
111 41
            if ($promiseOrValue instanceof Promise) {
112 41
                $result[$index] = null;
113 41
                $promiseOrValue->then(
114
                    function ($value) use ($index, &$count, $total, &$result, $all) {
115 39
                        $result[$index] = $value;
116 39
                        $count++;
117 39
                        if ($count < $total) {
118 25
                            return;
119
                        }
120
121 39
                        $all->resolve($result);
122 41
                    },
123 41
                    [$all, 'reject']
124
                );
125
            } else {
126 11
                $result[$index] = $promiseOrValue;
127 41
                $count++;
128
            }
129
        }
130 41
        if ($count === $total) {
131 1
            $all->resolve($result);
132
        }
133
134 41
        return new Promise($all, $this);
135
    }
136
137
    /**
138
     * Synchronously wait when promise completes
139
     *
140
     * @return ExecutionResult
141
     */
142 217
    public function wait(Promise $promise)
143
    {
144 217
        $this->beforeWait($promise);
145 217
        $dfdQueue     = Deferred::getQueue();
146 217
        $promiseQueue = SyncPromise::getQueue();
147
148 217
        while ($promise->adoptedPromise->state === SyncPromise::PENDING &&
0 ignored issues
show
Bug introduced by
The property state does not seem to exist on React\Promise\Promise.
Loading history...
149 217
            ! ($dfdQueue->isEmpty() && $promiseQueue->isEmpty())
150
        ) {
151 63
            Deferred::runQueue();
152 63
            SyncPromise::runQueue();
153 63
            $this->onWait($promise);
154
        }
155
156
        /** @var SyncPromise $syncPromise */
157 217
        $syncPromise = $promise->adoptedPromise;
158
159 217
        if ($syncPromise->state === SyncPromise::FULFILLED) {
160 217
            return $syncPromise->result;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $syncPromise->result also could return the type Throwable which is incompatible with the documented return type GraphQL\Executor\ExecutionResult.
Loading history...
161
        } elseif ($syncPromise->state === SyncPromise::REJECTED) {
162
            throw $syncPromise->result;
163
        }
164
165
        throw new InvariantViolation('Could not resolve promise');
166
    }
167
168
    /**
169
     * Execute just before starting to run promise completion
170
     *
171
     */
172 217
    protected function beforeWait(Promise $promise)
0 ignored issues
show
Unused Code introduced by
The parameter $promise is not used and could be removed. ( Ignorable by Annotation )

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

172
    protected function beforeWait(/** @scrutinizer ignore-unused */ Promise $promise)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
173
    {
174 217
    }
175
176
    /**
177
     * Execute while running promise completion
178
     *
179
     */
180 63
    protected function onWait(Promise $promise)
0 ignored issues
show
Unused Code introduced by
The parameter $promise is not used and could be removed. ( Ignorable by Annotation )

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

180
    protected function onWait(/** @scrutinizer ignore-unused */ Promise $promise)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
181
    {
182 63
    }
183
}
184