66
77use Patchlevel \EventSourcing \Attribute \Handle ;
88use ReflectionClass ;
9+ use ReflectionMethod ;
910use Symfony \Component \TypeInfo \Type \ObjectType ;
11+ use Symfony \Component \TypeInfo \Type \UnionType ;
1012use Symfony \Component \TypeInfo \TypeResolver \TypeResolver ;
1113
1214final class HandlerFinder
1315{
16+ private static TypeResolver $ typeResolver ;
17+
1418 /**
1519 * @param class-string $classString
1620 *
1721 * @return iterable<int, HandlerReference>
1822 */
1923 public static function findInClass (string $ classString ): iterable
2024 {
21- $ typeResolver = TypeResolver::create ();
2225 $ reflectionClass = new ReflectionClass ($ classString );
2326
2427 foreach ($ reflectionClass ->getMethods () as $ reflectionMethod ) {
@@ -28,53 +31,88 @@ public static function findInClass(string $classString): iterable
2831 continue ;
2932 }
3033
31- $ handle = $ handleAttributes [0 ]->newInstance ();
34+ foreach ($ handleAttributes as $ attribute ) {
35+ $ handle = $ attribute ->newInstance ();
36+
37+ if ($ handle ->commandClass !== null ) {
38+ yield new HandlerReference (
39+ $ handle ->commandClass ,
40+ $ reflectionMethod ->getName (),
41+ $ reflectionMethod ->isStatic (),
42+ );
43+
44+ continue ;
45+ }
46+
47+ foreach (self ::guessHandledClasses ($ reflectionMethod ) as $ class ) {
48+ yield new HandlerReference (
49+ $ class ,
50+ $ reflectionMethod ->getName (),
51+ $ reflectionMethod ->isStatic (),
52+ );
53+ }
54+ }
55+ }
56+ }
3257
33- if ($ handle ->commandClass !== null ) {
34- yield new HandlerReference (
35- $ handle ->commandClass ,
36- $ reflectionMethod ->getName (),
37- $ reflectionMethod ->isStatic (),
38- );
58+ /** @return list<class-string> */
59+ private static function guessHandledClasses (ReflectionMethod $ reflectionMethod ): array
60+ {
61+ $ parameters = $ reflectionMethod ->getParameters ();
3962
40- continue ;
41- }
63+ if ($ parameters === []) {
64+ throw InvalidHandleMethod::noParameters (
65+ $ reflectionMethod ->getDeclaringClass ()->getName (),
66+ $ reflectionMethod ->getName (),
67+ );
68+ }
4269
43- $ parameters = $ reflectionMethod -> getParameters ();
70+ $ reflectionType = $ parameters [ 0 ]-> getType ();
4471
45- if ($ parameters === [] ) {
46- throw InvalidHandleMethod::noParameters (
47- $ reflectionMethod ->getDeclaringClass ()->getName (),
48- $ reflectionMethod ->getName (),
49- );
50- }
72+ if ($ reflectionType === null ) {
73+ throw InvalidHandleMethod::incompatibleType (
74+ $ reflectionMethod ->getDeclaringClass ()->getName (),
75+ $ reflectionMethod ->getName (),
76+ );
77+ }
5178
52- $ reflectionType = $ parameters [ 0 ]-> getType ( );
79+ $ type = self :: typeResolver ()-> resolve ( $ reflectionType );
5380
54- if ($ reflectionType === null ) {
55- throw InvalidHandleMethod::incompatibleType (
56- $ reflectionMethod ->getDeclaringClass ()->getName (),
57- $ reflectionMethod ->getName (),
58- );
59- }
81+ if ($ type instanceof ObjectType) {
82+ /** @var class-string $className */
83+ $ className = $ type ->getClassName ();
6084
61- $ type = $ typeResolver ->resolve ($ reflectionType );
85+ return [$ className ];
86+ }
6287
63- if (!$ type instanceof ObjectType) {
64- throw InvalidHandleMethod::incompatibleType (
65- $ reflectionMethod ->getDeclaringClass ()->getName (),
66- $ reflectionMethod ->getName (),
67- );
68- }
88+ if ($ type instanceof UnionType) {
89+ $ types = [];
6990
70- /** @var class-string $commandClass */
71- $ commandClass = $ type ->getClassName ();
91+ foreach ($ type ->getTypes () as $ unionType ) {
92+ if (!$ unionType instanceof ObjectType) {
93+ throw InvalidHandleMethod::incompatibleType (
94+ $ reflectionMethod ->getDeclaringClass ()->getName (),
95+ $ reflectionMethod ->getName (),
96+ );
97+ }
7298
73- yield new HandlerReference (
74- $ commandClass ,
75- $ reflectionMethod ->getName (),
76- $ reflectionMethod ->isStatic (),
77- );
99+ /** @var class-string $className */
100+ $ className = $ unionType ->getClassName ();
101+
102+ $ types [] = $ className ;
103+ }
104+
105+ return $ types ;
78106 }
107+
108+ throw InvalidHandleMethod::incompatibleType (
109+ $ reflectionMethod ->getDeclaringClass ()->getName (),
110+ $ reflectionMethod ->getName (),
111+ );
112+ }
113+
114+ private static function typeResolver (): TypeResolver
115+ {
116+ return self ::$ typeResolver ??= TypeResolver::create ();
79117 }
80118}
0 commit comments