This repository has been archived by the owner on Apr 16, 2024. It is now read-only.
/
Action.php
243 lines (191 loc) · 6.48 KB
/
Action.php
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
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
<?php
/**
* @package DF_Web
*/
require_once 'DF/Error/InvalidArgumentException.php';
/**
* An object instance of this class represents an action to execute in a
* controller.
*
* Multiple actions can be stacked and will be executed in the order they
* are stacked.
*
* When forwarding to a method in the same or a new controller, a new action
* instance is created and placed on top of the stack, to be executed
* immediately.
*
* An object of this class is immutable. Respect that when subclassing.
*/
class DF_Web_Action {
public static $LOGGER = NULL;
protected $controller = NULL;
protected $method = NULL;
protected $arguments = NULL;
/**
* Constructor.
*
* @param string $controller
* @param string $method
* @param array $args
* @return DF_Web_Action
*/
public function __construct($controller, $method, $args) {
if (!is_string($controller)) {
throw new DF_Error_InvalidArgumentException('controller', $controller, 'string');
}
if (!is_string($method)) {
# TODO Could this parameter be anything other than string?
throw new DF_Error_InvalidArgumentException('method', $method, 'string');
}
if (NULL === $args) {
// ok
}
elseif (!is_array($args)) {
throw new DF_Error_InvalidArgumentException('args', $args, 'array');
}
$this->controller = $controller;
$this->method = $method;
$this->arguments = $args;
}
public function get_controller() {
return $this->controller;
}
public function get_method() {
return $this->method;
}
public function get_arguments() {
return $this->arguments;
}
public function dispatch($c) {
if (!$c instanceof DF_Web) {
throw new DF_Error_InvalidArgumentException("c", $c, DF_Web);
}
return $c->execute_action($this);
}
/**
*
* @param DF_Web_Controller $controller
* @param DF_Web $c
* @return mixed
*/
public function execute($controller, $c) {
if (!$controller instanceof DF_Web_Controller) {
throw new DF_Error_InvalidArgumentException("controller", $controller, DF_Web_Controller);
}
if (!$c instanceof DF_Web) {
throw new DF_Error_InvalidArgumentException("c", $c, DF_Web);
}
$method_name = $this->get_method();
$arguments = $this->get_arguments();
# Prepend the context object to the argumentlist
if ($arguments == NULL) {
$arguments = array();
}
array_unshift($arguments, $c);
if (!method_exists($controller, $method_name)) {
$argstr = DF_Web_Utils_Arguments::flatten_arguments_list($arguments);
$ctrl_name = get_class($controller);
throw new DF_Web_Exception("No such method: ${ctrl_name}->${method_name}($argstr)");
}
# TODO how can I check the PHP access level of a method?
#elseif (!is_callable($controller, $method_name)) {
# throw new DF_Web_Exception("Method is not public: $ctrl_name::$method_name");
#}
try {
# FIXME this inits an error if the callback is a protected method
$ret = self::execute_action_by_params($controller, $method_name, $arguments);
return $ret;
}
catch (DF_Web_Detach_Exception $ex) {
// Rethrow the exception to continue breaking the chain
throw $ex;
}
catch (DF_Web_Exception $ex) {
$c->add_error($ex);
self::$LOGGER->error("Fatal exception: ".$ex->getMessage());
throw new DF_Web_Detach_Exception(
$this,
"Got an error we cannot handle"
);
}
catch (Exception $ex) {
$c->add_error($ex);
self::$LOGGER->error("Fatal exception, breaking off chain: ".$ex->getMessage());
throw new DF_Web_Detach_Exception(
$this,
"Got an error we cannot handle"
);
}
return false;
}
/**
*
* @param DF_Web_Controller $controller
* @param string $method_name
* @param array $arguments
* @throws DF_Error_InvalidArgumentException
* @return mixed
*/
static private function execute_action_by_params($controller, $method_name, $arguments) {
if (!$controller instanceof DF_Web_Controller) {
throw new DF_Error_InvalidArgumentException("controller", $controller, DF_Web_Controller);
}
$callback = array($controller, "$method_name");
$ret = call_user_func_array(
$callback,
$arguments
);
if (NULL === $ret) {
$ret = TRUE;
}
return $ret;
}
public function equals($action) {
if (NULL === $action) {
return false;
}
if ($this === $action) {
return true;
}
if (get_class($action) !== get_class($this)) {
return false;
}
if ($this->get_controller() != $action->get_controller()) {
return false;
}
if ($this->get_method() != $action->get_method()) {
return false;
}
if ($this->get_arguments() != $action->get_arguments()) {
return false;
}
return true;
}
public function get_private_path() {
$controller_path = $this->get_controller_private_path();
$method_path = $this->get_method_private_path();
return "$controller_path/$method_path";
}
protected function get_method_private_path() {
$path = preg_replace('|^handle_(.+)$|', '$1', $this->get_method());
return $path;
}
protected function get_controller_private_path() {
$path = strtolower($this->get_controller());
$path = preg_replace('#_#', '/', $path);
return $path;
}
public function toString() {
$args = "";
if ($this->arguments) {
$args = DF_Web_Utils_Arguments::flatten_arguments_list($this->arguments);
}
$ctrl = $this->controller;
$method = $this->method;
return "{$ctrl}->{$method}({$args})";
}
public function __toString() {
return $this->toString();
}
}
DF_Web_Action::$LOGGER = DF_Web_Logger::logger('DF_Web_Action');