Skip to content

Commit 24442d3

Browse files
committed
New separate Bridge facade.
- Bridge helps encapsulate Middleware to Pipe logic and provides fluent interface as well as type safety for arguments passed to pipeline. - Removed previous `PipelineBridge` class. - Updated readme.
1 parent e0ebf3b commit 24442d3

9 files changed

+110
-105
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@
99
!phpcs.xml.dist
1010
!phpstan.dist.neon
1111
!/Src
12+
!/Server
1213
!/Tests/

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ $ composer require thewebsolver/pipeline
2222

2323
> Use _`Pipeline::sealWith()`_ method to pass a closure to handle thrown exception.
2424

25-
- Provides [bridge][b] for PHP Projects that implements [PSR-7][7], [PSR-15][15] (optional [PSR-11][11]) standards.
25+
- Provides [bridge][b] for PHP Projects that implements [PSR-7][7] & [PSR-15][15] standards.
2626

2727
> Use [Queue based Request Handler][q] implementation to handle stacked middlewares inside [Request Handler][h]'s handle method (_`RequestHandlerInterface::handle()`_).
2828

@@ -33,7 +33,7 @@ For usage details, visit [Wiki page][w].
3333
[h]: https://www.php-fig.org/psr/psr-15/#21-psrhttpserverrequesthandlerinterface
3434
[q]: https://www.php-fig.org/psr/psr-15/meta/#queue-based-request-handler
3535
[w]: https://github.com/TheWebSolver/pipeline/wiki
36-
[b]: Src/PipelineBridge.php
36+
[b]: Server/Bridge.php
3737
[7]: https://www.php-fig.org/psr/psr-7/
3838
[15]: https://www.php-fig.org/psr/psr-15/
3939
[11]: https://www.php-fig.org/psr/psr-11/

Server/Bridge.php

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<?php // phpcs:disable Squiz.Commenting.FunctionComment.ParamNameNoMatch
2+
declare( strict_types = 1 );
3+
4+
namespace TheWebSolver\Codegarage\Pipeline\Server;
5+
6+
use Closure;
7+
use LogicException;
8+
use Psr\Container\ContainerInterface;
9+
use TheWebSolver\Codegarage\Lib\Pipe;
10+
use Psr\Http\Server\MiddlewareInterface;
11+
use TheWebSolver\Codegarage\Lib\Pipeline;
12+
use TheWebSolver\Codegarage\Lib\Psr\Middleware;
13+
use TheWebSolver\Codegarage\Lib\Error\InvalidPipe;
14+
use Psr\Http\Message\ResponseInterface as Response;
15+
use TheWebSolver\Codegarage\Lib\Psr\RequestHandler;
16+
use TheWebSolver\Codegarage\Lib\Error\InvalidPipeline;
17+
use Psr\Http\Message\ServerRequestInterface as Request;
18+
use Psr\Http\Server\RequestHandlerInterface as Handler;
19+
use TheWebSolver\Codegarage\Lib\Interfaces\PipeInterface;
20+
use TheWebSolver\Codegarage\Lib\Interfaces\ChainOfResponsibility;
21+
22+
class Bridge {
23+
/** @var PipeInterface[] */
24+
private array $pipes;
25+
private Request $request;
26+
private Response $response;
27+
28+
/** @param class-string<Handler> $requestHandlerClassName Accepts a Response instance via constructor. */
29+
// phpcs:ignore Squiz.Commenting.FunctionComment.IncorrectTypeHint
30+
public function __construct(
31+
private readonly ?ContainerInterface $container = null,
32+
private readonly ?ChainOfResponsibility $pipeline = null,
33+
private readonly string $requestHandlerClassName = RequestHandler::class
34+
) {}
35+
36+
public function for( Request $request, Response $response ): self {
37+
$this->request = $request;
38+
$this->response = $response;
39+
40+
return $this;
41+
}
42+
43+
/**
44+
* @param string|PipeInterface|(Closure(Response, Closure $next, Request, ?string $requestHandlerClassName): Response) $pipe
45+
* @param string|PipeInterface|(Closure(Response, Closure $next, Request, ?string $requestHandlerClassName): Response) ...$pipes
46+
*/
47+
public function through( string|Closure|PipeInterface $pipe, string|Closure|PipeInterface ...$pipes ): self {
48+
foreach ( array( $pipe, ...$pipes ) as $handler ) {
49+
$this->pipes[] = Pipe::create( $handler, $this->container );
50+
}
51+
52+
return $this;
53+
}
54+
55+
/**
56+
* @param string|MiddlewareInterface|(Closure(Request, Handler): Response) $middleware
57+
* @param string|MiddlewareInterface|(Closure(Request, Handler): Response) ...$middlewares
58+
*/
59+
public function throughMiddlewares(
60+
string|Closure|MiddlewareInterface $middleware,
61+
string|Closure|MiddlewareInterface ...$middlewares
62+
): self {
63+
foreach ( array( $middleware, ...$middlewares ) as $handler ) {
64+
$this->pipes[] = Middleware::toPipe( $handler, $this->container );
65+
}
66+
67+
return $this;
68+
}
69+
70+
/**
71+
* @throws InvalidPipe|InvalidPipeline When Pipe is invalid or other error occurs in the pipeline.
72+
* @throws LogicException When pipeline does not return a Response instance.
73+
*/
74+
// phpcs:ignore Squiz.Commenting.FunctionCommentThrowTag.WrongNumber -- Exact number is vague.
75+
public function get(): Response {
76+
$transformed = ( $this->pipeline ?? new Pipeline( $this->container ) )
77+
->use( $this->request, $this->requestHandlerClassName )
78+
->send( $this->response )
79+
->through( $this->pipes )
80+
->thenReturn();
81+
82+
// Transformed value is always a Response. Making static analysis happy
83+
// and enforcing maximum security of the application along the way.
84+
return $transformed instanceof Response
85+
? $transformed
86+
: throw new LogicException(
87+
'Response instance must be returned. Instead returns: ' . get_debug_type( $transformed )
88+
);
89+
}
90+
}

Src/Pipeline.php

-4
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,6 @@ final class Pipeline implements ChainOfResponsibility {
2121

2222
public function __construct( private readonly ?ContainerInterface $container = null ) {}
2323

24-
public static function withRequest( \Psr\Http\Message\ServerRequestInterface $request ): PipelineBridge {
25-
return ( new PipelineBridge() )->withRequest( $request );
26-
}
27-
2824
public static function normalizeException( Throwable $thrown, mixed $subject = null ): InvalidPipe|InvalidPipeline {
2925
return $thrown instanceof InvalidPipe ? $thrown : new InvalidPipeline( $thrown, $subject );
3026
}

Src/PipelineBridge.php

-85
This file was deleted.

Tests/BridgeTest.php

+10-7
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@
1414
use Psr\Http\Message\ServerRequestInterface;
1515
use Psr\Http\Server\RequestHandlerInterface;
1616
use Psr\Container\ContainerExceptionInterface;
17-
use TheWebSolver\Codegarage\Lib\PipelineBridge;
1817
use TheWebSolver\Codegarage\Lib\Psr\Middleware;
18+
use TheWebSolver\Codegarage\Pipeline\Server\Bridge;
1919
use TheWebSolver\Codegarage\Test\Stub\ResponseStub;
2020
use TheWebSolver\Codegarage\Test\Stub\MiddlewareStub;
2121
use TheWebSolver\Codegarage\Lib\Interfaces\PipeInterface;
@@ -92,7 +92,7 @@ public function testMiddlewareConversionWithoutContainer( mixed $middleware, ?st
9292

9393
/** @dataProvider provideMiddlewares */
9494
public function testMiddlewareToPipeConversion( mixed $middleware, ?string $thrown = null ): void {
95-
$this->assertInstanceOf( PipeInterface::class, PipelineBridge::middlewareToPipe( $middleware ) );
95+
$this->assertInstanceOf( PipeInterface::class, Middleware::toPipe( $middleware ) );
9696
}
9797

9898
/** @return array<mixed[]>*/
@@ -136,12 +136,12 @@ public function testPipelineBridgeWithPsr() {
136136
/** @var ServerRequestInterface */
137137
$request = $this->createStub( ServerRequestInterface::class );
138138
$response = ( new ResponseStub() )->withStatus( 100 );
139-
$pipes = array_map( PipelineBridge::middlewareToPipe( ... ), $this->getRequestHandlerMiddlewares() );
139+
$pipes = array_map( Middleware::toPipe( ... ), $this->getRequestHandlerMiddlewares() );
140140
$handler = new RequestHandlerStub( ( new Pipeline() )->use( $request )->send( $response )->through( $pipes ) );
141141

142142
$this->assertSame( expected: 500, actual: $handler->handle( $request )->getStatusCode() );
143143

144-
$handler = new RequestHandlerStub( Pipeline::withRequest( $request )->process( $response )->through( $pipes ) );
144+
$handler = new RequestHandlerStub( ( new Bridge() )->for( $request, $response )->through( ...$pipes ) );
145145

146146
$this->assertSame( expected: 500, actual: $handler->handle( $request )->getStatusCode() );
147147
}
@@ -154,8 +154,11 @@ public function __construct( private ResponseInterface $response ) {}
154154

155155
$this->expectException( LogicException::class );
156156

157-
( new PipelineBridge() )
158-
->middlewareToPipe( new MiddlewareStub() )
159-
->handle( $response, $this->fail( ... ), $this->createStub( ServerRequestInterface::class ), $handler::class );
157+
Middleware::toPipe( new MiddlewareStub() )->handle(
158+
$response,
159+
$this->fail( ... ),
160+
$this->createStub( ServerRequestInterface::class ),
161+
$handler::class
162+
);
160163
}
161164
}

Tests/Stub/RequestHandlerStub.php

+4-6
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,16 @@
44
namespace TheWebSolver\Codegarage\Test\Stub;
55

66
use Psr\Http\Message\ResponseInterface;
7+
use TheWebSolver\Codegarage\Lib\Pipeline;
78
use Psr\Http\Message\ServerRequestInterface;
89
use Psr\Http\Server\RequestHandlerInterface;
9-
use TheWebSolver\Codegarage\Lib\PipelineBridge;
10+
use TheWebSolver\Codegarage\Pipeline\Server\Bridge;
1011
use TheWebSolver\Codegarage\Lib\Interfaces\ChainOfResponsibility;
1112

1213
class RequestHandlerStub implements RequestHandlerInterface {
13-
public function __construct(
14-
private readonly ChainOfResponsibility|PipelineBridge $handler,
15-
private readonly PipelineBridge $bridge = new PipelineBridge()
16-
) {}
14+
public function __construct( private readonly ChainOfResponsibility|Bridge $handler ) {}
1715

1816
public function handle( ServerRequestInterface $request ): ResponseInterface {
19-
return $this->handler instanceof PipelineBridge ? $this->handler->getResponse() : $this->handler->thenReturn();
17+
return $this->handler instanceof Pipeline ? $this->handler->thenReturn() : $this->handler->get();
2018
}
2119
}

composer.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
},
2121
"autoload": {
2222
"psr-4": {
23-
"TheWebSolver\\Codegarage\\Lib\\": "Src/"
23+
"TheWebSolver\\Codegarage\\Lib\\": "Src/",
24+
"TheWebSolver\\Codegarage\\Pipeline\\Server\\": "Server/"
2425
}
2526
},
2627
"autoload-dev": {

phpstan.dist.neon

+1
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ parameters:
22
level: max
33
paths:
44
- Src
5+
- Server

0 commit comments

Comments
 (0)