Skip to content

Commit 0988a3e

Browse files
authored
Merge pull request #37 from xp-forge/refactor/reflection
Migrate to new reflection library
2 parents dba5c63 + f1f81e6 commit 0988a3e

File tree

7 files changed

+56
-50
lines changed

7 files changed

+56
-50
lines changed

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"require" : {
99
"xp-framework/core": "^11.0 | ^10.0 | ^9.0 | ^8.0 | ^7.0",
1010
"xp-framework/http": "^10.0 | ^9.0 | ^8.0 | ^7.0",
11+
"xp-framework/reflection": "^2.0",
1112
"xp-forge/web": "^3.0 | ^2.9",
1213
"xp-forge/json": "^5.0 | ^4.0",
1314
"php": ">=7.0.0"

src/main/php/web/frontend/Delegate.class.php

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<?php namespace web\frontend;
22

3-
use lang\IllegalArgumentException;
3+
use lang\reflection\Method;
4+
use lang\{IllegalArgumentException, Reflection};
45
use web\frontend\View;
5-
use lang\reflect\Method;
66

77
class Delegate {
88
private static $SOURCES;
@@ -25,11 +25,11 @@ static function __static() {
2525
* Creates a new delegate
2626
*
2727
* @param object $instance
28-
* @param string|lang.reflect.Method $method
28+
* @param string|lang.reflection.Method $method
2929
*/
3030
public function __construct($instance, $method) {
3131
$this->instance= $instance;
32-
$this->method= $method instanceof Method ? $method : typeof($instance)->getMethod($method);
32+
$this->method= $method instanceof Method ? $method : Reflection::type($instance)->method($method);
3333
}
3434

3535
/** @return string */
@@ -40,7 +40,7 @@ public function group() {
4040

4141
/** @return string */
4242
public function name() {
43-
return nameof($this->instance).'::'.$this->method->getName();
43+
return nameof($this->instance).'::'.$this->method->name();
4444
}
4545

4646
/**
@@ -52,26 +52,28 @@ public function name() {
5252
public function parameters() {
5353
if (null === $this->parameters) {
5454
$this->parameters= [];
55-
foreach ($this->method->getParameters() as $param) {
56-
if ($annotations= $param->getAnnotations()) {
57-
foreach ($annotations as $from => $value) {
58-
$source= self::$SOURCES[$from] ?? self::$SOURCES['default'];
59-
}
55+
foreach ($this->method->parameters() as $param) {
56+
57+
// Check for parameter annotations...
58+
foreach ($param->annotations() as $annotation) {
59+
$source= self::$SOURCES[$annotation->name()] ?? self::$SOURCES['default'];
60+
$name= $annotation->argument(0) ?? $param->name();
6061

61-
$name= null === $value ? $param->getName() : $value;
62-
if ($param->isOptional()) {
63-
$default= $param->getDefaultValue();
64-
$this->parameters[$name]= function($req, $name) use($source, $default) {
65-
return $source($req, $name) ?? $default;
62+
if ($param->optional()) {
63+
$this->parameters[$name]= function($req, $name) use($source, $param) {
64+
return $source($req, $name) ?? $param->default();
6665
};
6766
} else {
6867
$this->parameters[$name]= $source;
6968
}
70-
} else {
71-
$this->parameters[$param->getName()]= self::$SOURCES['segment'];
69+
continue 2;
7270
}
71+
72+
// ...falling back to selecting the parameter from the segments
73+
$this->parameters[$param->name()]= self::$SOURCES['segment'];
7374
}
7475
}
76+
7577
return $this->parameters;
7678
}
7779

@@ -80,7 +82,7 @@ public function parameters() {
8082
*
8183
* @param var[] $args
8284
* @return web.frontend.View
83-
* @throws lang.reflect.TargetInvocationException
85+
* @throws lang.reflection.TargetException
8486
*/
8587
public function invoke($args) {
8688
$result= $this->method->invoke($this->instance, $args);

src/main/php/web/frontend/Delegates.class.php

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
<?php namespace web\frontend;
22

3-
use lang\IllegalArgumentException;
3+
use lang\{IllegalArgumentException, Reflection};
44

5-
/**
6-
* Matches request and routes to correct delegate
7-
*/
5+
/** Matches request and routes to correct delegate */
86
class Delegates {
97
public $patterns= [];
108

@@ -22,15 +20,16 @@ public function with($instance, $base= '/') {
2220
}
2321

2422
$base= rtrim($base, '/');
25-
foreach (typeof($instance)->getMethods() as $method) {
26-
$name= $method->getName();
27-
foreach ($method->getAnnotations() as $verb => $segment) {
23+
foreach (Reflection::type($instance)->methods() as $method) {
24+
$name= $method->name();
25+
foreach ($method->annotations() as $annotation) {
26+
$segment= $annotation->argument(0);
2827
$pattern= preg_replace(
2928
['/\{([^:}]+):([^}]+)\}/', '/\{([^}]+)\}/'],
3029
['(?<$1>$2)', '(?<$1>[^/]+)'],
3130
$base.('/' === $segment || null === $segment ? '/?' : $segment)
3231
);
33-
$this->patterns['#'.$verb.$pattern.'$#']= new Delegate($instance, $method);
32+
$this->patterns['#'.$annotation->name().$pattern.'$#']= new Delegate($instance, $method);
3433
}
3534
}
3635
return $this;

src/main/php/web/frontend/Frontend.class.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php namespace web\frontend;
22

3-
use lang\reflect\TargetInvocationException;
3+
use lang\reflection\TargetException;
44
use web\{Error, Handler, Request};
55

66
/**
@@ -98,7 +98,7 @@ private function view($req, $res, $delegate, $matches= []) {
9898
}
9999

100100
return $delegate->invoke($args);
101-
} catch (TargetInvocationException $e) {
101+
} catch (TargetException $e) {
102102
return $this->errors()->handle($e->getCause());
103103
}
104104
}

src/main/php/web/frontend/HandlersIn.class.php

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,28 @@
11
<?php namespace web\frontend;
22

3-
use lang\reflect\Package;
3+
use lang\reflection\Package;
44

55
/**
6-
* Creates routing based on classes annotated with `@handler` in a
7-
* given package.
6+
* Creates routing based on classes annotated with the `Handler` annotation
7+
* in a given package.
88
*
9-
* @test xp://web.frontend.unittest.HandlersInTest
9+
* @test web.frontend.unittest.HandlersInTest
1010
*/
1111
class HandlersIn extends Delegates {
1212

1313
/**
1414
* Creates this delegates instance
1515
*
16-
* @param lang.reflect.Package|string $package
16+
* @param lang.reflection.Package|string $package
1717
* @param function(lang.XPClass): object $new Optional function to create instances
1818
*/
1919
public function __construct($package, $new= null) {
20-
$p= $package instanceof Package ? $package : Package::forName($package);
21-
foreach ($p->getClasses() as $class) {
22-
if ($class->hasAnnotation('handler')) {
23-
$this->with($new ? $new($class) : $class->newInstance(), (string)$class->getAnnotation('handler'));
20+
$p= $package instanceof Package ? $package : new Package($package);
21+
foreach ($p->types() as $type) {
22+
if ($handler= $type->annotation(Handler::class)) {
23+
$this->with($new ? $new($type) : $type->newInstance(), (string)$handler->argument(0));
24+
} else {
25+
throw new \lang\IllegalStateException('Not a handler: '.$type->name());
2426
}
2527
}
2628
uksort($this->patterns, function($a, $b) { return strlen($b) - strlen($a); });
Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
11
<?php namespace web\frontend;
22

3-
use lang\IllegalArgumentException;
3+
use lang\{IllegalArgumentException, Reflection};
44

5-
/**
6-
* Creates routing based on a given instance
7-
*/
5+
/** Creates routing based on a given instance */
86
class MethodsIn extends Delegates {
97

108
/** @param object $instance */
119
public function __construct($instance) {
12-
$type= typeof($instance);
1310
if (!is_object($instance)) {
14-
throw new IllegalArgumentException('Expected an object, have '.$type);
11+
throw new IllegalArgumentException('Expected an object, have '.typeof($instance));
1512
}
1613

17-
$this->with($instance, $type->hasAnnotation('handler') ? (string)$type->getAnnotation('handler') : '/');
14+
$type= Reflection::type($instance);
15+
if ($handler= $type->annotation(Handler::class)) {
16+
$this->with($instance, (string)$handler->argument(0));
17+
} else {
18+
$this->with($instance, '/');
19+
}
1820
uksort($this->patterns, function($a, $b) { return strlen($b) - strlen($a); });
1921
}
2022
}

src/test/php/web/frontend/unittest/HandlersInTest.class.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
<?php namespace web\frontend\unittest;
22

3-
use lang\reflect\Package;
4-
use test\Assert;
5-
use test\{Test, TestCase};
3+
use lang\reflection\Package;
4+
use test\{Assert, Test};
65
use web\frontend\HandlersIn;
76

87
class HandlersInTest {
8+
const PACKAGE= 'web.frontend.unittest.actions';
99

1010
#[Test]
1111
public function can_create_with_string() {
12-
new HandlersIn('web.frontend.unittest.actions');
12+
new HandlersIn(self::PACKAGE);
1313
}
1414

1515
#[Test]
1616
public function can_create_with_package() {
17-
new HandlersIn(Package::forName('web.frontend.unittest.actions'));
17+
new HandlersIn(new Package(self::PACKAGE));
1818
}
1919

2020
#[Test]
2121
public function patterns_sorted_by_length() {
22-
$delegates= new HandlersIn('web.frontend.unittest.actions');
22+
$delegates= new HandlersIn(self::PACKAGE);
2323
Assert::equals(
2424
[
2525
'#get/blogs/(?<category>[^/]+)/(?<id>[0-9]+)$#',

0 commit comments

Comments
 (0)