Skip to content

Commit 59f7a1e

Browse files
committed
Every throwable (except InvalidPipe) is converted to InvalidPipeline.
This change is to streamline and better typehint expected exception for projects implementing Pipeline. - Removed checking container has item before resolving in Pipeline Bridge.
1 parent 66df2a9 commit 59f7a1e

File tree

3 files changed

+42
-20
lines changed

3 files changed

+42
-20
lines changed

Src/InvalidPipeline.php

+14-1
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,18 @@
88
namespace TheWebSolver\Codegarage\Lib;
99

1010
use Exception;
11+
use Throwable;
1112

12-
class InvalidPipeline extends Exception {}
13+
class InvalidPipeline extends Exception {
14+
public function __construct( Throwable $previous, private readonly mixed $subject = null ) {
15+
parent::__construct( $previous->getMessage(), $previous->getCode(), $previous );
16+
}
17+
18+
public function hasSubject(): bool {
19+
return isset( $this->subject );
20+
}
21+
22+
public function getSubject(): mixed {
23+
return $this->subject;
24+
}
25+
}

Src/Pipeline.php

+24-10
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
* @package TheWebSolver\Codegarage\Library
66
*
77
* @phpcs:disable Squiz.Commenting.FunctionComment.ParamNameNoMatch, Squiz.Commenting.FunctionComment.IncorrectTypeHint -- Closure type-hint OK.
8+
* @phpcs:disable Squiz.Commenting.FunctionCommentThrowTag.WrongNumber -- Accuracy is deceiving!!!
89
*/
910

1011
declare( strict_types = 1 );
@@ -32,7 +33,6 @@ class Pipeline {
3233
* @throws InvalidPipeline When could not determine thrown exception.
3334
* @phpstan-param class-string<Pipe>|Pipe|Closure(mixed $subject, Closure $next, mixed ...$use): mixed $pipe
3435
*/
35-
// phpcs:ignore Squiz.Commenting.FunctionCommentThrowTag.WrongNumber -- Exactly 2 exception thrown.
3636
final public static function resolve( string|Closure|Pipe $pipe ): Closure {
3737
$isClassName = is_string( $pipe ) && class_exists( $pipe );
3838

@@ -44,7 +44,7 @@ final public static function resolve( string|Closure|Pipe $pipe ): Closure {
4444
$pipe instanceof Closure => $pipe,
4545
};
4646
} catch ( Throwable $e ) {
47-
self::throw( $e );
47+
throw self::getException( $e );
4848
}
4949
}
5050

@@ -109,16 +109,20 @@ public function pipe( string|Closure|Pipe $pipe ): static {
109109
* @throws InvalidPipe When pipe type could not be resolved.
110110
* @throws InvalidPipeline When a pipe abrupt the pipeline by throwing an exception & sealWith not used.
111111
*/
112-
// phpcs:ignore Squiz.Commenting.FunctionCommentThrowTag.Missing -- Doesn't throw throwable.
113112
public function then( Closure $return ): mixed {
114113
$use = $this->use ?? array();
115114
$pipes = array_reverse( $this->pipes );
116115
$subject = $this->subject;
117116

118117
try {
119118
return array_reduce( $pipes, $this->chain( ... ), $return )( $subject, ...$use );
120-
} catch ( Throwable $e ) {
121-
return ( $seal = $this->catcher ?? null ) ? $seal( $e, ...$use ) : self::throw( $e );
119+
} catch ( InvalidPipe|InvalidPipeline $e ) {
120+
if ( ! $sealer = ( $this->catcher ?? null ) ) {
121+
throw $e;
122+
}
123+
124+
// "InvalidPipe" is an internal error. Must be fixed and should never be sealed.
125+
return $e instanceof InvalidPipe ? throw $e : $sealer( $e, ...$use );
122126
}
123127
}
124128

@@ -134,12 +138,22 @@ public function thenReturn() {
134138

135139
/** Gets a Closure that wraps current pipe with the next pipe in the pipeline. */
136140
protected function chain( Closure $next, string|Closure|Pipe $current ): Closure {
137-
return fn ( $subject ) => self::resolve( $current )( $subject, $next, ...( $this->use ?? array() ) );
141+
return function ( $subject ) use ( $current, $next ) {
142+
try {
143+
return self::resolve( $current )( $subject, $next, ...( $this->use ?? array() ) );
144+
} catch ( Throwable $e ) {
145+
// Here, exception can be anything besides Pipe & Pipeline exception. This exception may be
146+
// thrown when pipe is handling the subject. We'll need to convert whatever thrown back to
147+
// the InvalidPipeline exception and silently pass the previous subject through this new
148+
// InvalidPipeline exception so that it can be consumed and/or handled by the client.
149+
throw self::getException( $e, $subject );
150+
}
151+
};
138152
}
139153

140-
private static function throw( Throwable $e ): never {
141-
throw $e instanceof InvalidPipe
142-
? $e
143-
: new InvalidPipeline( $e->getMessage(), $e->getCode(), $e );
154+
private static function getException( Throwable $previous ): InvalidPipe|InvalidPipeline {
155+
return ! $previous instanceof InvalidPipe
156+
? new InvalidPipeline( $previous, subject: func_num_args() === 2 ? func_get_arg( 1 ) : null )
157+
: $previous;
144158
}
145159
}

Src/PipelineBridge.php

+4-9
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,9 @@ public static function toMiddleware( mixed $middleware ): object {
8484
throw $e instanceof InvalidMiddlewareForPipe
8585
? $e
8686
: ( ! is_string( $middleware )
87-
? new InvalidPipeline( $e->getMessage(), $e->getCode(), $e )
88-
: new InvalidMiddlewareForPipe(
89-
sprintf(
90-
'The given middleware classname: "%1$s" must be an instance of "%2$s".',
91-
$middleware,
92-
$interface
93-
)
94-
) );
87+
? new InvalidPipeline( $e )
88+
: new InvalidMiddlewareForPipe( $e->getMessage(), $e->getCode(), $e )
89+
);
9590
}//end try
9691
}
9792

@@ -115,7 +110,7 @@ protected static function getPipeHandler( object $with, array $args ) {
115110
}
116111

117112
public static function make( string $className ): object {
118-
return isset( static::$container ) && static::$container->has( id: $className )
113+
return isset( static::$container )
119114
? static::$container->get( id: $className )
120115
: new $className();
121116
}

0 commit comments

Comments
 (0)