diff --git a/composer.json b/composer.json index a76e3be..99e67be 100755 --- a/composer.json +++ b/composer.json @@ -8,6 +8,7 @@ "require" : { "xp-framework/core": "^11.0 | ^10.0 | ^9.0 | ^8.0 | ^7.0", "xp-framework/http": "^10.0 | ^9.0 | ^8.0 | ^7.0", + "xp-framework/reflection": "^2.0", "xp-forge/web": "^3.0 | ^2.9", "xp-forge/json": "^5.0 | ^4.0", "php": ">=7.0.0" diff --git a/src/main/php/web/frontend/Delegate.class.php b/src/main/php/web/frontend/Delegate.class.php index 7b570be..4ccd900 100755 --- a/src/main/php/web/frontend/Delegate.class.php +++ b/src/main/php/web/frontend/Delegate.class.php @@ -1,8 +1,8 @@ instance= $instance; - $this->method= $method instanceof Method ? $method : typeof($instance)->getMethod($method); + $this->method= $method instanceof Method ? $method : Reflection::type($instance)->method($method); } /** @return string */ @@ -40,7 +40,7 @@ public function group() { /** @return string */ public function name() { - return nameof($this->instance).'::'.$this->method->getName(); + return nameof($this->instance).'::'.$this->method->name(); } /** @@ -52,26 +52,28 @@ public function name() { public function parameters() { if (null === $this->parameters) { $this->parameters= []; - foreach ($this->method->getParameters() as $param) { - if ($annotations= $param->getAnnotations()) { - foreach ($annotations as $from => $value) { - $source= self::$SOURCES[$from] ?? self::$SOURCES['default']; - } + foreach ($this->method->parameters() as $param) { + + // Check for parameter annotations... + foreach ($param->annotations() as $annotation) { + $source= self::$SOURCES[$annotation->name()] ?? self::$SOURCES['default']; + $name= $annotation->argument(0) ?? $param->name(); - $name= null === $value ? $param->getName() : $value; - if ($param->isOptional()) { - $default= $param->getDefaultValue(); - $this->parameters[$name]= function($req, $name) use($source, $default) { - return $source($req, $name) ?? $default; + if ($param->optional()) { + $this->parameters[$name]= function($req, $name) use($source, $param) { + return $source($req, $name) ?? $param->default(); }; } else { $this->parameters[$name]= $source; } - } else { - $this->parameters[$param->getName()]= self::$SOURCES['segment']; + continue 2; } + + // ...falling back to selecting the parameter from the segments + $this->parameters[$param->name()]= self::$SOURCES['segment']; } } + return $this->parameters; } @@ -80,7 +82,7 @@ public function parameters() { * * @param var[] $args * @return web.frontend.View - * @throws lang.reflect.TargetInvocationException + * @throws lang.reflection.TargetException */ public function invoke($args) { $result= $this->method->invoke($this->instance, $args); diff --git a/src/main/php/web/frontend/Delegates.class.php b/src/main/php/web/frontend/Delegates.class.php index cc48cad..97e1ebd 100755 --- a/src/main/php/web/frontend/Delegates.class.php +++ b/src/main/php/web/frontend/Delegates.class.php @@ -1,10 +1,8 @@ getMethods() as $method) { - $name= $method->getName(); - foreach ($method->getAnnotations() as $verb => $segment) { + foreach (Reflection::type($instance)->methods() as $method) { + $name= $method->name(); + foreach ($method->annotations() as $annotation) { + $segment= $annotation->argument(0); $pattern= preg_replace( ['/\{([^:}]+):([^}]+)\}/', '/\{([^}]+)\}/'], ['(?<$1>$2)', '(?<$1>[^/]+)'], $base.('/' === $segment || null === $segment ? '/?' : $segment) ); - $this->patterns['#'.$verb.$pattern.'$#']= new Delegate($instance, $method); + $this->patterns['#'.$annotation->name().$pattern.'$#']= new Delegate($instance, $method); } } return $this; diff --git a/src/main/php/web/frontend/Frontend.class.php b/src/main/php/web/frontend/Frontend.class.php index f3d041f..14d61d0 100755 --- a/src/main/php/web/frontend/Frontend.class.php +++ b/src/main/php/web/frontend/Frontend.class.php @@ -1,6 +1,6 @@ invoke($args); - } catch (TargetInvocationException $e) { + } catch (TargetException $e) { return $this->errors()->handle($e->getCause()); } } diff --git a/src/main/php/web/frontend/HandlersIn.class.php b/src/main/php/web/frontend/HandlersIn.class.php index 73829e8..d1aa494 100755 --- a/src/main/php/web/frontend/HandlersIn.class.php +++ b/src/main/php/web/frontend/HandlersIn.class.php @@ -1,26 +1,28 @@ getClasses() as $class) { - if ($class->hasAnnotation('handler')) { - $this->with($new ? $new($class) : $class->newInstance(), (string)$class->getAnnotation('handler')); + $p= $package instanceof Package ? $package : new Package($package); + foreach ($p->types() as $type) { + if ($handler= $type->annotation(Handler::class)) { + $this->with($new ? $new($type) : $type->newInstance(), (string)$handler->argument(0)); + } else { + throw new \lang\IllegalStateException('Not a handler: '.$type->name()); } } uksort($this->patterns, function($a, $b) { return strlen($b) - strlen($a); }); diff --git a/src/main/php/web/frontend/MethodsIn.class.php b/src/main/php/web/frontend/MethodsIn.class.php index 5ca63f2..9449963 100755 --- a/src/main/php/web/frontend/MethodsIn.class.php +++ b/src/main/php/web/frontend/MethodsIn.class.php @@ -1,20 +1,22 @@ with($instance, $type->hasAnnotation('handler') ? (string)$type->getAnnotation('handler') : '/'); + $type= Reflection::type($instance); + if ($handler= $type->annotation(Handler::class)) { + $this->with($instance, (string)$handler->argument(0)); + } else { + $this->with($instance, '/'); + } uksort($this->patterns, function($a, $b) { return strlen($b) - strlen($a); }); } } \ No newline at end of file diff --git a/src/test/php/web/frontend/unittest/HandlersInTest.class.php b/src/test/php/web/frontend/unittest/HandlersInTest.class.php index 1f11b85..6c5da2a 100755 --- a/src/test/php/web/frontend/unittest/HandlersInTest.class.php +++ b/src/test/php/web/frontend/unittest/HandlersInTest.class.php @@ -1,25 +1,25 @@ [^/]+)/(?[0-9]+)$#',