Subversion Repositories PHPX

Rev

Rev 64 | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 64 Rev 75
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 = '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
}