5
5
* @package TheWebSolver\Codegarage\Library
6
6
*
7
7
* @phpcs:disable Squiz.Commenting.FunctionComment.ParamNameNoMatch, Squiz.Commenting.FunctionComment.IncorrectTypeHint -- Closure type-hint OK.
8
+ * @phpcs:disable Squiz.Commenting.FunctionCommentThrowTag.WrongNumber -- Accuracy is deceiving!!!
8
9
*/
9
10
10
11
declare ( strict_types = 1 );
@@ -32,7 +33,6 @@ class Pipeline {
32
33
* @throws InvalidPipeline When could not determine thrown exception.
33
34
* @phpstan-param class-string<Pipe>|Pipe|Closure(mixed $subject, Closure $next, mixed ...$use): mixed $pipe
34
35
*/
35
- // phpcs:ignore Squiz.Commenting.FunctionCommentThrowTag.WrongNumber -- Exactly 2 exception thrown.
36
36
final public static function resolve ( string |Closure |Pipe $ pipe ): Closure {
37
37
$ isClassName = is_string ( $ pipe ) && class_exists ( $ pipe );
38
38
@@ -44,7 +44,7 @@ final public static function resolve( string|Closure|Pipe $pipe ): Closure {
44
44
$ pipe instanceof Closure => $ pipe ,
45
45
};
46
46
} catch ( Throwable $ e ) {
47
- self ::throw ( $ e );
47
+ throw self ::getException ( $ e );
48
48
}
49
49
}
50
50
@@ -109,16 +109,20 @@ public function pipe( string|Closure|Pipe $pipe ): static {
109
109
* @throws InvalidPipe When pipe type could not be resolved.
110
110
* @throws InvalidPipeline When a pipe abrupt the pipeline by throwing an exception & sealWith not used.
111
111
*/
112
- // phpcs:ignore Squiz.Commenting.FunctionCommentThrowTag.Missing -- Doesn't throw throwable.
113
112
public function then ( Closure $ return ): mixed {
114
113
$ use = $ this ->use ?? array ();
115
114
$ pipes = array_reverse ( $ this ->pipes );
116
115
$ subject = $ this ->subject ;
117
116
118
117
try {
119
118
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 );
122
126
}
123
127
}
124
128
@@ -134,12 +138,22 @@ public function thenReturn() {
134
138
135
139
/** Gets a Closure that wraps current pipe with the next pipe in the pipeline. */
136
140
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
+ };
138
152
}
139
153
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 ;
144
158
}
145
159
}
0 commit comments