Skip to content

Commit 31d9008

Browse files
authored
Merge pull request #294 from clue-labs/runner
Rename internal SAPI handlers to `HttpServerRunner` and `SapiRunner` and update API to use invokable classes
2 parents dcdcfb0 + f625681 commit 31d9008

8 files changed

Lines changed: 186 additions & 159 deletions

File tree

src/App.php

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@
22

33
namespace FrameworkX;
44

5-
use FrameworkX\Io\LogStreamHandler;
65
use FrameworkX\Io\MiddlewareHandler;
7-
use FrameworkX\Io\ReactiveHandler;
86
use FrameworkX\Io\RedirectHandler;
97
use FrameworkX\Io\RouteHandler;
10-
use FrameworkX\Io\SapiHandler;
8+
use FrameworkX\Runner\HttpServerRunner;
9+
use FrameworkX\Runner\SapiRunner;
1110
use Psr\Http\Message\ResponseInterface;
1211
use Psr\Http\Message\ServerRequestInterface;
1312
use React\Http\Message\Response;
@@ -23,8 +22,8 @@ class App
2322
/** @var RouteHandler */
2423
private $router;
2524

26-
/** @var ReactiveHandler|SapiHandler */
27-
private $sapi;
25+
/** @var HttpServerRunner|SapiRunner */
26+
private $runner;
2827

2928
/**
3029
* Instantiate new X application
@@ -127,7 +126,7 @@ public function __construct(...$middleware)
127126

128127
$this->router = $router;
129128
$this->handler = new MiddlewareHandler($handlers);
130-
$this->sapi = $container->getSapi();
129+
$this->runner = $container->getRunner();
131130
}
132131

133132
/**
@@ -241,7 +240,7 @@ public function redirect(string $route, string $target, int $code = Response::ST
241240
* Runs the app to handle HTTP requests according to any registered routes and middleware.
242241
*
243242
* This is where the magic happens: When executed on the command line (CLI),
244-
* this will run the powerful reactive request handler built on top of
243+
* this will run the powerful reactive application runner built on top of
245244
* ReactPHP. This works by running the efficient built-in HTTP web server to
246245
* handle incoming HTTP requests through ReactPHP's HTTP and socket server.
247246
* This async execution mode is usually recommended as it can efficiently
@@ -252,14 +251,14 @@ public function redirect(string $route, string $target, int $code = Response::ST
252251
* When executed behind traditional PHP SAPIs (PHP-FPM, FastCGI, Apache, etc.),
253252
* this will handle a single request and run until a single response is sent.
254253
* This is particularly useful because it allows you to run the exact same
255-
* app in any environment.
254+
* application code in any environment.
256255
*
257-
* @see ReactiveHandler::run()
258-
* @see SapiHandler::run()
256+
* @see HttpServerRunner::__invoke()
257+
* @see SapiRunner::__invoke()
259258
*/
260259
public function run(): void
261260
{
262-
$this->sapi->run(\Closure::fromCallable([$this, 'handleRequest']));
261+
($this->runner)(\Closure::fromCallable([$this, 'handleRequest']));
263262
}
264263

265264
/**

src/Container.php

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
namespace FrameworkX;
44

55
use FrameworkX\Io\LogStreamHandler;
6-
use FrameworkX\Io\ReactiveHandler;
76
use FrameworkX\Io\RouteHandler;
8-
use FrameworkX\Io\SapiHandler;
7+
use FrameworkX\Runner\HttpServerRunner;
8+
use FrameworkX\Runner\SapiRunner;
99
use Psr\Container\ContainerInterface;
1010
use Psr\Http\Message\ServerRequestInterface;
1111

@@ -169,8 +169,8 @@ public function getObject(string $class) /*: object (PHP 7.2+) */
169169
return $this; // @phpstan-ignore-line returns instanceof `T`
170170
} elseif ($class === RouteHandler::class) {
171171
return new RouteHandler($this); // @phpstan-ignore-line returns instanceof `T`
172-
} elseif ($class === ReactiveHandler::class) {
173-
return new ReactiveHandler(new LogStreamHandler('php://output'), $this->getEnv('X_LISTEN')); // @phpstan-ignore-line returns instanceof `T`
172+
} elseif ($class === HttpServerRunner::class) {
173+
return new HttpServerRunner(new LogStreamHandler('php://output'), $this->getEnv('X_LISTEN')); // @phpstan-ignore-line returns instanceof `T`
174174
}
175175
return new $class();
176176
}
@@ -179,16 +179,16 @@ public function getObject(string $class) /*: object (PHP 7.2+) */
179179
}
180180

181181
/**
182-
* [Internal] Get SAPI handler from container
182+
* [Internal] Get the app runner appropriate for this environment from container
183183
*
184-
* @return ReactiveHandler|SapiHandler
184+
* @return HttpServerRunner|SapiRunner
185185
* @throws \TypeError if container config or factory returns an unexpected type
186186
* @throws \Throwable if container factory function throws unexpected exception
187187
* @internal
188188
*/
189-
public function getSapi() /*: ReactiveHandler|SapiHandler (PHP 8.0+) */
189+
public function getRunner() /*: HttpServerRunner|SapiRunner (PHP 8.0+) */
190190
{
191-
return $this->getObject(\PHP_SAPI === 'cli' ? ReactiveHandler::class : SapiHandler::class);
191+
return $this->getObject(\PHP_SAPI === 'cli' ? HttpServerRunner::class : SapiRunner::class);
192192
}
193193

194194
/**
@@ -204,10 +204,10 @@ private function loadObject(string $name, int $depth = 64) /*: object (PHP 7.2+)
204204
{
205205
\assert(\is_array($this->container));
206206

207-
if ($name === ReactiveHandler::class && !\array_key_exists(ReactiveHandler::class, $this->container)) {
208-
// special case: create ReactiveHandler with X_LISTEN environment variable
209-
$this->container[ReactiveHandler::class] = static function (?string $X_LISTEN = null): ReactiveHandler {
210-
return new ReactiveHandler(new LogStreamHandler('php://output'), $X_LISTEN);
207+
if ($name === HttpServerRunner::class && !\array_key_exists(HttpServerRunner::class, $this->container)) {
208+
// special case: create HttpServerRunner with X_LISTEN environment variable
209+
$this->container[HttpServerRunner::class] = static function (?string $X_LISTEN = null): HttpServerRunner {
210+
return new HttpServerRunner(new LogStreamHandler('php://output'), $X_LISTEN);
211211
};
212212
}
213213

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
<?php
22

3-
namespace FrameworkX\Io;
3+
namespace FrameworkX\Runner;
44

5+
use FrameworkX\Io\FiberHandler;
6+
use FrameworkX\Io\LogStreamHandler;
57
use React\EventLoop\Loop;
68
use React\Http\HttpServer;
79
use React\Socket\SocketServer;
810

911
/**
10-
* [Internal] Powerful reactive request handler built on top of ReactPHP.
12+
* [Internal] Powerful reactive application runner built on top of ReactPHP.
1113
*
1214
* This is where the magic happens: The main `App` uses this class to run
1315
* ReactPHP's efficient HTTP server to handle incoming HTTP requests when
@@ -17,11 +19,11 @@
1719
* continue to run until it is interrupted by a signal.
1820
*
1921
* Note that this is an internal class only and nothing you should usually have
20-
* to care about. See also the `App` and `SapiHandler` for more details.
22+
* to care about. See also the `App` and `SapiRunner` for more details.
2123
*
2224
* @internal
2325
*/
24-
class ReactiveHandler
26+
class HttpServerRunner
2527
{
2628
/** @var LogStreamHandler */
2729
private $logger;
@@ -36,7 +38,11 @@ public function __construct(LogStreamHandler $logger, ?string $listenAddress)
3638
$this->listenAddress = $listenAddress ?? '127.0.0.1:8080';
3739
}
3840

39-
public function run(callable $handler): void
41+
/**
42+
* @param callable(\Psr\Http\Message\ServerRequestInterface):(\Psr\Http\Message\ResponseInterface|\React\Promise\PromiseInterface<\Psr\Http\Message\ResponseInterface>) $handler
43+
* @return void
44+
*/
45+
public function __invoke(callable $handler): void
4046
{
4147
$socket = new SocketServer($this->listenAddress);
4248

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php
22

3-
namespace FrameworkX\Io;
3+
namespace FrameworkX\Runner;
44

55
use Psr\Http\Message\ResponseInterface;
66
use Psr\Http\Message\ServerRequestInterface;
@@ -11,21 +11,25 @@
1111
use React\Stream\ReadableStreamInterface;
1212

1313
/**
14-
* [Internal] Request handler for traditional PHP SAPIs.
14+
* [Internal] Application runner for traditional PHP SAPIs.
1515
*
16-
* This request handler will be used when executed behind traditional PHP SAPIs
16+
* This application runner will be used when executed behind traditional PHP SAPIs
1717
* (PHP-FPM, FastCGI, Apache, etc.). It will handle a single request and run
1818
* until a single response is sent. This is particularly useful because it
19-
* allows you to run the exact same app in any environment.
19+
* allows you to run the exact same application code in any environment.
2020
*
2121
* Note that this is an internal class only and nothing you should usually have
22-
* to care about. See also the `App` and `ReactiveHandler` for more details.
22+
* to care about. See also the `App` and `HttpServerRunner` for more details.
2323
*
2424
* @internal
2525
*/
26-
class SapiHandler
26+
class SapiRunner
2727
{
28-
public function run(callable $handler): void
28+
/**
29+
* @param callable(ServerRequestInterface):(ResponseInterface|PromiseInterface<ResponseInterface>) $handler
30+
* @return void
31+
*/
32+
public function __invoke(callable $handler): void
2933
{
3034
$request = $this->requestFromGlobals();
3135

tests/AppTest.php

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
use FrameworkX\Container;
88
use FrameworkX\ErrorHandler;
99
use FrameworkX\Io\MiddlewareHandler;
10-
use FrameworkX\Io\ReactiveHandler;
1110
use FrameworkX\Io\RouteHandler;
11+
use FrameworkX\Runner\HttpServerRunner;
1212
use FrameworkX\Tests\Fixtures\InvalidAbstract;
1313
use FrameworkX\Tests\Fixtures\InvalidConstructorInt;
1414
use FrameworkX\Tests\Fixtures\InvalidConstructorIntersection;
@@ -92,26 +92,26 @@ public function testConstructWithContainerMockAssignsDefaultHandlersFromContaine
9292
$errorHandler = new ErrorHandler();
9393
$routeHandler = $this->createMock(RouteHandler::class);
9494

95-
$sapi = $this->createMock(ReactiveHandler::class);
95+
$runner = $this->createMock(HttpServerRunner::class);
9696

9797
$container = $this->createMock(Container::class);
9898
$container->expects($this->exactly(3))->method('getObject')->willReturnMap([
9999
[AccessLogHandler::class, $accessLogHandler],
100100
[ErrorHandler::class, $errorHandler],
101101
[RouteHandler::class, $routeHandler],
102102
]);
103-
$container->expects($this->once())->method('getSapi')->willReturn($sapi);
103+
$container->expects($this->once())->method('getRunner')->willReturn($runner);
104104
assert($container instanceof Container);
105105

106106
$app = new App($container);
107107

108-
$ref = new \ReflectionProperty($app, 'sapi');
108+
$ref = new \ReflectionProperty($app, 'runner');
109109
if (PHP_VERSION_ID < 80100) {
110110
$ref->setAccessible(true);
111111
}
112112
$ret = $ref->getValue($app);
113113

114-
$this->assertSame($sapi, $ret);
114+
$this->assertSame($runner, $ret);
115115

116116
$ref = new ReflectionProperty($app, 'handler');
117117
if (PHP_VERSION_ID < 80100) {
@@ -138,13 +138,13 @@ public function testConstructWithContainerInstanceAssignsDefaultHandlersAndConta
138138
$container = new Container([]);
139139
$app = new App($container);
140140

141-
$ref = new \ReflectionProperty($app, 'sapi');
141+
$ref = new \ReflectionProperty($app, 'runner');
142142
if (PHP_VERSION_ID < 80100) {
143143
$ref->setAccessible(true);
144144
}
145145
$ret = $ref->getValue($app);
146146

147-
$this->assertSame($container->getSapi(), $ret);
147+
$this->assertSame($container->getRunner(), $ret);
148148

149149
$ref = new ReflectionProperty($app, 'handler');
150150
if (PHP_VERSION_ID < 80100) {
@@ -893,39 +893,39 @@ public function testConstructWithRouteHandlerClassNameFollowedByMiddlewareThrows
893893
new App(RouteHandler::class, $middleware);
894894
}
895895

896-
public function testConstructWithContainerWithListenAddressWillPassListenAddressToReactiveHandler(): void
896+
public function testConstructWithContainerWithListenAddressWillPassListenAddressToHttpServerRunner(): void
897897
{
898898
$container = new Container([
899899
'X_LISTEN' => '0.0.0.0:8081'
900900
]);
901901

902902
$app = new App($container);
903903

904-
// $sapi = $app->sapi;
905-
$ref = new \ReflectionProperty($app, 'sapi');
904+
// $runner = $app->runner;
905+
$ref = new \ReflectionProperty($app, 'runner');
906906
if (PHP_VERSION_ID < 80100) {
907907
$ref->setAccessible(true);
908908
}
909-
$sapi = $ref->getValue($app);
910-
assert($sapi instanceof ReactiveHandler);
909+
$runner = $ref->getValue($app);
910+
assert($runner instanceof HttpServerRunner);
911911

912-
// $listenAddress = $sapi->listenAddress;
913-
$ref = new \ReflectionProperty($sapi, 'listenAddress');
912+
// $listenAddress = $runner->listenAddress;
913+
$ref = new \ReflectionProperty($runner, 'listenAddress');
914914
if (PHP_VERSION_ID < 80100) {
915915
$ref->setAccessible(true);
916916
}
917-
$listenAddress = $ref->getValue($sapi);
917+
$listenAddress = $ref->getValue($runner);
918918

919919
$this->assertEquals('0.0.0.0:8081', $listenAddress);
920920
}
921921

922-
public function testRunWillExecuteRunOnSapiHandlerFromContainer(): void
922+
public function testRunWillInvokeRunnerFromContainer(): void
923923
{
924-
$sapi = $this->createMock(ReactiveHandler::class);
925-
$sapi->expects($this->once())->method('run');
924+
$runner = $this->createMock(HttpServerRunner::class);
925+
$runner->expects($this->once())->method('__invoke');
926926

927927
$container = new Container([
928-
ReactiveHandler::class => $sapi
928+
HttpServerRunner::class => $runner
929929
]);
930930

931931
$app = new App($container);

0 commit comments

Comments
 (0)