Rev 52 | Rev 64 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 52 | Rev 57 | ||
---|---|---|---|
1 | <?php
|
1 | <?php
|
2 | 2 | ||
3 | namespace PointedEars\PHPX; |
3 | namespace PointedEars\PHPX; |
4 | 4 | ||
- | 5 | if (!defined('DIRECTORY_SEPARATOR')) |
|
- | 6 | {
|
|
- | 7 | define('DIRECTORY_SEPARATOR', '/'); |
|
- | 8 | }
|
|
- | 9 | ||
5 | function autoload ($class) |
10 | function autoload ($class) |
6 | {
|
11 | {
|
7 | if (\strpos($class, '..')) |
12 | if (\strpos($class, '..') !== false) |
8 | {
|
13 | {
|
9 | throw new \InvalidArgumentException( |
14 | throw new \InvalidArgumentException( |
10 | 'Refusing to load unsafe class ' . $class); |
15 | "Refusing to load unsafe class '{$class}'"); |
11 | }
|
16 | }
|
12 | 17 | ||
13 | require_once \preg_replace('#\\\#', '/', |
18 | require_once \str_replace('\\', DIRECTORY_SEPARATOR, |
- | 19 | \preg_replace( |
|
14 | \preg_replace('#^' . \preg_quote(__NAMESPACE__) .'#', __DIR__, $class) |
20 | '#^' . \preg_quote(__NAMESPACE__, '#') .'#', |
- | 21 | __DIR__,
|
|
- | 22 | $class
|
|
- | 23 | )
|
|
15 | ) . '.php'; |
24 | ) . '.php'; |
16 | }
|
25 | }
|
17 | 26 | ||
18 | \spl_autoload_register(__NAMESPACE__ . '\\autoload'); |
27 | \spl_autoload_register(__NAMESPACE__ . '\\autoload'); |
19 | 28 | ||
20 | /**
|
29 | /**
|
21 | * Basic application class
|
30 | * Basic application class
|
22 | *
|
31 | *
|
23 | * @author Thomas Lahn
|
32 | * @author Thomas Lahn
|
24 | */
|
33 | */
|
25 | class Application
|
34 | class Application
|
26 | {
|
35 | {
|
27 | /**
|
36 | /**
|
28 | * Relative path to the controllers directory
|
37 | * Relative path to the controllers directory
|
29 | * @var string
|
38 | * @var string
|
30 | */
|
39 | */
|
31 | protected $_controllerPath = 'application/controllers'; |
40 | protected $_controllerPath = 'application/controllers'; |
32 | 41 | ||
33 | /**
|
42 | /**
|
34 | * Default controller of the application
|
43 | * Default controller of the application
|
35 | * @var string
|
44 | * @var string
|
36 | */
|
45 | */
|
37 | protected $_defaultController = 'Index'; |
46 | protected $_defaultController = 'Index'; |
38 | 47 | ||
39 | /**
|
48 | /**
|
40 | * Registry key for the default database of the application
|
49 | * Registry key for the default database of the application
|
41 | * @var string
|
50 | * @var string
|
42 | */
|
51 | */
|
43 | protected $_defaultDatabase; |
52 | protected $_defaultDatabase; |
44 | 53 | ||
45 | /**
|
54 | /**
|
46 | * Currently active controller of this application
|
55 | * Currently active controller of this application
|
47 | * @var Controller
|
56 | * @var Controller
|
48 | */
|
57 | */
|
49 | protected $_currentController; |
58 | protected $_currentController; |
50 | 59 | ||
51 | /**
|
60 | /**
|
52 | * Singleton
|
61 | * Singleton
|
53 | *
|
62 | *
|
54 | * @var Application
|
63 | * @var Application
|
55 | */
|
64 | */
|
56 | private static $_instance; |
65 | private static $_instance; |
57 | 66 | ||
58 | protected function __construct () |
67 | protected function __construct () |
59 | {
|
68 | {
|
60 | /* Singleton pattern */
|
69 | /* Singleton pattern */
|
61 | }
|
70 | }
|
62 | 71 | ||
63 | /**
|
72 | /**
|
64 | * Gets a reference to the <code>Application</code> instance
|
73 | * Gets a reference to the <code>Application</code> instance
|
65 | *
|
74 | *
|
66 | * @param Application $instance
|
75 | * @param Application $instance
|
67 | * The instance to be used as application. The default is a new
|
76 | * The instance to be used as application. The default is a new
|
68 | * application. This parameter is ignored if the application was
|
77 | * application. This parameter is ignored if the application was
|
69 | * already initialized.
|
78 | * already initialized.
|
70 | * @return Application
|
79 | * @return Application
|
71 | */
|
80 | */
|
72 | public static function getInstance (Application $instance = null) |
81 | public static function getInstance (Application $instance = null) |
73 | {
|
82 | {
|
74 | if (self::$_instance === null) |
83 | if (self::$_instance === null) |
75 | {
|
84 | {
|
76 | self::$_instance = ($instance === null) ? new self() : $instance; |
85 | self::$_instance = ($instance === null) ? new self() : $instance; |
77 | }
|
86 | }
|
78 | 87 | ||
79 | return self::$_instance; |
88 | return self::$_instance; |
80 | }
|
89 | }
|
81 | 90 | ||
82 | /**
|
91 | /**
|
83 | * Getter for properties
|
92 | * Getter for properties
|
84 | *
|
93 | *
|
85 | * @param string $name
|
94 | * @param string $name
|
86 | * @throws ModelPropertyException
|
95 | * @throws ModelPropertyException
|
87 | * @return mixed
|
96 | * @return mixed
|
88 | */
|
97 | */
|
89 | public function __get ($name) |
98 | public function __get ($name) |
90 | {
|
99 | {
|
91 | /* Support for Object-Relational Mappers */
|
100 | /* Support for Object-Relational Mappers */
|
92 | if (\strpos($name, 'persistent') === 0) |
101 | if (\strpos($name, 'persistent') === 0) |
93 | {
|
102 | {
|
94 | $class = \get_class($this); |
103 | $class = \get_class($this); |
95 | return $class::${$name}; |
104 | return $class::${$name}; |
96 | }
|
105 | }
|
97 | 106 | ||
98 | $method = 'get' . \ucfirst($name); |
107 | $method = 'get' . \ucfirst($name); |
99 | 108 | ||
100 | if (\method_exists($this, $method)) |
109 | if (\method_exists($this, $method)) |
101 | {
|
110 | {
|
102 | return $this->$method(); |
111 | return $this->$method(); |
103 | }
|
112 | }
|
104 | 113 | ||
105 | if (\property_exists($this, "_$name")) |
114 | if (\property_exists($this, "_$name")) |
106 | {
|
115 | {
|
107 | return $this->{"_$name"}; |
116 | return $this->{"_$name"}; |
108 | }
|
117 | }
|
109 | 118 | ||
110 | return $this->$name; |
119 | return $this->$name; |
111 | }
|
120 | }
|
112 | 121 | ||
113 | /**
|
122 | /**
|
114 | * Setter for properties
|
123 | * Setter for properties
|
115 | *
|
124 | *
|
116 | * @param string $name
|
125 | * @param string $name
|
117 | * @param mixed $value The new property value before assignment
|
126 | * @param mixed $value The new property value before assignment
|
118 | * @throws ModelPropertyException
|
127 | * @throws ModelPropertyException
|
119 | */
|
128 | */
|
120 | public function __set ($name, $value) |
129 | public function __set ($name, $value) |
121 | {
|
130 | {
|
122 | $method = 'set' . \ucfirst($name); |
131 | $method = 'set' . \ucfirst($name); |
123 | 132 | ||
124 | if (\method_exists($this, $method)) |
133 | if (\method_exists($this, $method)) |
125 | {
|
134 | {
|
126 | return $this->$method($value); |
135 | return $this->$method($value); |
127 | }
|
136 | }
|
128 | 137 | ||
129 | if (\property_exists($this, "_$name")) |
138 | if (\property_exists($this, "_$name")) |
130 | {
|
139 | {
|
131 | $this->{"_$name"} = $value; |
140 | $this->{"_$name"} = $value; |
132 | return $this->{"_$name"}; |
141 | return $this->{"_$name"}; |
133 | }
|
142 | }
|
134 | 143 | ||
135 | /* NOTE: Attempts to set other properties are _silently_ _ignored_ */
|
144 | /* NOTE: Attempts to set other properties are _silently_ _ignored_ */
|
136 | }
|
145 | }
|
137 | 146 | ||
138 | /**
|
147 | /**
|
139 | * Runs the application, setting up session management and
|
148 | * Runs the application, setting up session management and
|
140 | * constructing the controller indicated by the URI
|
149 | * constructing the controller indicated by the URI
|
141 | */
|
150 | */
|
142 | public function run () |
151 | public function run () |
143 | {
|
152 | {
|
144 | $this->startSession(); |
153 | $this->startSession(); |
145 | 154 | ||
146 | $controller = self::getParam('controller', $_REQUEST); |
155 | $controller = self::getParam('controller', $_REQUEST); |
147 | if (!$controller) |
156 | if (!$controller) |
148 | {
|
157 | {
|
149 | $controller = $this->_defaultController; |
158 | $controller = $this->_defaultController; |
150 | }
|
159 | }
|
151 | 160 | ||
152 | $controller = \ucfirst($controller); |
161 | $controller = \ucfirst($controller); |
153 | 162 | ||
154 | $controller = $controller . 'Controller'; |
163 | $controller = $controller . 'Controller'; |
155 | require_once "{$this->_controllerPath}/{$controller}.php"; |
164 | require_once "{$this->_controllerPath}/{$controller}.php"; |
156 | $this->_currentController = new $controller(); |
165 | $this->_currentController = new $controller(); |
157 | 166 | ||
158 | return $this; |
167 | return $this; |
159 | }
|
168 | }
|
160 | 169 | ||
161 | protected function startSession () |
170 | protected function startSession () |
162 | {
|
171 | {
|
163 | \session_start(); |
172 | \session_start(); |
164 | }
|
173 | }
|
165 | 174 | ||
166 | /**
|
175 | /**
|
167 | * Gets a request parameter
|
176 | * Gets a request parameter
|
168 | *
|
177 | *
|
169 | * @param string $key
|
178 | * @param string $key
|
170 | * Key to look up in the array
|
179 | * Key to look up in the array
|
171 | * @param array $array
|
180 | * @param array $array
|
172 | * Array where to look up <var>$key</var>.
|
181 | * Array where to look up <var>$key</var>.
|
173 | * The default is <code>$_GET</code>.
|
182 | * The default is <code>$_GET</code>.
|
174 | * @return mixed
|
183 | * @return mixed
|
175 | * <code>null</code> if there is no such <var>$key</var>
|
184 | * <code>null</code> if there is no such <var>$key</var>
|
176 | * in <var>$array</var>
|
185 | * in <var>$array</var>
|
177 | */
|
186 | */
|
178 | public static function getParam ($key, array $array = null) |
187 | public static function getParam ($key, array $array = null) |
179 | {
|
188 | {
|
180 | if ($array === null) |
189 | if ($array === null) |
181 | {
|
190 | {
|
182 | $array = $_GET; |
191 | $array = $_GET; |
183 | }
|
192 | }
|
184 | 193 | ||
185 | return isset($array[$key]) ? $array[$key] : null; |
194 | return isset($array[$key]) ? $array[$key] : null; |
186 | }
|
195 | }
|
187 | 196 | ||
188 | /**
|
197 | /**
|
189 | * Registers a database
|
198 | * Registers a database
|
190 | *
|
199 | *
|
191 | * @param string $key
|
200 | * @param string $key
|
192 | * @param Database $database
|
201 | * @param Database $database
|
193 | * @return string Registry key
|
202 | * @return string Registry key
|
194 | * @see Application::setDefaultDatabase()
|
203 | * @see Application::setDefaultDatabase()
|
195 | */
|
204 | */
|
196 | public function registerDatabase ($key, Db\Database $database) |
205 | public function registerDatabase ($key, Db\Database $database) |
197 | {
|
206 | {
|
198 | Registry::set($key, $database); |
207 | Registry::set($key, $database); |
199 | return $key; |
208 | return $key; |
200 | }
|
209 | }
|
201 | 210 | ||
202 | /**
|
211 | /**
|
203 | * Sets the default database
|
212 | * Sets the default database
|
204 | * @param string Registry key to refer to the {@link Database}
|
213 | * @param string Registry key to refer to the {@link Database}
|
205 | */
|
214 | */
|
206 | public function setDefaultDatabase ($key) |
215 | public function setDefaultDatabase ($key) |
207 | {
|
216 | {
|
208 | $this->_defaultDatabase = $key; |
217 | $this->_defaultDatabase = $key; |
209 | }
|
218 | }
|
210 | 219 | ||
211 | /**
|
220 | /**
|
212 | * Sets the current controller for this application
|
221 | * Sets the current controller for this application
|
213 | *
|
222 | *
|
214 | * @param Controller $controller
|
223 | * @param Controller $controller
|
215 | * @return Application
|
224 | * @return Application
|
216 | */
|
225 | */
|
217 | public function setCurrentController (Controller $controller) |
226 | public function setCurrentController (Controller $controller) |
218 | {
|
227 | {
|
219 | $this->_currentController = $controller; |
228 | $this->_currentController = $controller; |
220 | return $this; |
229 | return $this; |
221 | }
|
230 | }
|
222 | 231 | ||
223 | /**
|
232 | /**
|
224 | * Returns the current controller for this application
|
233 | * Returns the current controller for this application
|
225 | *
|
234 | *
|
226 | * @return Controller
|
235 | * @return Controller
|
227 | */
|
236 | */
|
228 | public function getCurrentController () |
237 | public function getCurrentController () |
229 | {
|
238 | {
|
230 | return $this->_currentController; |
239 | return $this->_currentController; |
231 | }
|
240 | }
|
232 | 241 | ||
233 | /**
|
242 | /**
|
234 | * Returns the default database for this application
|
243 | * Returns the default database for this application
|
235 | *
|
244 | *
|
236 | * @return Database
|
245 | * @return Database
|
237 | */
|
246 | */
|
238 | public function getDefaultDatabase () |
247 | public function getDefaultDatabase () |
239 | {
|
248 | {
|
240 | return Registry::get($this->_defaultDatabase); |
249 | return Registry::get($this->_defaultDatabase); |
241 | }
|
250 | }
|
242 | 251 | ||
243 | /**
|
252 | /**
|
244 | * Returns a relative URI-reference for an action of the
|
253 | * Returns a relative URI-reference for an action of the
|
245 | * application
|
254 | * application
|
246 | *
|
255 | *
|
247 | * @param string[optional] $controller
|
256 | * @param string[optional] $controller
|
248 | * @param string[optional] $action
|
257 | * @param string[optional] $action
|
249 | * @param int[optional] $id
|
258 | * @param int[optional] $id
|
250 | */
|
259 | */
|
251 | public function getURL ($controller = null, $action = null, $id = null) |
260 | public function getURL ($controller = null, $action = null, $id = null) |
252 | {
|
261 | {
|
253 | /* Apache module */
|
262 | /* Apache module */
|
254 | $url = self::getParam('SCRIPT_URL', $_SERVER); |
263 | $url = self::getParam('SCRIPT_URL', $_SERVER); |
255 | if ($url === null) |
264 | if ($url === null) |
256 | {
|
265 | {
|
257 | /* FastCGI */
|
266 | /* FastCGI */
|
258 | $url = self::getParam('URL', $_SERVER); |
267 | $url = self::getParam('URL', $_SERVER); |
259 | if ($url === null) |
268 | if ($url === null) |
260 | {
|
269 | {
|
261 | /* Server/PHP too old, compute URI */
|
270 | /* Server/PHP too old, compute URI */
|
262 | $url = self::getParam('REQUEST_URI', $_SERVER); |
271 | $url = self::getParam('REQUEST_URI', $_SERVER); |
263 | if (\preg_match('/^[^?]+/', $url, $matches) > 0) |
272 | if (\preg_match('/^[^?]+/', $url, $matches) > 0) |
264 | {
|
273 | {
|
265 | $url = $matches[0]; |
274 | $url = $matches[0]; |
266 | }
|
275 | }
|
267 | else
|
276 | else
|
268 | {
|
277 | {
|
269 | /* Has .php in it, but at least it works */
|
278 | /* Has .php in it, but at least it works */
|
270 | $url = self::getParam('SCRIPT_NAME', $_SERVER); |
279 | $url = self::getParam('SCRIPT_NAME', $_SERVER); |
271 | if ($url === null) |
280 | if ($url === null) |
272 | {
|
281 | {
|
273 | throw new \Exception( |
282 | throw new \Exception( |
274 | 'None of $_SERVER["SCRIPT_URL"], $_SERVER["URL"],'
|
283 | 'None of $_SERVER["SCRIPT_URL"], $_SERVER["URL"],'
|
275 | . ' $_SERVER["REQUEST_URI"], or $_SERVER["SCRIPT_NAME"]' |
284 | . ' $_SERVER["REQUEST_URI"], or $_SERVER["SCRIPT_NAME"]' |
276 | . ' is available, cannot continue.'); |
285 | . ' is available, cannot continue.'); |
277 | }
|
286 | }
|
278 | }
|
287 | }
|
279 | }
|
288 | }
|
280 | }
|
289 | }
|
281 | 290 | ||
282 | $query = (($controller !== null) ? 'controller=' . $controller : '') |
291 | $query = (($controller !== null) ? 'controller=' . $controller : '') |
283 | . (($action !== null) ? '&action=' . $action : '') |
292 | . (($action !== null) ? '&action=' . $action : '') |
284 | . (($id !== null) ? '&id=' . $id : ''); |
293 | . (($id !== null) ? '&id=' . $id : ''); |
285 | 294 | ||
286 | return $url . ($query ? '?' . $query : ''); |
295 | return $url . ($query ? '?' . $query : ''); |
287 | }
|
296 | }
|
288 | 297 | ||
289 | /**
|
298 | /**
|
290 | * Performs a server-side redirect within the application
|
299 | * Performs a server-side redirect within the application
|
291 | */
|
300 | */
|
292 | public static function redirect ($query = '') |
301 | public static function redirect ($query = '') |
293 | {
|
302 | {
|
294 | $script_uri = self::getParam('SCRIPT_URI', $_SERVER); |
303 | $script_uri = self::getParam('SCRIPT_URI', $_SERVER); |
295 | if ($script_uri === null) |
304 | if ($script_uri === null) |
296 | {
|
305 | {
|
297 | /* Server/PHP too old, compute URI */
|
306 | /* Server/PHP too old, compute URI */
|
298 | if (\preg_match('/^[^?]+/', |
307 | if (\preg_match('/^[^?]+/', |
299 | self::getParam('REQUEST_URI', $_SERVER), $matches) > 0) |
308 | self::getParam('REQUEST_URI', $_SERVER), $matches) > 0) |
300 | {
|
309 | {
|
301 | $query_prefix = $matches[0]; |
310 | $query_prefix = $matches[0]; |
302 | }
|
311 | }
|
303 | else
|
312 | else
|
304 | {
|
313 | {
|
305 | /* Has .php in it, but at least it works */
|
314 | /* Has .php in it, but at least it works */
|
306 | $query_prefix = self::getParam('SCRIPT_NAME', $_SERVER); |
315 | $query_prefix = self::getParam('SCRIPT_NAME', $_SERVER); |
307 | }
|
316 | }
|
308 | 317 | ||
309 | /* TODO: Let user decide which ports map to which URI scheme */
|
318 | /* TODO: Let user decide which ports map to which URI scheme */
|
310 | $script_uri = (self::getParam('SERVER_PORT', $_SERVER) == 443 |
319 | $script_uri = (self::getParam('SERVER_PORT', $_SERVER) == 443 |
311 | ? 'https://'
|
320 | ? 'https://'
|
312 | : 'http://') |
321 | : 'http://') |
313 | . self::getParam('HTTP_HOST', $_SERVER) |
322 | . self::getParam('HTTP_HOST', $_SERVER) |
314 | . $query_prefix; |
323 | . $query_prefix; |
315 | }
|
324 | }
|
316 | 325 | ||
317 | \header('Location: ' . $script_uri |
326 | \header('Location: ' . $script_uri |
318 | . ($query ? (substr($query, 0, 1) === '?' ? '' : '?') . $query : '')); |
327 | . ($query ? (substr($query, 0, 1) === '?' ? '' : '?') . $query : '')); |
319 | }
|
328 | }
|
320 | }
|
329 | }
|