-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathDelegate.class.php
More file actions
executable file
·112 lines (101 loc) · 3.62 KB
/
Delegate.class.php
File metadata and controls
executable file
·112 lines (101 loc) · 3.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
<?php namespace web\rest;
use io\streams\{InputStream, Streams};
use lang\reflection\{Method, TargetException};
use lang\{IllegalArgumentException, Reflection, Type};
use web\Request;
class Delegate {
private static $SOURCES;
private $instance, $method;
private $params= [];
static function __static() {
self::$SOURCES= [
'param' => function($req, $format, $name) { return $req->param($name); },
'value' => function($req, $format, $name) { return $req->value($name); },
'header' => function($req, $format, $name) { return $req->header($name); },
'stream' => function($req, $format, $name) { return $req->stream(); },
'entity' => function($req, $format, $name) { return $format->read($req, $name); },
'request' => function($req, $format, $name) { return $req; },
'body' => function($req, $format, $name) {
if (null === ($stream= $req->stream())) {
throw new IllegalArgumentException('Expecting a request body, none transmitted');
}
return Streams::readAll($stream);
},
];
}
/**
* Creates a new delegate
*
* @param object $instance
* @param string|lang.reflection.Method $method
* @param string $source Default source
*/
public function __construct($instance, $method, $source) {
$this->instance= $instance;
$this->method= $method instanceof Method ? $method : Reflection::type($instance)->method($method);
foreach ($this->method->parameters() as $param) {
// Source explicitely set by annotation
foreach ($param->annotations() as $annotation) {
if ($accessor= self::$SOURCES[$annotation->name()] ?? null) {
$this->param($param, $name ?? $param->name(), $accessor);
continue 2;
}
}
// Source derived from parameter type
$type= $param->constraint()->type();
if (Type::$VAR === $type) {
// NOOP
} else if ($type->isAssignableFrom(InputStream::class)) {
$source= 'stream';
} else if ($type->isAssignableFrom(Request::class)) {
$source= 'request';
}
$this->param($param, $param->name(), self::$SOURCES[$source]);
}
}
/**
* Adds parameter request accessor for a given parameter
*
* @param lang.reflection.Parameter $param
* @param string $name
* @param function(web.Request, web.rest.format.EntityFormat, string): var $accessor
* @return void
* @throws lang.IllegalArgumentException
*/
private function param($param, $name, $accessor) {
if ($param->optional()) {
$default= $param->default();
$read= function($req, $format) use($accessor, $name, $default) {
return $accessor($req, $format, $name) ?? $default;
};
} else {
$read= function($req, $format) use($accessor, $name) {
if (null === ($value= $accessor($req, $format, $name))) {
throw new IllegalArgumentException('Missing argument '.$name);
}
return $value;
};
}
$this->params[$name]= ['type' => $param->constraint()->type(), 'read' => $read];
}
/** @return string */
public function name() { return nameof($this->instance).'::'.$this->method->name(); }
/** @return lang.reflection.Annotations */
public function annotations() { return $this->method->annotations(); }
/** @return [:var] */
public function params() { return $this->params; }
/**
* Invokes the delegate
*
* @param var[] $arguments
* @return var
* @throws lang.Throwable
*/
public function invoke($args) {
try {
return $this->method->invoke($this->instance, $args);
} catch (TargetException $e) {
throw $e->getCause();
}
}
}