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
1011declare ( 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}
0 commit comments