Imported Upstream version 2.4.0
David Prévot
8 years ago
4 | 4 | - 5.5 |
5 | 5 | - 5.6 |
6 | 6 | - 7.0 |
7 | - nightly | |
7 | 8 | - hhvm |
8 | 9 | |
9 | 10 | before_install: |
10 | 11 | - composer self-update |
11 | 12 | |
12 | 13 | install: |
13 | - composer install --prefer-source | |
14 | - composer install | |
14 | 15 | |
15 | 16 | script: |
16 | 17 | - phpunit -v --coverage-text |
0 | 0 | CHANGELOG |
1 | 1 | ========= |
2 | 2 | |
3 | * 2.4.0 (2016-03-31) | |
4 | ||
5 | * Support foreign thenables in `resolve()`. | |
6 | Any object that provides a `then()` method is now assimilated to a trusted | |
7 | promise that follows the state of this thenable (#52). | |
8 | * Fix `some()` and `any()` for input arrays containing not enough items | |
9 | (#34). | |
10 | ||
3 | 11 | * 2.3.0 (2016-03-24) |
4 | 12 | |
5 | * Allow cancellation of promises returned by functions working on promise | |
6 | collections (#36). | |
7 | * Handle \Throwable in the same way as \Exception (#51 by @joshdifabio). | |
13 | * Allow cancellation of promises returned by functions working on promise | |
14 | collections (#36). | |
15 | * Handle `\Throwable` in the same way as `\Exception` (#51 by @joshdifabio). | |
8 | 16 | |
9 | 17 | * 2.2.2 (2016-02-26) |
10 | 18 | |
11 | * Fix cancellation handlers called multiple times (#47 by @clue). | |
12 | ||
13 | * 2.2.2 (2016-02-26) | |
14 | ||
15 | * Fix cancellation handlers called multiple times (#47 by @clue). | |
19 | * Fix cancellation handlers called multiple times (#47 by @clue). | |
16 | 20 | |
17 | 21 | * 2.2.1 (2015-07-03) |
18 | 22 | |
19 | * Fix stack error when resolving a promise in its own fulfillment or rejection | |
20 | handlers. | |
23 | * Fix stack error when resolving a promise in its own fulfillment or | |
24 | rejection handlers. | |
21 | 25 | |
22 | 26 | * 2.2.0 (2014-12-30) |
23 | 27 | |
24 | * Introduce new ExtendedPromiseInterface implemented by all promises | |
25 | * Add new .done() method (part of the ExtendedPromiseInterface) | |
26 | * Add new .otherwise() method (part of the ExtendedPromiseInterface) | |
27 | * Add new .always() method (part of the ExtendedPromiseInterface) | |
28 | * Add new .progress() method (part of the ExtendedPromiseInterface) | |
29 | * Rename Deferred::progress to Deferred::notify to avoid confusion with | |
30 | ExtendedPromiseInterface::progress (a Deferred::progress alias is still | |
31 | available for backward compatibility) | |
32 | * resolve() now always returns a ExtendedPromiseInterface | |
28 | * Introduce new `ExtendedPromiseInterface` implemented by all promises. | |
29 | * Add new `done()` method (part of the `ExtendedPromiseInterface`). | |
30 | * Add new `otherwise()` method (part of the `ExtendedPromiseInterface`). | |
31 | * Add new `always()` method (part of the `ExtendedPromiseInterface`). | |
32 | * Add new `progress()` method (part of the `ExtendedPromiseInterface`). | |
33 | * Rename `Deferred::progress` to `Deferred::notify` to avoid confusion with | |
34 | `ExtendedPromiseInterface::progress` (a `Deferred::progress` alias is | |
35 | still available for backward compatibility) | |
36 | * `resolve()` now always returns a `ExtendedPromiseInterface`. | |
33 | 37 | |
34 | 38 | * 2.1.0 (2014-10-15) |
35 | 39 | |
36 | * Introduce new CancellablePromiseInterface implemented by all promises | |
37 | * Add new .cancel() method (part of the CancellablePromiseInterface) | |
40 | * Introduce new `CancellablePromiseInterface` implemented by all promises. | |
41 | * Add new `cancel()` method (part of the `CancellablePromiseInterface`). | |
38 | 42 | |
39 | 43 | * 2.0.0 (2013-12-10) |
40 | 44 | |
41 | New major release. The goal was to streamline the API and to make it more | |
42 | compliant with other promise libraries and especially with the new upcoming | |
43 | [ES6 promises specification](https://github.com/domenic/promises-unwrapping/). | |
45 | New major release. The goal is to streamline the API and to make it more | |
46 | compliant with other promise libraries and especially with the new upcoming | |
47 | [ES6 promises specification](https://github.com/domenic/promises-unwrapping/). | |
44 | 48 | |
45 | * Add standalone Promise class. | |
46 | * Add new React\Promise\race() function. | |
47 | * BC break: Bump minimum PHP version to PHP 5.4. | |
48 | * BC break: Remove ResolverInterface and PromiseInterface from Deferred. | |
49 | * BC break: Change signature of PromiseInterface. | |
50 | * BC break: Remove When and Util classes and move static methods to functions. | |
51 | * BC break: FulfilledPromise and RejectedPromise now throw an exception when | |
52 | initialized with a promise instead of a value/reason. | |
53 | * BC break: React\Promise\Deferred::resolve() and React\Promise\Deferred::reject() | |
54 | no longer return a promise. | |
49 | * Add standalone Promise class. | |
50 | * Add new `race()` function. | |
51 | * BC break: Bump minimum PHP version to PHP 5.4. | |
52 | * BC break: Remove `ResolverInterface` and `PromiseInterface` from | |
53 | `Deferred`. | |
54 | * BC break: Change signature of `PromiseInterface`. | |
55 | * BC break: Remove `When` and `Util` classes and move static methods to | |
56 | functions. | |
57 | * BC break: `FulfilledPromise` and `RejectedPromise` now throw an exception | |
58 | when initialized with a promise instead of a value/reason. | |
59 | * BC break: `Deferred::resolve()` and `Deferred::reject()` no longer return | |
60 | a promise. | |
55 | 61 | |
56 | 62 | * 1.0.4 (2013-04-03) |
57 | 63 | |
58 | * Trigger PHP errors when invalid callback is passed. | |
59 | * Fully resolve rejection value before calling rejection handler. | |
60 | * Add When::lazy() to create lazy promises which will be initialized once a | |
61 | consumer calls the then() method. | |
64 | * Trigger PHP errors when invalid callback is passed. | |
65 | * Fully resolve rejection value before calling rejection handler. | |
66 | * Add `When::lazy()` to create lazy promises which will be initialized once | |
67 | a consumer calls the `then()` method. | |
62 | 68 | |
63 | 69 | * 1.0.3 (2012-11-17) |
64 | 70 | |
65 | * Add `PromisorInterface` for objects that have a `promise()` method. | |
71 | * Add `PromisorInterface` for objects that have a `promise()` method. | |
66 | 72 | |
67 | 73 | * 1.0.2 (2012-11-14) |
68 | 74 | |
69 | * Fix bug in When::any() not correctly unwrapping to a single result value | |
70 | * $promiseOrValue argument of When::resolve() and When::reject() is now optional | |
75 | * Fix bug in `When::any()` not correctly unwrapping to a single result | |
76 | value. | |
77 | * `$promiseOrValue` argument of `When::resolve()` and When::reject() is now | |
78 | optional. | |
71 | 79 | |
72 | 80 | * 1.0.1 (2012-11-13) |
73 | 81 | |
74 | * Prevent deep recursion which was reaching `xdebug.max_nesting_level` default of 100 | |
82 | * Prevent deep recursion which was reaching `xdebug.max_nesting_level` | |
83 | default of 100. | |
75 | 84 | |
76 | 85 | * 1.0.0 (2012-11-07) |
77 | 86 | |
78 | * First tagged release | |
87 | * First tagged release. |
461 | 461 | If `$promiseOrValue` is a value, it will be the resolution value of the |
462 | 462 | returned promise. |
463 | 463 | |
464 | If `$promiseOrValue` is a promise, it will simply be returned. | |
464 | If `$promiseOrValue` is a thenable (any object that provides a `then()` method), | |
465 | a trusted promise that follows the state of the thenable is returned. | |
466 | ||
467 | If `$promiseOrValue` is a promise, it will be returned as is. | |
465 | 468 | |
466 | 469 | Note: The promise returned is always a promise implementing |
467 | 470 | [ExtendedPromiseInterface](#extendedpromiseinterface). If you pass in a custom |
519 | 522 | The returned promise will only reject if *all* items in `$promisesOrValues` are |
520 | 523 | rejected. The rejection value will be an array of all rejection reasons. |
521 | 524 | |
525 | The returned promise will also reject with a `React\Promise\Exception\LengthException` | |
526 | if `$promisesOrValues` contains 0 items. | |
527 | ||
522 | 528 | #### some() |
523 | 529 | |
524 | 530 | ```php |
534 | 540 | to resolve (that is, when `(count($promisesOrValues) - $howMany) + 1` items |
535 | 541 | reject). The rejection value will be an array of |
536 | 542 | `(count($promisesOrValues) - $howMany) + 1` rejection reasons. |
543 | ||
544 | The returned promise will also reject with a `React\Promise\Exception\LengthException` | |
545 | if `$promisesOrValues` contains less items than `$howMany`. | |
537 | 546 | |
538 | 547 | #### map() |
539 | 548 | |
664 | 673 | ->then(function ($x) { |
665 | 674 | throw new \Exception($x + 1); |
666 | 675 | }) |
667 | ->then(null, function (\Exception $x) { | |
676 | ->otherwise(function (\Exception $x) { | |
668 | 677 | // Propagate the rejection |
669 | 678 | throw $x; |
670 | 679 | }) |
671 | ->then(null, function (\Exception $x) { | |
680 | ->otherwise(function (\Exception $x) { | |
672 | 681 | // Can also propagate by returning another rejection |
673 | return React\Promise\reject((integer) $x->getMessage() + 1); | |
674 | }) | |
675 | ->then(null, function ($x) { | |
676 | echo 'Reject ' . $x; // 3 | |
682 | return React\Promise\reject( | |
683 | new \Exception($x->getMessage() + 1) | |
684 | ); | |
685 | }) | |
686 | ->otherwise(function ($x) { | |
687 | echo 'Reject ' . $x->getMessage(); // 3 | |
677 | 688 | }); |
678 | 689 | |
679 | 690 | $deferred->resolve(1); // Prints "Reject 3" |
692 | 703 | return $x + 1; |
693 | 704 | }) |
694 | 705 | ->then(function ($x) { |
695 | throw \Exception($x + 1); | |
696 | }) | |
697 | ->then(null, function (\Exception $x) { | |
706 | throw new \Exception($x + 1); | |
707 | }) | |
708 | ->otherwise(function (\Exception $x) { | |
698 | 709 | // Handle the rejection, and don't propagate. |
699 | 710 | // This is like catch without a rethrow |
700 | return (integer) $x->getMessage() + 1; | |
711 | return $x->getMessage() + 1; | |
701 | 712 | }) |
702 | 713 | ->then(function ($x) { |
703 | 714 | echo 'Mixed ' . $x; // 4 |
4 | 4 | class CancellationQueue |
5 | 5 | { |
6 | 6 | private $started = false; |
7 | ||
8 | /** | |
9 | * @var CancellablePromiseInterface[] | |
10 | */ | |
11 | 7 | private $queue = []; |
12 | 8 | |
13 | 9 | public function __invoke() |
20 | 16 | $this->drain(); |
21 | 17 | } |
22 | 18 | |
23 | public function enqueue($promise) | |
19 | public function enqueue($cancellable) | |
24 | 20 | { |
25 | if (!$promise instanceof CancellablePromiseInterface) { | |
21 | if (!method_exists($cancellable, 'then') || !method_exists($cancellable, 'cancel')) { | |
26 | 22 | return; |
27 | 23 | } |
28 | 24 | |
29 | $length = array_push($this->queue, $promise); | |
25 | $length = array_push($this->queue, $cancellable); | |
30 | 26 | |
31 | 27 | if ($this->started && 1 === $length) { |
32 | 28 | $this->drain(); |
36 | 32 | private function drain() |
37 | 33 | { |
38 | 34 | for ($i = key($this->queue); isset($this->queue[$i]); $i++) { |
39 | $promise = $this->queue[$i]; | |
35 | $cancellable = $this->queue[$i]; | |
40 | 36 | |
41 | 37 | $exception = null; |
42 | 38 | |
43 | 39 | try { |
44 | $promise->cancel(); | |
40 | $cancellable->cancel(); | |
41 | } catch (\Throwable $exception) { | |
45 | 42 | } catch (\Exception $exception) { |
46 | 43 | } |
47 | 44 |
0 | <?php | |
1 | ||
2 | namespace React\Promise\Exception; | |
3 | ||
4 | class LengthException extends \LengthException | |
5 | { | |
6 | } |
3 | 3 | |
4 | 4 | function resolve($promiseOrValue = null) |
5 | 5 | { |
6 | if (!$promiseOrValue instanceof PromiseInterface) { | |
7 | return new FulfilledPromise($promiseOrValue); | |
8 | } | |
9 | ||
10 | 6 | if ($promiseOrValue instanceof ExtendedPromiseInterface) { |
11 | 7 | return $promiseOrValue; |
12 | 8 | } |
13 | 9 | |
14 | return new Promise(function ($resolve, $reject, $notify) use ($promiseOrValue) { | |
15 | $promiseOrValue->then($resolve, $reject, $notify); | |
16 | }); | |
10 | if (method_exists($promiseOrValue, 'then')) { | |
11 | $canceller = null; | |
12 | ||
13 | if (method_exists($promiseOrValue, 'cancel')) { | |
14 | $canceller = [$promiseOrValue, 'cancel']; | |
15 | } | |
16 | ||
17 | return new Promise(function ($resolve, $reject, $notify) use ($promiseOrValue) { | |
18 | $promiseOrValue->then($resolve, $reject, $notify); | |
19 | }, $canceller); | |
20 | } | |
21 | ||
22 | return new FulfilledPromise($promiseOrValue); | |
17 | 23 | } |
18 | 24 | |
19 | 25 | function reject($promiseOrValue = null) |
47 | 53 | return; |
48 | 54 | } |
49 | 55 | |
56 | $fulfiller = function ($value) use ($cancellationQueue, $resolve) { | |
57 | $cancellationQueue(); | |
58 | $resolve($value); | |
59 | }; | |
60 | ||
61 | $rejecter = function ($reason) use ($cancellationQueue, $reject) { | |
62 | $cancellationQueue(); | |
63 | $reject($reason); | |
64 | }; | |
65 | ||
50 | 66 | foreach ($array as $promiseOrValue) { |
51 | 67 | $cancellationQueue->enqueue($promiseOrValue); |
52 | ||
53 | $fulfiller = function ($value) use ($cancellationQueue, $resolve) { | |
54 | $cancellationQueue(); | |
55 | $resolve($value); | |
56 | }; | |
57 | ||
58 | $rejecter = function ($reason) use ($cancellationQueue, $reject) { | |
59 | $cancellationQueue(); | |
60 | $reject($reason); | |
61 | }; | |
62 | 68 | |
63 | 69 | resolve($promiseOrValue) |
64 | 70 | ->done($fulfiller, $rejecter, $notify); |
83 | 89 | return new Promise(function ($resolve, $reject, $notify) use ($promisesOrValues, $howMany, $cancellationQueue) { |
84 | 90 | resolve($promisesOrValues) |
85 | 91 | ->done(function ($array) use ($howMany, $cancellationQueue, $resolve, $reject, $notify) { |
86 | if (!is_array($array) || !$array || $howMany < 1) { | |
92 | if (!is_array($array) || $howMany < 1) { | |
87 | 93 | $resolve([]); |
88 | 94 | return; |
89 | 95 | } |
90 | 96 | |
91 | $len = count($array); | |
92 | $toResolve = min($howMany, $len); | |
97 | $len = count($array); | |
98 | ||
99 | if ($len < $howMany) { | |
100 | throw new Exception\LengthException( | |
101 | sprintf( | |
102 | 'Input array must contain at least %d item%s but contains only %s item%s.', | |
103 | $howMany, | |
104 | 1 === $howMany ? '' : 's', | |
105 | $len, | |
106 | 1 === $len ? '' : 's' | |
107 | ) | |
108 | ); | |
109 | } | |
110 | ||
111 | $toResolve = $howMany; | |
93 | 112 | $toReject = ($len - $toResolve) + 1; |
94 | 113 | $values = []; |
95 | 114 | $reasons = []; |
4 | 4 | class CancellationQueueTest extends TestCase |
5 | 5 | { |
6 | 6 | /** @test */ |
7 | public function ignoresNonCancellablePromises() | |
7 | public function acceptsSimpleCancellableThenable() | |
8 | 8 | { |
9 | $p = new SimpleFulfilledTestPromise(); | |
9 | $p = new SimpleTestCancellableThenable(); | |
10 | ||
11 | $cancellationQueue = new CancellationQueue(); | |
12 | $cancellationQueue->enqueue($p); | |
13 | ||
14 | $cancellationQueue(); | |
15 | ||
16 | $this->assertTrue($p->cancelCalled); | |
17 | } | |
18 | ||
19 | /** @test */ | |
20 | public function ignoresSimpleCancellable() | |
21 | { | |
22 | $p = new SimpleTestCancellable(); | |
10 | 23 | |
11 | 24 | $cancellationQueue = new CancellationQueue(); |
12 | 25 | $cancellationQueue->enqueue($p); |
1 | 1 | |
2 | 2 | namespace React\Promise; |
3 | 3 | |
4 | use React\Promise\Exception\LengthException; | |
5 | ||
4 | 6 | class FunctionAnyTest extends TestCase |
5 | 7 | { |
6 | 8 | /** @test */ |
7 | public function shouldResolveToNullWithEmptyInputArray() | |
9 | public function shouldRejectWithLengthExceptionWithEmptyInputArray() | |
10 | { | |
11 | $mock = $this->createCallableMock(); | |
12 | $mock | |
13 | ->expects($this->once()) | |
14 | ->method('__invoke') | |
15 | ->with( | |
16 | $this->callback(function($exception){ | |
17 | return $exception instanceof LengthException && | |
18 | 'Input array must contain at least 1 item but contains only 0 items.' === $exception->getMessage(); | |
19 | }) | |
20 | ); | |
21 | ||
22 | any([]) | |
23 | ->then($this->expectCallableNever(), $mock); | |
24 | } | |
25 | ||
26 | /** @test */ | |
27 | public function shouldResolveToNullWithNonArrayInput() | |
8 | 28 | { |
9 | 29 | $mock = $this->createCallableMock(); |
10 | 30 | $mock |
12 | 32 | ->method('__invoke') |
13 | 33 | ->with($this->identicalTo(null)); |
14 | 34 | |
15 | any([]) | |
35 | any(null) | |
16 | 36 | ->then($mock); |
17 | 37 | } |
18 | 38 |
39 | 39 | $mock, |
40 | 40 | $this->expectCallableNever() |
41 | 41 | ); |
42 | } | |
43 | ||
44 | /** @test */ | |
45 | public function shouldResolveAThenable() | |
46 | { | |
47 | $thenable = new SimpleFulfilledTestThenable(); | |
48 | ||
49 | $mock = $this->createCallableMock(); | |
50 | $mock | |
51 | ->expects($this->once()) | |
52 | ->method('__invoke') | |
53 | ->with($this->identicalTo('foo')); | |
54 | ||
55 | resolve($thenable) | |
56 | ->then( | |
57 | $mock, | |
58 | $this->expectCallableNever() | |
59 | ); | |
60 | } | |
61 | ||
62 | /** @test */ | |
63 | public function shouldResolveACancellableThenable() | |
64 | { | |
65 | $thenable = new SimpleTestCancellableThenable(); | |
66 | ||
67 | $promise = resolve($thenable); | |
68 | $promise->cancel(); | |
69 | ||
70 | $this->assertTrue($thenable->cancelCalled); | |
42 | 71 | } |
43 | 72 | |
44 | 73 | /** @test */ |
0 | 0 | <?php |
1 | 1 | |
2 | 2 | namespace React\Promise; |
3 | ||
4 | use React\Promise\Exception\LengthException; | |
3 | 5 | |
4 | 6 | class FunctionSomeTest extends TestCase |
5 | 7 | { |
6 | 8 | /** @test */ |
7 | public function shouldResolveEmptyInput() | |
9 | public function shouldRejectWithLengthExceptionWithEmptyInputArray() | |
10 | { | |
11 | $mock = $this->createCallableMock(); | |
12 | $mock | |
13 | ->expects($this->once()) | |
14 | ->method('__invoke') | |
15 | ->with( | |
16 | $this->callback(function($exception){ | |
17 | return $exception instanceof LengthException && | |
18 | 'Input array must contain at least 1 item but contains only 0 items.' === $exception->getMessage(); | |
19 | }) | |
20 | ); | |
21 | ||
22 | some( | |
23 | [], | |
24 | 1 | |
25 | )->then($this->expectCallableNever(), $mock); | |
26 | } | |
27 | ||
28 | /** @test */ | |
29 | public function shouldRejectWithLengthExceptionWithInputArrayContainingNotEnoughItems() | |
30 | { | |
31 | $mock = $this->createCallableMock(); | |
32 | $mock | |
33 | ->expects($this->once()) | |
34 | ->method('__invoke') | |
35 | ->with( | |
36 | $this->callback(function($exception){ | |
37 | return $exception instanceof LengthException && | |
38 | 'Input array must contain at least 4 items but contains only 3 items.' === $exception->getMessage(); | |
39 | }) | |
40 | ); | |
41 | ||
42 | some( | |
43 | [1, 2, 3], | |
44 | 4 | |
45 | )->then($this->expectCallableNever(), $mock); | |
46 | } | |
47 | ||
48 | /** @test */ | |
49 | public function shouldResolveToEmptyArrayWithNonArrayInput() | |
8 | 50 | { |
9 | 51 | $mock = $this->createCallableMock(); |
10 | 52 | $mock |
13 | 55 | ->with($this->identicalTo([])); |
14 | 56 | |
15 | 57 | some( |
16 | [], | |
58 | null, | |
17 | 59 | 1 |
18 | 60 | )->then($mock); |
19 | 61 | } |
3 | 3 | |
4 | 4 | class SimpleFulfilledTestPromise implements PromiseInterface |
5 | 5 | { |
6 | public $cancelCalled = false; | |
7 | ||
8 | 6 | public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) |
9 | 7 | { |
10 | 8 | try { |
12 | 10 | $onFulfilled('foo'); |
13 | 11 | } |
14 | 12 | |
15 | return new self('foo'); | |
13 | return new self(); | |
14 | } catch (\Throwable $exception) { | |
15 | return new RejectedPromise($exception); | |
16 | 16 | } catch (\Exception $exception) { |
17 | 17 | return new RejectedPromise($exception); |
18 | 18 | } |
19 | 19 | } |
20 | ||
21 | public function cancel() | |
22 | { | |
23 | $this->cancelCalled = true; | |
24 | } | |
25 | 20 | } |
0 | <?php | |
1 | ||
2 | namespace React\Promise; | |
3 | ||
4 | class SimpleFulfilledTestThenable | |
5 | { | |
6 | public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) | |
7 | { | |
8 | try { | |
9 | if ($onFulfilled) { | |
10 | $onFulfilled('foo'); | |
11 | } | |
12 | ||
13 | return new self(); | |
14 | } catch (\Throwable $exception) { | |
15 | return new RejectedPromise($exception); | |
16 | } catch (\Exception $exception) { | |
17 | return new RejectedPromise($exception); | |
18 | } | |
19 | } | |
20 | } |
10 | 10 | $onRejected('foo'); |
11 | 11 | } |
12 | 12 | |
13 | return new self('foo'); | |
13 | return new self(); | |
14 | } catch (\Throwable $exception) { | |
15 | return new RejectedPromise($exception); | |
14 | 16 | } catch (\Exception $exception) { |
15 | 17 | return new RejectedPromise($exception); |
16 | 18 | } |
0 | <?php | |
1 | ||
2 | namespace React\Promise; | |
3 | ||
4 | class SimpleTestCancellable | |
5 | { | |
6 | public $cancelCalled = false; | |
7 | ||
8 | public function cancel() | |
9 | { | |
10 | $this->cancelCalled = true; | |
11 | } | |
12 | } |
0 | <?php | |
1 | ||
2 | namespace React\Promise; | |
3 | ||
4 | class SimpleTestCancellableThenable | |
5 | { | |
6 | public $cancelCalled = false; | |
7 | ||
8 | public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) | |
9 | { | |
10 | return new self(); | |
11 | } | |
12 | ||
13 | public function cancel() | |
14 | { | |
15 | $this->cancelCalled = true; | |
16 | } | |
17 | } |