Skip to content

Commit 8964184

Browse files
committed
feat: add middleware to FrankenPhpSymfony
1 parent f00cf6c commit 8964184

File tree

7 files changed

+140
-11
lines changed

7 files changed

+140
-11
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace Runtime\FrankenPhpSymfony\Exception;
4+
5+
use Throwable;
6+
7+
class InvalidMiddlewareException extends \Exception
8+
{
9+
function __construct(
10+
public string $className,
11+
int $code = 0,
12+
?Throwable $previous = null
13+
) {
14+
parent::__construct(
15+
"The middleware class '$className' is invalid.",
16+
$code,
17+
$previous
18+
);
19+
}
20+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Runtime\FrankenPhpSymfony\Middleware;
6+
7+
interface MiddlewareInterface
8+
{
9+
function wrap(callable $handler, array $server): void;
10+
}

src/frankenphp-symfony/src/Runner.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
namespace Runtime\FrankenPhpSymfony;
66

7+
use Runtime\FrankenPhpSymfony\Exception\InvalidMiddlewareException;
8+
use Runtime\FrankenPhpSymfony\Middleware\MiddlewareInterface;
79
use Symfony\Component\HttpFoundation\Request;
810
use Symfony\Component\HttpKernel\HttpKernelInterface;
911
use Symfony\Component\HttpKernel\TerminableInterface;
@@ -19,9 +21,13 @@ class Runner implements RunnerInterface
1921
public function __construct(
2022
private HttpKernelInterface $kernel,
2123
private int $loopMax,
24+
private array $middlewares = []
2225
) {
2326
}
2427

28+
/**
29+
* @throws InvalidMiddlewareException
30+
*/
2531
public function run(): int
2632
{
2733
// Prevent worker script termination when a client connection is interrupted
@@ -47,6 +53,15 @@ public function run(): int
4753
$sfResponse->send();
4854
};
4955

56+
foreach ($this->middlewares as $middlewareClass) {
57+
if (!is_a($middlewareClass, MiddlewareInterface::class, true)) {
58+
throw new InvalidMiddlewareException($middlewareClass, 1761117929733);
59+
}
60+
61+
$middleware = new $middlewareClass();
62+
$handler = fn () => $middleware->wrap($handler, $server);
63+
}
64+
5065
$loops = 0;
5166
do {
5267
$ret = \frankenphp_handle_request($handler);

src/frankenphp-symfony/src/Runtime.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ class Runtime extends SymfonyRuntime
2323
public function __construct(array $options = [])
2424
{
2525
$options['frankenphp_loop_max'] = (int) ($options['frankenphp_loop_max'] ?? $_SERVER['FRANKENPHP_LOOP_MAX'] ?? $_ENV['FRANKENPHP_LOOP_MAX'] ?? 500);
26+
$options['frankenphp_middlewares'] = (string) ($options['frankenphp_middlewares'] ?? $_SERVER['FRANKENPHP_MIDDLEWARES'] ?? $_ENV['FRANKENPHP_MIDDLEWARES'] ?? '');
27+
$options['frankenphp_middlewares'] = array_filter(explode("\n", $options['frankenphp_middlewares']));
2628

2729
parent::__construct($options);
2830
}

src/frankenphp-symfony/tests/RunnerTest.php

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44

55
namespace Runtime\FrankenPhpSymfony\Tests;
66

7-
require_once __DIR__.'/function-mock.php';
7+
require_once __DIR__ . '/function-mock.php';
88

99
use PHPUnit\Framework\TestCase;
10+
use Runtime\FrankenPhpSymfony\Exception\InvalidMiddlewareException;
1011
use Runtime\FrankenPhpSymfony\Runner;
12+
use Runtime\FrankenPhpSymfony\Tests\Support\InvalidMiddleware;
13+
use Runtime\FrankenPhpSymfony\Tests\Support\TestMiddleware;
1114
use Symfony\Component\HttpFoundation\Request;
1215
use Symfony\Component\HttpFoundation\Response;
1316
use Symfony\Component\HttpKernel\HttpKernelInterface;
@@ -22,22 +25,65 @@ interface TestAppInterface extends HttpKernelInterface, TerminableInterface
2225
*/
2326
class RunnerTest extends TestCase
2427
{
25-
public function testRun(): void
28+
29+
static function runData(): iterable
2630
{
31+
yield 'basic' => [];
32+
yield 'middleware' => [
33+
'middleware' => TestMiddleware::class
34+
];
35+
yield 'Invalid middleware' => [
36+
'middleware' => InvalidMiddleware::class,
37+
'expectException' => InvalidMiddlewareException::class
38+
];
39+
}
40+
41+
/**
42+
* @dataProvider runData
43+
*/
44+
public function testRun(
45+
?string $middleware = null,
46+
?string $expectException = null
47+
): void {
48+
if ($expectException !== null) {
49+
$this->expectException($expectException);
50+
}
51+
2752
$application = $this->createMock(TestAppInterface::class);
28-
$application
29-
->expects($this->once())
30-
->method('handle')
31-
->willReturnCallback(function (Request $request, int $type = HttpKernelInterface::MAIN_REQUEST, bool $catch = true): Response {
32-
$this->assertSame('bar', $request->server->get('FOO'));
3353

34-
return new Response();
35-
});
36-
$application->expects($this->once())->method('terminate');
54+
if ($expectException === null) {
55+
$application
56+
->expects($this->once())
57+
->method('handle')
58+
->willReturnCallback(
59+
function (
60+
Request $request,
61+
int $type = HttpKernelInterface::MAIN_REQUEST,
62+
bool $catch = true
63+
): Response {
64+
$this->assertSame('bar', $request->server->get('FOO'));
65+
66+
return new Response();
67+
}
68+
);
69+
$application->expects($this->once())->method('terminate');
70+
}
3771

3872
$_SERVER['FOO'] = 'bar';
3973

40-
$runner = new Runner($application, 500);
74+
$runner = new Runner($application, 500, array_filter([
75+
$middleware
76+
]));
77+
78+
$assertMiddlewareInvoked = $expectException === null && $middleware && method_exists($middleware, 'isInvoked');
79+
if ($assertMiddlewareInvoked) {
80+
$this->assertFalse($middleware::isInvoked());
81+
}
82+
4183
$this->assertSame(0, $runner->run());
84+
85+
if ($assertMiddlewareInvoked) {
86+
$this->assertTrue($middleware::isInvoked());
87+
}
4288
}
4389
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace Runtime\FrankenPhpSymfony\Tests\Support;
4+
5+
class InvalidMiddleware
6+
{
7+
8+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Runtime\FrankenPhpSymfony\Tests\Support;
6+
7+
use Runtime\FrankenPhpSymfony\Middleware\MiddlewareInterface;
8+
9+
class TestMiddleware implements MiddlewareInterface
10+
{
11+
function __construct()
12+
{
13+
self::$invoked = false;
14+
}
15+
16+
private static bool $invoked = false;
17+
18+
public function wrap(callable $handler, array $server): void
19+
{
20+
self::$invoked = true;
21+
$handler();
22+
}
23+
24+
public static function isInvoked(): bool
25+
{
26+
return self::$invoked;
27+
}
28+
}

0 commit comments

Comments
 (0)