Skip to content

Commit d81c13a

Browse files
committed
NEW: support for external middleware adapter & container.
1 parent c5da824 commit d81c13a

File tree

2 files changed

+72
-35
lines changed

2 files changed

+72
-35
lines changed

Src/Pipeline.php

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ final public static function resolve( string|Closure|Pipe $pipe ): Closure {
4343

4444
return match ( true ) {
4545
default => throw InvalidPipeError::from( $pipe ),
46-
$isClassName => self::make( $pipe )->handle( ... ),
46+
$isClassName => PipelineBridge::make( $pipe )->handle( ... ),
4747
$pipe instanceof Pipe => $pipe->handle( ... ),
4848
$pipe instanceof Closure => $pipe,
4949
};
@@ -172,10 +172,4 @@ public function thenReturn() {
172172
protected function chain( Closure $next, string|Closure|Pipe $current ): Closure {
173173
return fn ( $subject ) => self::resolve( $current )( $subject, $next, ...( $this->use ?? array() ) );
174174
}
175-
176-
private static function make( string $pipe ): Pipe {
177-
return function_exists( '\\TheWebSolver\\Codegarage\\app' )
178-
? \TheWebSolver\Codegarage\app()->make( $pipe )
179-
: new $pipe();
180-
}
181175
}

Src/PipelineBridge.php

Lines changed: 71 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -22,33 +22,42 @@
2222
class PipelineBridge {
2323
public const MIDDLEWARE_RESPONSE = 'middlewareResponse';
2424

25+
/** @phpstan-param class-string */
26+
private static string $middlewareInterface;
27+
/** @phpstan-param class-string */
28+
private static string $middlewareClass;
29+
/** @var \Psr\Container\ContainerInterface */
30+
private static object $container;
31+
2532
/**
2633
* @param string|Pipe|Closure(mixed $subject, Closure $next, mixed ...$use): mixed $from
2734
* @throws InvalidPipeError When invalid pipe given.
2835
*/
2936
public static function toPipe( string|Closure|Pipe $from ): Pipe {
30-
return new class( $from ) implements Pipe {
31-
public function __construct( private readonly string|Closure|Pipe $pipe ) {}
37+
$pipe = Pipeline::resolve( pipe: $from );
38+
39+
return new class( $pipe ) implements Pipe {
40+
public function __construct( private readonly Closure $pipe ) {}
3241

3342
/**
3443
* @param mixed $subject
3544
* @param Closure(mixed $subject, mixed ...$use): mixed $next
3645
*/
3746
public function handle( mixed $subject, Closure $next, mixed ...$use ): mixed {
38-
return $next( Pipeline::resolve( $this->pipe )( $subject, $next, ...$use ) );
47+
return $next( ( $this->pipe )( $subject, $next, ...$use ) );
3948
}
4049
};
4150
}
4251

4352
/**
44-
* @param string|Closure|Middleware $middleware
45-
* @return Middleware
46-
* @throws LogicException When invoked on projects that doesn't implement PSR7 & PSR15
53+
* @throws LogicException When invoked on projects that doesn't implement PSR7 & PSR15.
4754
* @throws TypeError When middleware creation fails due to invalid classname.
4855
* @throws Throwable When unknown error occurs.
4956
*/
50-
public static function toMiddleware( $middleware ) {
51-
$interface = '\\Psr\\Http\\Server\\MiddlewareInterface';
57+
public static function toMiddleware( mixed $middleware ): object {
58+
$interface = static::hasMiddlewareInterfaceAdapter()
59+
? static::$middlewareInterface
60+
: '\\Psr\\Http\\Server\\MiddlewareInterface';
5261

5362
if ( ! interface_exists( $interface ) ) {
5463
throw new LogicException(
@@ -62,10 +71,10 @@ public static function toMiddleware( $middleware ) {
6271
try {
6372
$middleware = ( match ( true ) {
6473
// Middleware classname is a non-existing classname, then default to null.
65-
default => null,
66-
$middleware instanceof Closure => $middleware,
67-
$isClassName => ( new $middleware() )->process( ... ),
68-
$middleware instanceof Middleware => $middleware->process( ... ),
74+
default => null,
75+
$middleware instanceof Closure => $middleware,
76+
$isClassName => static::make( $middleware )->process( ... ),
77+
is_a( $middleware, $interface ) => $middleware->process( ... ),
6978
} );
7079

7180
if ( null === $middleware ) {
@@ -74,18 +83,12 @@ public static function toMiddleware( $middleware ) {
7483
'Non-existing class "%1$s". Middleware must be a Closure, an instance of %2$s'
7584
. ' or classname of a class that implements %2$s.',
7685
$provided,
77-
$interface
86+
static::$middlewareInterface
7887
)
7988
);
8089
}
8190

82-
return new class( $middleware ) implements Middleware {
83-
public function __construct( private readonly Closure $middleware ) {}
84-
85-
public function process( Request $request, Handler $handler ): Response {
86-
return ( $this->middleware )( $request, $handler );
87-
}
88-
};
91+
return static::getMiddlewareAdapter( $middleware );
8992
} catch ( Throwable $e ) {
9093
if ( ! is_string( $middleware ) ) {
9194
throw $e;
@@ -95,22 +98,62 @@ public function process( Request $request, Handler $handler ): Response {
9598
sprintf(
9699
'The given middleware classname: "%1$s" must be an instance of "%2$s".',
97100
$middleware,
98-
$interface
101+
static::$middlewareInterface
99102
)
100103
);
101104
}//end try
102105
}
103106

104107
/** @param string|Closure|Middleware $middleware */
105108
public static function middlewareToPipe( $middleware ): Pipe {
109+
// Because Pipe::handle() wraps this function with the next pipe, we do not need to...
110+
// ...manually wrap middleware with $next & let createPipe take care of it.
111+
// If we do so, same middleware will recreate response multiple times
112+
// making our app less performant which we don't want at all cost.
106113
return self::toPipe(
107-
// Because Pipe::handle() wraps this function with the next pipe, we do not need to...
108-
static fn ( Response $r, Closure $next, Request $request, Handler $handler ) =>
109-
// ...manually wrap middleware with $next & let createPipe take care of it.
110-
// If we do so, same middleware will recreate response multiple times
111-
// making our app less performant which we don't want at all cost.
112-
self::toMiddleware( $middleware )
113-
->process( $request->withAttribute( self::MIDDLEWARE_RESPONSE, $r ), $handler )
114+
static fn ( $r, $next, $request, $handler ) => self::toMiddleware( $middleware )
115+
->process( $request->withAttribute( static::MIDDLEWARE_RESPONSE, $r ), $handler )
114116
);
115117
}
118+
119+
public static function make( string $className ): object {
120+
return isset( static::$container ) && static::$container->has( id: $className )
121+
? static::$container->get( id: $className )
122+
: new $className();
123+
}
124+
125+
/** @param \Psr\Container\ContainerInterface $container */
126+
public static function setApp( object $container ): void {
127+
static::$container = $container;
128+
}
129+
130+
public static function setMiddlewareAdapter( string $interface, string $className ): void {
131+
static::$middlewareInterface = $interface;
132+
static::$middlewareClass = $className;
133+
}
134+
135+
public static function resetMiddlewareAdapter(): void {
136+
static::$middlewareInterface = '';
137+
static::$middlewareClass = '';
138+
}
139+
140+
private static function getMiddlewareAdapter( Closure $middleware ): object {
141+
return static::hasMiddlewareClassAdapter()
142+
? new static::$middlewareClass( $middleware )
143+
: new class( $middleware ) implements Middleware {
144+
public function __construct( private readonly Closure $middleware ) {}
145+
146+
public function process( Request $request, Handler $handler ): Response {
147+
return ( $this->middleware )( $request, $handler );
148+
}
149+
};
150+
}
151+
152+
private static function hasMiddlewareInterfaceAdapter(): bool {
153+
return isset( static::$middlewareInterface ) && interface_exists( static::$middlewareInterface );
154+
}
155+
156+
private static function hasMiddlewareClassAdapter(): bool {
157+
return isset( static::$middlewareClass ) && class_exists( static::$middlewareClass );
158+
}
116159
}

0 commit comments

Comments
 (0)