Skip to content

Commit 76372ae

Browse files
authored
allow replacement (#53)
* Allow the add mode of middleware to be specified * Make the check more explicit * Set permenant add modes * - add append and prepend helpers * Added remove and replace functions to allow for modifications after setting up existing middleware without causing exceptions * Added handler testing for middleware * better append tests * fix indexing issue and add some regression tests
1 parent cac0fed commit 76372ae

File tree

6 files changed

+225
-2
lines changed

6 files changed

+225
-2
lines changed

src/Middleware/MiddlewareHandler.php

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@ public function append(MiddlewareInterface $middleware): self
3030
return $this->add($middleware, self::APPEND);
3131
}
3232

33-
public function add(MiddlewareInterface $middleware, ?int $addMode = null)
33+
public function add(MiddlewareInterface $middleware, ?int $addMode = null): self
3434
{
3535
if ($addMode === self::PREPEND)
3636
{
37-
$this->_middlewares = [$middleware] + $this->_middlewares;
37+
array_unshift($this->_middlewares, $middleware);
3838
}
3939
else
4040
{
@@ -44,6 +44,35 @@ public function add(MiddlewareInterface $middleware, ?int $addMode = null)
4444
return $this;
4545
}
4646

47+
public function remove(MiddlewareInterface|string $remove): self
48+
{
49+
foreach ($this->_middlewares as $key => $middleware)
50+
{
51+
if ($middleware instanceof $remove || $middleware::class === $remove)
52+
{
53+
unset($this->_middlewares[$key]);
54+
break;
55+
}
56+
}
57+
58+
$this->_middlewares = array_values($this->_middlewares);
59+
return $this;
60+
}
61+
62+
public function replace(MiddlewareInterface|string $replace, MiddlewareInterface $with): self
63+
{
64+
foreach ($this->_middlewares as $key => $middleware)
65+
{
66+
if ($middleware instanceof $replace || $middleware::class === $replace)
67+
{
68+
$this->_middlewares[$key] = $with;
69+
break;
70+
}
71+
}
72+
73+
return $this;
74+
}
75+
4776
public function handle(Context $c): Response
4877
{
4978
$handler = $this->_handler;
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
<?php
2+
3+
namespace Cubex\Tests\Middleware;
4+
5+
use Cubex\Middleware\MiddlewareHandler;
6+
use Cubex\Tests\Supporting\Middleware\MiddlewareHandlerTester;
7+
use Cubex\Tests\Supporting\Middleware\SecondTestMiddleware;
8+
use Cubex\Tests\Supporting\Middleware\TestFailedMiddleware;
9+
use Cubex\Tests\Supporting\Middleware\TestMiddleware;
10+
use Packaged\Context\Context;
11+
use Packaged\Http\Request;
12+
use Packaged\Routing\Handler\FuncHandler;
13+
use PHPUnit\Framework\TestCase;
14+
use Symfony\Component\HttpFoundation\RedirectResponse;
15+
16+
class MiddlewareHandlerTest extends TestCase
17+
{
18+
19+
public function testSuccess()
20+
{
21+
$handler = new MiddlewareHandler(new FuncHandler(fn ($c) => new RedirectResponse('/success')));
22+
$handler->add(new TestMiddleware());
23+
24+
$resp = $handler->handle(new Context(Request::create('/testing')));
25+
self::assertInstanceOf(RedirectResponse::class, $resp);
26+
self::assertEquals('/success', $resp->getTargetUrl());
27+
}
28+
29+
public function testFailed()
30+
{
31+
$handler = new MiddlewareHandler(new FuncHandler(fn ($c) => new RedirectResponse('/success')));
32+
$handler->add(new TestFailedMiddleware());
33+
34+
$resp = $handler->handle(new Context(Request::create('/testing')));
35+
self::assertInstanceOf(RedirectResponse::class, $resp);
36+
self::assertEquals('/failed', $resp->getTargetUrl());
37+
}
38+
39+
public function testPrepend()
40+
{
41+
$handler = new MiddlewareHandler(new FuncHandler(fn ($c) => new RedirectResponse('/success')));
42+
$handler->add(new TestMiddleware());
43+
$tester = MiddlewareHandlerTester::with($handler);
44+
self::assertCount(1, $tester->getMiddlewares());
45+
self::assertInstanceOf(TestMiddleware::class, $tester->getMiddlewares()[0]);
46+
47+
$handler->prepend(new SecondTestMiddleware());
48+
self::assertCount(2, $tester->getMiddlewares());
49+
self::assertInstanceOf(SecondTestMiddleware::class, $tester->getMiddlewares()[0]);
50+
self::assertInstanceOf(TestMiddleware::class, $tester->getMiddlewares()[1]);
51+
}
52+
53+
public function testAdd()
54+
{
55+
$handler = new MiddlewareHandler(new FuncHandler(fn ($c) => new RedirectResponse('/success')));
56+
$handler->add(new TestMiddleware());
57+
$tester = MiddlewareHandlerTester::with($handler);
58+
self::assertCount(1, $tester->getMiddlewares());
59+
self::assertInstanceOf(TestMiddleware::class, $tester->getMiddlewares()[0]);
60+
61+
$handler->add(new SecondTestMiddleware());
62+
self::assertCount(2, $tester->getMiddlewares());
63+
self::assertInstanceOf(TestMiddleware::class, $tester->getMiddlewares()[0]);
64+
self::assertInstanceOf(SecondTestMiddleware::class, $tester->getMiddlewares()[1]);
65+
}
66+
67+
public function testAppend()
68+
{
69+
$handler = new MiddlewareHandler(new FuncHandler(fn ($c) => new RedirectResponse('/success')));
70+
$handler->append(new TestMiddleware());
71+
$tester = MiddlewareHandlerTester::with($handler);
72+
self::assertCount(1, $tester->getMiddlewares());
73+
self::assertInstanceOf(TestMiddleware::class, $tester->getMiddlewares()[0]);
74+
75+
$handler->append(new SecondTestMiddleware());
76+
self::assertCount(2, $tester->getMiddlewares());
77+
self::assertInstanceOf(TestMiddleware::class, $tester->getMiddlewares()[0]);
78+
self::assertInstanceOf(SecondTestMiddleware::class, $tester->getMiddlewares()[1]);
79+
}
80+
81+
public function testReplace()
82+
{
83+
$handler = new MiddlewareHandler(new FuncHandler(fn ($c) => new RedirectResponse('/success')));
84+
$handler->add(new TestMiddleware());
85+
$tester = MiddlewareHandlerTester::with($handler);
86+
self::assertCount(1, $tester->getMiddlewares());
87+
self::assertInstanceOf(TestMiddleware::class, $tester->getMiddlewares()[0]);
88+
89+
$handler->replace(TestMiddleware::class, new SecondTestMiddleware());
90+
self::assertCount(1, $tester->getMiddlewares());
91+
self::assertInstanceOf(SecondTestMiddleware::class, $tester->getMiddlewares()[0]);
92+
}
93+
94+
public function testRemove()
95+
{
96+
$handler = new MiddlewareHandler(new FuncHandler(fn ($c) => new RedirectResponse('/success')));
97+
$handler->add(new TestMiddleware());
98+
$tester = MiddlewareHandlerTester::with($handler);
99+
self::assertCount(1, $tester->getMiddlewares());
100+
self::assertInstanceOf(TestMiddleware::class, $tester->getMiddlewares()[0]);
101+
102+
$handler->remove(TestMiddleware::class);
103+
self::assertCount(0, $tester->getMiddlewares());
104+
}
105+
106+
public function testRemoveAndAdditionIndexesCorrectly()
107+
{
108+
$handler = new MiddlewareHandler(new FuncHandler(fn ($c) => new RedirectResponse('/success')));
109+
$handler->add(new TestMiddleware());
110+
$tester = MiddlewareHandlerTester::with($handler);
111+
self::assertCount(1, $tester->getMiddlewares());
112+
self::assertInstanceOf(TestMiddleware::class, $tester->getMiddlewares()[0]);
113+
114+
$handler->remove(TestMiddleware::class);
115+
self::assertCount(0, $tester->getMiddlewares());
116+
117+
$handler->add(new TestMiddleware());
118+
self::assertCount(1, $tester->getMiddlewares());
119+
self::assertInstanceOf(TestMiddleware::class, $tester->getMiddlewares()[0]);
120+
121+
$handler->prepend(new SecondTestMiddleware());
122+
self::assertCount(2, $tester->getMiddlewares());
123+
self::assertInstanceOf(SecondTestMiddleware::class, $tester->getMiddlewares()[0]);
124+
}
125+
126+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?php
2+
3+
namespace Cubex\Tests\Supporting\Middleware;
4+
5+
use Cubex\Middleware\MiddlewareHandler;
6+
7+
class MiddlewareHandlerTester extends MiddlewareHandler
8+
{
9+
protected MiddlewareHandler $handler;
10+
11+
public static function with(MiddlewareHandler $handler): self
12+
{
13+
$h = new self($handler);
14+
$h->handler = $handler;
15+
return $h;
16+
}
17+
18+
public function getMiddlewares(): array
19+
{
20+
return $this->handler->_middlewares;
21+
}
22+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
namespace Cubex\Tests\Supporting\Middleware;
4+
5+
use Cubex\Middleware\Middleware;
6+
use Packaged\Context\Context;
7+
use Symfony\Component\HttpFoundation\Response;
8+
9+
class SecondTestMiddleware extends Middleware
10+
{
11+
public function handle(Context $c): Response
12+
{
13+
return $this->next($c);
14+
}
15+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
namespace Cubex\Tests\Supporting\Middleware;
4+
5+
use Cubex\Middleware\Middleware;
6+
use Packaged\Context\Context;
7+
use Symfony\Component\HttpFoundation\RedirectResponse;
8+
use Symfony\Component\HttpFoundation\Response;
9+
10+
class TestFailedMiddleware extends Middleware
11+
{
12+
public function handle(Context $c): Response
13+
{
14+
return new RedirectResponse('/failed');
15+
}
16+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
namespace Cubex\Tests\Supporting\Middleware;
4+
5+
use Cubex\Middleware\Middleware;
6+
use Packaged\Context\Context;
7+
use Symfony\Component\HttpFoundation\Response;
8+
9+
class TestMiddleware extends Middleware
10+
{
11+
public function handle(Context $c): Response
12+
{
13+
return $this->next($c);
14+
}
15+
}

0 commit comments

Comments
 (0)