Skip to content
This repository was archived by the owner on Jan 29, 2020. It is now read-only.

Commit 660a8cc

Browse files
committed
Imports the ApplicationRunner from zend-expressive as RequestHandlerRunner
Imports the (still in development) `ApplicationRunner` from zend-expressive as the class `RequestHandlerRunner`.
1 parent d9b2fb8 commit 660a8cc

File tree

2 files changed

+209
-0
lines changed

2 files changed

+209
-0
lines changed

src/RequestHandlerRunner.php

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?php
2+
/**
3+
* @see https://github.com/zendframework/zend-serverhandler-runner for the canonical source repository
4+
* @copyright Copyright (c) 2018 Zend Technologies USA Inc. (https://www.zend.com)
5+
* @license https://github.com/zendframework/zend-serverhandler-runner/blob/master/LICENSE.md New BSD License
6+
*/
7+
8+
declare(strict_types=1);
9+
10+
namespace Zend\ServerHandler\Runner;
11+
12+
use Psr\Http\Message\ServerRequestInterface;
13+
use Psr\Http\Server\RequestHandlerInterface;
14+
use Throwable;
15+
16+
/**
17+
* "Run" a request handler.
18+
*
19+
* The RequestHandlerRunner will marshal a request using the composed factory, and
20+
* then pass the request to the composed handler. Finally, it emits the response
21+
* returned by the handler using the composed emitter.
22+
*
23+
* If the factory for generating the request raises an exception or throwable,
24+
* then the runner will use the composed error response generator to generate a
25+
* response, based on the exception or throwable raised.
26+
*/
27+
class RequestHandlerRunner
28+
{
29+
/**
30+
* @var Emitter\EmitterInterface
31+
*/
32+
private $emitter;
33+
34+
/**
35+
* A request handler to run as the application.
36+
*
37+
* @var RequestHandlerInterface
38+
*/
39+
private $handler;
40+
41+
/**
42+
* A factory capable of generating an error response in the scenario that
43+
* the $serverRequestFactory raises an exception during generation of the
44+
* request instance.
45+
*
46+
* The factory will receive the Throwable or Exception that caused the error,
47+
* and must return a Psr\Http\Message\ResponseInterface instance.
48+
*
49+
* @var callable
50+
*/
51+
private $serverRequestErrorResponseGenerator;
52+
53+
/**
54+
* A factory capable of generating a Psr\Http\Message\ServerRequestInterface instance.
55+
* The factory will not receive any arguments.
56+
*
57+
* @var callable
58+
*/
59+
private $serverRequestFactory;
60+
61+
public function __construct(
62+
RequestHandlerInterface $handler,
63+
Emitter\EmitterInterface $emitter,
64+
callable $serverRequestFactory,
65+
callable $serverRequestErrorResponseGenerator
66+
) {
67+
$this->handler = $handler;
68+
$this->emitter = $emitter;
69+
$this->serverRequestFactory = $serverRequestFactory;
70+
$this->serverRequestErrorResponseGenerator = $serverRequestErrorResponseGenerator;
71+
}
72+
73+
/**
74+
* Run the application
75+
*/
76+
public function run(ServerRequestInterface $request = null) : void
77+
{
78+
try {
79+
$request = $request ?: ($this->serverRequestFactory)();
80+
} catch (Throwable $e) {
81+
// Error in generating the request
82+
$this->emitMarshalServerRequestException($e);
83+
return;
84+
}
85+
86+
$response = $this->handler->handle($request);
87+
88+
$this->emitter->emit($response);
89+
}
90+
91+
private function emitMarshalServerRequestException(Throwable $exception) : void
92+
{
93+
$response = ($this->serverRequestErrorResponseGenerator)($exception);
94+
$this->emitter->emit($response);
95+
}
96+
}

test/RequestHandlerRunnerTest.php

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
<?php
2+
/**
3+
* @see https://github.com/zendframework/zend-serverhandler-runner for the canonical source repository
4+
* @copyright Copyright (c) 2018 Zend Technologies USA Inc. (https://www.zend.com)
5+
* @license https://github.com/zendframework/zend-serverhandler-runner/blob/master/LICENSE.md New BSD License
6+
*/
7+
8+
declare(strict_types=1);
9+
10+
namespace ZendTest\ServerHandler\Runner;
11+
12+
use Exception;
13+
use PHPUnit\Framework\Assert;
14+
use PHPUnit\Framework\TestCase;
15+
use Prophecy\Argument;
16+
use Psr\Http\Message\ResponseInterface;
17+
use Psr\Http\Message\ServerRequestInterface;
18+
use Psr\Http\Server\RequestHandlerInterface;
19+
use Zend\ServerHandler\Runner\Emitter\EmitterInterface;
20+
use Zend\ServerHandler\Runner\RequestHandlerRunner;
21+
22+
class RequestHandlerRunnerTest extends TestCase
23+
{
24+
public function testUsesErrorResponseGeneratorToGenerateResponseWhenRequestFactoryRaisesException()
25+
{
26+
$exception = new Exception();
27+
$serverRequestFactory = function () use ($exception) {
28+
throw $exception;
29+
};
30+
31+
$response = $this->prophesize(ResponseInterface::class)->reveal();
32+
33+
$errorResponseGenerator = function ($e) use ($exception, $response) {
34+
Assert::assertSame($exception, $e);
35+
return $response;
36+
};
37+
38+
$emitter = $this->prophesize(EmitterInterface::class);
39+
$emitter->emit($response)->shouldBeCalled();
40+
41+
$handler = $this->prophesize(RequestHandlerInterface::class);
42+
$handler->handle(Argument::any())->shouldNotBeCalled();
43+
44+
$runner = new RequestHandlerRunner(
45+
$handler->reveal(),
46+
$emitter->reveal(),
47+
$serverRequestFactory,
48+
$errorResponseGenerator
49+
);
50+
51+
$this->assertNull($runner->run());
52+
}
53+
54+
public function testRunPassesRequestGeneratedByRequestFactoryToHandleWhenNoRequestPassedToRun()
55+
{
56+
$request = $this->prophesize(ServerRequestInterface::class)->reveal();
57+
58+
$serverRequestFactory = function () use ($request) {
59+
return $request;
60+
};
61+
62+
$errorResponseGenerator = function ($e) {
63+
Assert::fail('Should never hit error response generator');
64+
};
65+
66+
$response = $this->prophesize(ResponseInterface::class)->reveal();
67+
68+
$handler = $this->prophesize(RequestHandlerInterface::class);
69+
$handler->handle($request)->willReturn($response);
70+
71+
$emitter = $this->prophesize(EmitterInterface::class);
72+
$emitter->emit($response)->shouldBeCalled();
73+
74+
$runner = new RequestHandlerRunner(
75+
$handler->reveal(),
76+
$emitter->reveal(),
77+
$serverRequestFactory,
78+
$errorResponseGenerator
79+
);
80+
81+
$this->assertNull($runner->run());
82+
}
83+
84+
public function testRunPassesRequestPassedDuringInvocationToHandler()
85+
{
86+
$request = $this->prophesize(ServerRequestInterface::class)->reveal();
87+
88+
$serverRequestFactory = function () {
89+
Assert::fail('Should never hit server request factory');
90+
};
91+
92+
$errorResponseGenerator = function ($e) {
93+
Assert::fail('Should never hit error response generator');
94+
};
95+
96+
$response = $this->prophesize(ResponseInterface::class)->reveal();
97+
98+
$handler = $this->prophesize(RequestHandlerInterface::class);
99+
$handler->handle($request)->willReturn($response);
100+
101+
$emitter = $this->prophesize(EmitterInterface::class);
102+
$emitter->emit($response)->shouldBeCalled();
103+
104+
$runner = new RequestHandlerRunner(
105+
$handler->reveal(),
106+
$emitter->reveal(),
107+
$serverRequestFactory,
108+
$errorResponseGenerator
109+
);
110+
111+
$this->assertNull($runner->run($request));
112+
}
113+
}

0 commit comments

Comments
 (0)