Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit9da81f0

Browse files
committed
feat: add middleware to frankenPhp runner
1 parent0608052 commit9da81f0

File tree

8 files changed

+234
-5
lines changed

8 files changed

+234
-5
lines changed

‎src/Symfony/Component/Runtime/Runner/FrankenPhpWorkerRunner.php‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
useSymfony\Component\HttpFoundation\Request;
1515
useSymfony\Component\HttpKernel\HttpKernelInterface;
1616
useSymfony\Component\HttpKernel\TerminableInterface;
17+
useSymfony\Component\Runtime\Runner\Middleware\MiddlewareInterface;
1718
useSymfony\Component\Runtime\RunnerInterface;
1819

1920
/**
@@ -23,9 +24,15 @@
2324
*/
2425
class FrankenPhpWorkerRunnerimplements RunnerInterface
2526
{
27+
/**
28+
* @param HttpKernelInterface $kernel
29+
* @param int $loopMax
30+
* @param iterable<MiddlewareInterface> $middlewares
31+
*/
2632
publicfunction__construct(
2733
privateHttpKernelInterface$kernel,
2834
privateint$loopMax,
35+
privateiterable$middlewares = [],
2936
) {
3037
}
3138

@@ -52,6 +59,13 @@ public function run(): int
5259
$sfResponse->send();
5360
};
5461

62+
foreach ($this->middlewaresas$middleware) {
63+
if (!$middlewareinstanceof MiddlewareInterface) {
64+
thrownew \LogicException(\sprintf('The middleware "%s" must implement the "%s" interface.',\is_object($middleware) ?$middleware::class :\gettype($middleware), MiddlewareInterface::class));
65+
}
66+
$handler =fn () =>$middleware->wrap($handler,$server);
67+
}
68+
5569
$loops =0;
5670
do {
5771
$ret =frankenphp_handle_request($handler);
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the Symfony package.
7+
*
8+
* (c) Fabien Potencier <fabien@symfony.com>
9+
*
10+
* For the full copyright and license information, please view the LICENSE
11+
* file that was distributed with this source code.
12+
*/
13+
14+
namespaceSymfony\Component\Runtime\Runner\Middleware;
15+
16+
/**
17+
* @author Sascha Heilmeier<sascha.heilmeier@netlogix.de>
18+
*/
19+
readonlyclass MiddlewareFactory
20+
{
21+
/**
22+
* @param class-string<MiddlewareInterface> ...$middleware
23+
* @return \Generator<MiddlewareInterface>
24+
*/
25+
publicfunctioncreate(string ...$middleware):\Generator
26+
{
27+
foreach ($middlewareas$middlewareClass) {
28+
yieldnew$middlewareClass();
29+
}
30+
}
31+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the Symfony package.
7+
*
8+
* (c) Fabien Potencier <fabien@symfony.com>
9+
*
10+
* For the full copyright and license information, please view the LICENSE
11+
* file that was distributed with this source code.
12+
*/
13+
14+
namespaceSymfony\Component\Runtime\Runner\Middleware;
15+
16+
/**
17+
* @author Sascha Heilmeier<sascha.heilmeier@netlogix.de>
18+
*/
19+
interface MiddlewareInterface
20+
{
21+
publicfunctionwrap(callable$handler,array$server):void;
22+
}

‎src/Symfony/Component/Runtime/SymfonyRuntime.php‎

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
useSymfony\Component\Runtime\Internal\MissingDotenv;
2525
useSymfony\Component\Runtime\Internal\SymfonyErrorHandler;
2626
useSymfony\Component\Runtime\Runner\FrankenPhpWorkerRunner;
27+
useSymfony\Component\Runtime\Runner\Middleware\MiddlewareFactory;
28+
useSymfony\Component\Runtime\Runner\Middleware\MiddlewareInterface;
2729
useSymfony\Component\Runtime\Runner\Symfony\ConsoleApplicationRunner;
2830
useSymfony\Component\Runtime\Runner\Symfony\HttpKernelRunner;
2931
useSymfony\Component\Runtime\Runner\Symfony\ResponseRunner;
@@ -91,6 +93,7 @@ class SymfonyRuntime extends GenericRuntime
9193
* dotenv_overload?: ?bool,
9294
* dotenv_extra_paths?: ?string[],
9395
* worker_loop_max?: int, // Use 0 or a negative integer to never restart the worker. Default: 500
96+
* worker_middlewares?: string
9497
* } $options
9598
*/
9699
publicfunction__construct(array$options = [])
@@ -153,14 +156,31 @@ public function __construct(array $options = [])
153156

154157
$options['worker_loop_max'] = (int) ($workerLoopMax ??500);
155158

159+
$workerMiddlewares = ($options['worker_middlewares'] ??$_SERVER['FRANKENPHP_MIDDLEWARES'] ??$_ENV['FRANKENPHP_MIDDLEWARES'] ??'');
160+
161+
if (!\is_string($workerMiddlewares)) {
162+
thrownew \LogicException(\sprintf('The "worker_middlewares" runtime option must be an string, "%s" given.',get_debug_type($workerLoopMax)));
163+
}
164+
165+
$workerMiddlewares =array_filter(explode("\n",$workerMiddlewares));
166+
167+
foreach ($workerMiddlewaresas$workerMiddleware) {
168+
if (!is_a($workerMiddleware, MiddlewareInterface::class,true)) {
169+
thrownew \LogicException(\sprintf('The middleware class "%s" must implement "%s".',$workerMiddleware, MiddlewareInterface::class));
170+
}
171+
}
172+
173+
$options['worker_middlewares'] =$workerMiddlewares;
174+
156175
parent::__construct($options);
157176
}
158177

159178
publicfunctiongetRunner(?object$application):RunnerInterface
160179
{
161180
if ($applicationinstanceof HttpKernelInterface) {
162181
if ($_SERVER['FRANKENPHP_WORKER'] ??false) {
163-
returnnewFrankenPhpWorkerRunner($application,$this->options['worker_loop_max']);
182+
$middlewareFactory =newMiddlewareFactory();
183+
returnnewFrankenPhpWorkerRunner($application,$this->options['worker_loop_max'],$middlewareFactory->create(...$this->options['worker_middlewares']));
164184
}
165185

166186
returnnewHttpKernelRunner($application, Request::createFromGlobals(),$this->options['debug'] ??false);

‎src/Symfony/Component/Runtime/Tests/FrankenPhpWorkerRunnerTest.php‎

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,35 @@
1313

1414
require_once__DIR__.'/frankenphp-function-mock.php';
1515

16+
usePHPUnit\Framework\Attributes\DataProvider;
1617
usePHPUnit\Framework\TestCase;
1718
useSymfony\Component\HttpFoundation\Request;
1819
useSymfony\Component\HttpFoundation\Response;
1920
useSymfony\Component\HttpKernel\HttpKernelInterface;
2021
useSymfony\Component\HttpKernel\TerminableInterface;
2122
useSymfony\Component\Runtime\Runner\FrankenPhpWorkerRunner;
23+
useSymfony\Component\Runtime\Runner\Middleware\MiddlewareInterface;
2224

2325
interface TestAppInterfaceextends HttpKernelInterface, TerminableInterface
2426
{
2527
}
2628

2729
class FrankenPhpWorkerRunnerTestextends TestCase
2830
{
29-
publicfunctiontestRun()
31+
publicstaticfunctionrunData():iterable
3032
{
33+
yield'default' => [];
34+
35+
yield'middleware' => [
36+
'withMiddleware' =>true,
37+
];
38+
}
39+
40+
/**
41+
* @param class-string<MiddlewareInterface>|null $middleware
42+
*/
43+
#[DataProvider('runData')]
44+
publicfunctiontestRun(bool$withMiddleware =false) {
3145
$application =$this->createMock(TestAppInterface::class);
3246
$application
3347
->expects($this->once())
@@ -41,7 +55,30 @@ public function testRun()
4155

4256
$_SERVER['FOO'] ='bar';
4357

44-
$runner =newFrankenPhpWorkerRunner($application,500);
58+
if ($withMiddleware) {
59+
$middlewareMock =$this->createMock(MiddlewareInterface::class);
60+
$middlewareMock
61+
->expects($this->once())
62+
->method('wrap')->willReturnCallback(fn ($handler) =>$handler());
63+
}
64+
65+
$runner =newFrankenPhpWorkerRunner($application,500,array_filter([$middlewareMock ??null]));
66+
4567
$this->assertSame(0,$runner->run());
4668
}
69+
70+
publicfunctiontestRunInvalidMiddleware()
71+
{
72+
$this->expectException(\LogicException::class);
73+
$this->expectExceptionMessage(
74+
\sprintf(
75+
'The middleware "%s" must implement the "%s" interface',
76+
\stdClass::class,
77+
MiddlewareInterface::class
78+
)
79+
);
80+
$application =$this->createMock(TestAppInterface::class);
81+
$runner =newFrankenPhpWorkerRunner($application,500, [new \stdClass]);
82+
$runner->run();
83+
}
4784
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the Symfony package.
7+
*
8+
* (c) Fabien Potencier <fabien@symfony.com>
9+
*
10+
* For the full copyright and license information, please view the LICENSE
11+
* file that was distributed with this source code.
12+
*/
13+
14+
namespaceSymfony\Component\Runtime\Tests\Support;
15+
16+
class InvalidMiddleware
17+
{
18+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the Symfony package.
7+
*
8+
* (c) Fabien Potencier <fabien@symfony.com>
9+
*
10+
* For the full copyright and license information, please view the LICENSE
11+
* file that was distributed with this source code.
12+
*/
13+
14+
namespaceSymfony\Component\Runtime\Tests\Support;
15+
16+
useSymfony\Component\Runtime\Runner\Middleware\MiddlewareInterface;
17+
18+
class TestMiddlewareimplements MiddlewareInterface
19+
{
20+
publicfunctionwrap(callable$handler,array$server):void
21+
{
22+
$handler();
23+
}
24+
}

‎src/Symfony/Component/Runtime/Tests/SymfonyRuntimeTest.php‎

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,14 @@
1111

1212
namespaceSymfony\Component\Runtime\Tests;
1313

14+
usePHPUnit\Framework\Attributes\DataProvider;
1415
usePHPUnit\Framework\TestCase;
1516
useSymfony\Component\HttpKernel\HttpKernelInterface;
1617
useSymfony\Component\Runtime\Runner\FrankenPhpWorkerRunner;
18+
useSymfony\Component\Runtime\Runner\Middleware\MiddlewareInterface;
1719
useSymfony\Component\Runtime\SymfonyRuntime;
20+
useSymfony\Component\Runtime\Tests\Support\InvalidMiddleware;
21+
useSymfony\Component\Runtime\Tests\Support\TestMiddleware;
1822

1923
class SymfonyRuntimeTestextends TestCase
2024
{
@@ -35,19 +39,78 @@ public function testGetRunner()
3539
}
3640
}
3741

38-
publicfunctiontestStringWorkerMaxLoopThrows()
42+
publicfunctiontestGetRunnerWithMiddleware()
43+
{
44+
$application =$this->createStub(HttpKernelInterface::class);
45+
46+
$_SERVER['FRANKENPHP_MIDDLEWARES'] = TestMiddleware::class;
47+
$runtime =newSymfonyRuntime();
48+
49+
try {
50+
$_SERVER['FRANKENPHP_WORKER'] =1;
51+
$runner =$runtime->getRunner($application);
52+
$this->assertInstanceOf(FrankenPhpWorkerRunner::class,$runner);
53+
54+
$middlewaresProperty =new \ReflectionProperty($runner,'middlewares');
55+
$middlewares =iterator_to_array($middlewaresProperty->getValue($runner));
56+
$this->assertCount(1,$middlewares);
57+
$this->assertInstanceOf(TestMiddleware::class,$middlewares[0]);
58+
}finally {
59+
restore_error_handler();
60+
restore_exception_handler();
61+
}
62+
}
63+
64+
publicfunction_testStringWorkerMaxLoopThrows()
3965
{
4066
$this->expectException(\LogicException::class);
4167
$this->expectExceptionMessage('The "worker_loop_max" runtime option must be an integer, "string" given.');
4268

4369
newSymfonyRuntime(['worker_loop_max' =>'foo']);
4470
}
4571

46-
publicfunctiontestBoolWorkerMaxLoopThrows()
72+
publicfunction_testBoolWorkerMaxLoopThrows()
4773
{
4874
$this->expectException(\LogicException::class);
4975
$this->expectExceptionMessage('The "worker_loop_max" runtime option must be an integer, "bool" given.');
5076

5177
newSymfonyRuntime(['worker_loop_max' =>false]);
5278
}
79+
80+
publicstaticfunctionworkerMiddlewaresOptionData():iterable
81+
{
82+
yield'valid middleware' => [
83+
'value' => TestMiddleware::class,
84+
'expectedWorkerMiddlewares' => [TestMiddleware::class],
85+
];
86+
87+
yield'invalid middleware' => [
88+
'value' => InvalidMiddleware::class,
89+
'expectedMessage' =>\sprintf(
90+
'The middleware class "%s" must implement "%s"',
91+
InvalidMiddleware::class,
92+
MiddlewareInterface::class
93+
),
94+
];
95+
}
96+
97+
#[DataProvider('workerMiddlewaresOptionData')]
98+
publicfunction_testWorkerMiddlewaresOption(
99+
mixed$value,
100+
?array$expectedWorkerMiddlewares =null,
101+
?string$expectedMessage =null,
102+
) {
103+
if (null !==$expectedMessage) {
104+
$this->expectException(\LogicException::class);
105+
$this->expectExceptionMessage($expectedMessage);
106+
}
107+
108+
$runtime =newSymfonyRuntime(['worker_middlewares' =>$value,'error_handler' =>false]);
109+
110+
if (null !==$expectedWorkerMiddlewares) {
111+
$optionsReflection =new \ReflectionProperty($runtime,'options');
112+
$workerMiddlewares =$optionsReflection->getValue($runtime)['worker_middlewares'] ?? [];
113+
$this->assertEquals($expectedWorkerMiddlewares,$workerMiddlewares);
114+
}
115+
}
53116
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp