SyncPromiseAdapter::onWait()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 0

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

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

179
    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...
180
    {
181 66
    }
182
}
183