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