Failed Conditions
Push — master ( 15672a...e51596 )
by Vladimir
03:57
created

SyncPromiseAdapter::convertThenable()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 7
ccs 4
cts 4
cp 1
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 2
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 186
    public function isThenable($value)
25
    {
26 186
        return $value instanceof Deferred;
27
    }
28
29
    /**
30
     * @inheritdoc
31
     */
32 41
    public function convertThenable($thenable)
33
    {
34 41
        if (! $thenable instanceof Deferred) {
35 1
            throw new InvariantViolation('Expected instance of GraphQL\Deferred, got ' . Utils::printSafe($thenable));
36
        }
37
38 41
        return new Promise($thenable->promise, $this);
39
    }
40
41
    /**
42
     * @inheritdoc
43
     */
44 198
    public function then(Promise $promise, ?callable $onFulfilled = null, ?callable $onRejected = null)
45
    {
46
        /** @var SyncPromise $adoptedPromise */
47 198
        $adoptedPromise = $promise->adoptedPromise;
48
49 198
        return new Promise($adoptedPromise->then($onFulfilled, $onRejected), $this);
50
    }
51
52
    /**
53
     * @inheritdoc
54
     */
55 188
    public function create(callable $resolver)
56
    {
57 188
        $promise = new SyncPromise();
58
59
        try {
60 188
            $resolver(
61
                [
62 188
                    $promise,
63 188
                    'resolve',
64
                ],
65
                [
66 188
                    $promise,
67 188
                    'reject',
68
                ]
69
            );
70
        } catch (\Exception $e) {
71
            $promise->reject($e);
72
        } catch (\Throwable $e) {
73
            $promise->reject($e);
74
        }
75
76 188
        return new Promise($promise, $this);
77
    }
78
79
    /**
80
     * @inheritdoc
81
     */
82 61
    public function createFulfilled($value = null)
83
    {
84 61
        $promise = new SyncPromise();
85
86 61
        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 40
    public function all(array $promisesOrValues)
103
    {
104 40
        $all = new SyncPromise();
105
106 40
        $total  = count($promisesOrValues);
107 40
        $count  = 0;
108 40
        $result = [];
109
110 40
        foreach ($promisesOrValues as $index => $promiseOrValue) {
111 40
            if ($promiseOrValue instanceof Promise) {
112 40
                $result[$index] = null;
113 40
                $promiseOrValue->then(
114 40
                    function ($value) use ($index, &$count, $total, &$result, $all) {
115 38
                        $result[$index] = $value;
116 38
                        $count++;
117 38
                        if ($count < $total) {
118 25
                            return;
119
                        }
120
121 38
                        $all->resolve($result);
122 40
                    },
123 40
                    [$all, 'reject']
124
                );
125
            } else {
126 10
                $result[$index] = $promiseOrValue;
127 40
                $count++;
128
            }
129
        }
130 40
        if ($count === $total) {
131 1
            $all->resolve($result);
132
        }
133
134 40
        return new Promise($all, $this);
135
    }
136
137
    /**
138
     * Synchronously wait when promise completes
139
     *
140
     * @return ExecutionResult
141
     */
142 215
    public function wait(Promise $promise)
143
    {
144 215
        $this->beforeWait($promise);
145 215
        $dfdQueue     = Deferred::getQueue();
146 215
        $promiseQueue = SyncPromise::getQueue();
147
148 215
        while ($promise->adoptedPromise->state === SyncPromise::PENDING &&
149 215
            ! ($dfdQueue->isEmpty() && $promiseQueue->isEmpty())
150
        ) {
151 193
            Deferred::runQueue();
152 193
            SyncPromise::runQueue();
153 193
            $this->onWait($promise);
154
        }
155
156
        /** @var SyncPromise $syncPromise */
157 215
        $syncPromise = $promise->adoptedPromise;
158
159 215
        if ($syncPromise->state === SyncPromise::FULFILLED) {
160 215
            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 215
    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 215
    }
175
176
    /**
177
     * Execute while running promise completion
178
     *
179
     */
180 193
    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 193
    }
183
}
184