blob: 80516861119130e013e1afa4d7757e20117d19fd (
plain)
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
|
<?php
namespace Jasny\Controller;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
/**
* Execute controller on given route
*/
trait RouteAction
{
/**
* @var boolean
*/
protected $actionCancelled = false;
/**
* Get request, set for controller
*
* @return ServerRequestInterface
*/
abstract public function getRequest();
/**
* Get response. set for controller
*
* @return ResponseInterface
*/
abstract public function getResponse();
/**
* Respond with a server error
*
* @param string $message
* @param int $code HTTP status code
*/
abstract public function notFound($message = '', $code = 404);
/**
* Get the route
*
* @return \stdClass
*/
protected function getRoute()
{
$route = $this->getRequest()->getAttribute('route');
if (!isset($route)) {
throw new \LogicException("Route has not been set");
}
if (is_array($route)) {
$route = (object)$route;
}
if (!$route instanceof \stdClass) {
$type = (is_object($route) ? get_class($route) . ' ' : '') . gettype($route);
throw new \UnexpectedValueException("Expected route to be a stdClass object, not a $type");
}
return $route;
}
/**
* Get the method name of the action
*
* @param string $action
* @return string
*/
protected function getActionMethod($action)
{
return \Jasny\camelcase($action) . 'Action';
}
/**
* Called before executing the action.
* @codeCoverageIgnore
*
* <code>
* protected function beforeAction()
* {
* $this->respondWith('json'); // Respond with JSON by default
*
* if ($this->auth->getUser()->getCredits() <= 0) {
* $this->paymentRequired();
* }
* }
* </code>
*/
protected function before()
{
}
/**
* Called before executing the action.
* @codeCoverageIgnore
*/
protected function after()
{
}
/**
* Cancel the action
*/
public function cancel()
{
$this->actionCancelled = true;
}
/**
* Check if the action is cancelled
*
* @return boolean
*/
public function isCancelled()
{
return $this->actionCancelled;
}
/**
* Run the controller
*
* @return ResponseInterface
*/
public function run()
{
$route = $this->getRoute();
$method = $this->getActionMethod(isset($route->action) ? $route->action : 'default');
if (!method_exists($this, $method)) {
return $this->notFound();
}
$this->before();
if (!$this->isCancelled()) {
$args = isset($route->args) ? $route->args
: $this->getFunctionArgs($route, new \ReflectionMethod($this, $method));
call_user_func_array([$this, $method], $args);
}
$this->after();
}
/**
* Get the arguments for a function from a route using reflection
*
* @param \stdClass $route
* @param \ReflectionFunctionAbstract $refl
* @return array
*/
protected function getFunctionArgs(\stdClass $route, \ReflectionFunctionAbstract $refl)
{
$args = [];
$params = $refl->getParameters();
foreach ($params as $param) {
$key = $param->name;
if (property_exists($route, $key)) {
$value = $route->$key;
} else {
if (!$param->isOptional()) {
$fn = $refl instanceof \ReflectionMethod ? $refl->class . '::' . $refl->name : $refl->name;
throw new \RuntimeException("Missing argument '$key' for {$fn}()");
}
$value = $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null;
}
$args[$key] = $value;
}
return $args;
}
}
|