Skip to content

Commit 01fe2c6

Browse files
committed
Add Generic PromiseWrapper class
1 parent 713bc42 commit 01fe2c6

File tree

8 files changed

+188
-6
lines changed

8 files changed

+188
-6
lines changed

src/Promise/PromiseInterface.php

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,23 @@ interface PromiseInterface
77
* Waits until the promise completes if possible.
88
*
99
* @return mixed
10-
* @throws \LogicException if the promise has no wait function or if the
11-
* promise does not settle after waiting.
10+
* @throws \LogicException if the promise has no wait function.
1211
*/
1312
public function wait();
13+
14+
/**
15+
* Appends fulfillment and rejection handlers to the promise, and returns
16+
* a new promise resolving to the return value of the called handler.
17+
*
18+
* @param callable $onFulfilled Invoked when the promise fulfills
19+
* @param callable $onRejected Invoked when the promise is rejected
20+
*
21+
* @return PromiseInterface
22+
*
23+
* @throws \LogicException if the promise has no then function.
24+
*/
25+
public function then(
26+
callable $onFulfilled = null,
27+
callable $onRejected = null
28+
);
1429
}

src/Promise/PromiseWrapper.php

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<?php
2+
3+
namespace GraphQL\Promise;
4+
5+
class PromiseWrapper implements PromiseInterface
6+
{
7+
private $wrappedPromise;
8+
9+
/**
10+
* PromiseWrapper constructor.
11+
* @param $promise
12+
*/
13+
public function __construct($promise = null)
14+
{
15+
if (null !== $promise) {
16+
$this->setWrappedPromise($promise);
17+
}
18+
}
19+
/**
20+
* @param $promise
21+
* @return self
22+
*/
23+
public static function wrap($promise)
24+
{
25+
return new static($promise);
26+
}
27+
/**
28+
* Waits until the promise completes if possible.
29+
*
30+
* @return mixed
31+
* @throws \LogicException if the promise has no wait function.
32+
*/
33+
public function wait()
34+
{
35+
if (!$this->objectHasMethod($this->wrappedPromise, 'wait')) {
36+
throw new \LogicException('Promise does not implement "wait" method');
37+
}
38+
39+
return $this->wrappedPromise->wait();
40+
}
41+
/**
42+
* Appends fulfillment and rejection handlers to the promise, and returns
43+
* a new promise resolving to the return value of the called handler.
44+
*
45+
* @param callable $onFulfilled Invoked when the promise fulfills
46+
* @param callable $onRejected Invoked when the promise is rejected
47+
*
48+
* @return $this
49+
*
50+
* @throws \LogicException if the promise has no then function.
51+
*/
52+
public function then(
53+
callable $onFulfilled = null,
54+
callable $onRejected = null
55+
)
56+
{
57+
if (null === $onFulfilled && null === $onRejected) {
58+
return $this;
59+
}
60+
$newWrappedPromise = $this->getWrappedPromise()->then($onFulfilled, $onRejected);
61+
62+
return $this->setWrappedPromise($newWrappedPromise);
63+
}
64+
65+
public function getWrappedPromise()
66+
{
67+
return $this->wrappedPromise;
68+
}
69+
70+
public function setWrappedPromise($wrappedPromise)
71+
{
72+
if (!$this->objectHasMethod($wrappedPromise, 'then')) {
73+
throw new \LogicException('Promise does not implement "then" method');
74+
}
75+
76+
$this->wrappedPromise = $wrappedPromise;
77+
78+
return $this;
79+
}
80+
81+
protected function objectHasMethod($object, $method)
82+
{
83+
return is_object($object) && is_callable([$object, $method]);
84+
}
85+
}

tests/Promise/FakePromise.php renamed to tests/Promise/CliPromise.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
<?php
22
namespace GraphQL\Tests\Promise;
33

4-
use GraphQL\Promise\PromiseInterface;
5-
6-
class FakePromise implements PromiseInterface
4+
class CliPromise
75
{
86
private $pid;
97
private $outputFile;
@@ -29,6 +27,11 @@ public function wait()
2927
return $log;
3028
}
3129

30+
public function then()
31+
{
32+
return $this;
33+
}
34+
3235
private function isTerminated()
3336
{
3437
try {
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?php
2+
namespace GraphQL\Tests\Promise\InvalidPromise;
3+
4+
class NoThenMethod
5+
{
6+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
namespace GraphQL\Tests\Promise\InvalidPromise;
3+
4+
class NoWaitMethod
5+
{
6+
public function then()
7+
{
8+
return $this;
9+
}
10+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
namespace GraphQL\Tests\Promise\InvalidPromise;
3+
4+
class ThenReturnsInvalidPromiseMethod
5+
{
6+
public function then()
7+
{
8+
return new NoThenMethod();
9+
}
10+
}

tests/Promise/PromiseTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
namespace GraphQL\Tests\Promise;
33

44
use GraphQL\GraphQL;
5+
use GraphQL\Promise\PromiseWrapper;
56
use GraphQL\Schema;
67
use GraphQL\Type\Definition\ObjectType;
78
use GraphQL\Type\Definition\Type;
@@ -24,7 +25,7 @@ public function testAsyncResolving()
2425
'log' => [
2526
'type' => $logType,
2627
'resolve' => function () {
27-
return new FakePromise('`which composer` diagnose');
28+
return PromiseWrapper::wrap(new CliPromise('`which composer` diagnose'));
2829
},
2930
],
3031
],

tests/Promise/PromiseWrapperTest.php

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
namespace GraphQL\Tests\Promise;
3+
4+
use GraphQL\GraphQL;
5+
use GraphQL\Promise\PromiseWrapper;
6+
use GraphQL\Schema;
7+
use GraphQL\Tests\Promise\InvalidPromise\NoThenMethod;
8+
use GraphQL\Tests\Promise\InvalidPromise\NoWaitMethod;
9+
use GraphQL\Tests\Promise\InvalidPromise\ThenReturnsInvalidPromiseMethod;
10+
use GraphQL\Type\Definition\ObjectType;
11+
use GraphQL\Type\Definition\Type;
12+
13+
class PromiseWrapperTest extends \PHPUnit_Framework_TestCase
14+
{
15+
/**
16+
* @expectedException \LogicException
17+
* @expectedExceptionMessage Promise does not implement "then" method
18+
*/
19+
public function testWrapNotObject()
20+
{
21+
PromiseWrapper::wrap([]);
22+
}
23+
24+
/**
25+
* @expectedException \LogicException
26+
* @expectedExceptionMessage Promise does not implement "then" method
27+
*/
28+
public function testWrapObjectWithoutThenMethod()
29+
{
30+
PromiseWrapper::wrap(new NoThenMethod());
31+
}
32+
33+
/**
34+
* @expectedException \LogicException
35+
* @expectedExceptionMessage Promise does not implement "wait" method
36+
*/
37+
public function testWrapObjectWithoutWaitMethod()
38+
{
39+
$promise = PromiseWrapper::wrap(new NoWaitMethod());
40+
$promise->wait();
41+
}
42+
43+
/**
44+
* @expectedException \LogicException
45+
* @expectedExceptionMessage Promise does not implement "then" method
46+
*/
47+
public function testWrapObjectThenReturnsInvalidPromise()
48+
{
49+
$promise = PromiseWrapper::wrap(new ThenReturnsInvalidPromiseMethod());
50+
$promise->then(function() {});
51+
}
52+
}

0 commit comments

Comments
 (0)