Namespaces

  • Nette
    • Application
    • Caching
    • Collections
    • Config
    • Forms
    • IO
    • Loaders
    • Mail
    • Reflection
    • Security
    • Templates
    • Web
  • None
  • PHP

Classes

  • AppForm
  • Application
  • CliRouter
  • Control
  • DownloadResponse
  • ForwardingResponse
  • JsonResponse
  • Link
  • MultiRouter
  • Presenter
  • PresenterComponent
  • PresenterLoader
  • PresenterRequest
  • RedirectingResponse
  • RenderResponse
  • Route
  • SimpleRouter

Interfaces

  • IPartiallyRenderable
  • IPresenter
  • IPresenterLoader
  • IPresenterResponse
  • IRenderable
  • IRouter
  • ISignalReceiver
  • IStatePersistent

Exceptions

  • AbortException
  • ApplicationException
  • BadRequestException
  • BadSignalException
  • ForbiddenRequestException
  • InvalidLinkException
  • InvalidPresenterException
  • Overview
  • Namespace
  • Class
  • Tree
  • Other releases
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (https://nette.org)
  5:  *
  6:  * Copyright (c) 2004 David Grudl (http://davidgrudl.com)
  7:  *
  8:  * For the full copyright and license information, please view
  9:  * the file license.txt that was distributed with this source code.
 10:  */
 11: 
 12: namespace Nette\Application;
 13: 
 14: use Nette,
 15:     Nette\Environment;
 16: 
 17: 
 18: 
 19: /**
 20:  * Front Controller.
 21:  *
 22:  * @author     David Grudl
 23:  */
 24: class Application extends Nette\Object
 25: {
 26:     /** @var int */
 27:     public static $maxLoop = 20;
 28: 
 29:     /** @var array */
 30:     public $defaultServices = array(
 31:         'Nette\\Application\\IRouter' => 'Nette\Application\MultiRouter',
 32:         'Nette\\Application\\IPresenterLoader' => array(__CLASS__, 'createPresenterLoader'),
 33:     );
 34: 
 35:     /** @var bool enable fault barrier? */
 36:     public $catchExceptions;
 37: 
 38:     /** @var string */
 39:     public $errorPresenter;
 40: 
 41:     /** @var array of function(Application $sender); Occurs before the application loads presenter */
 42:     public $onStartup;
 43: 
 44:     /** @var array of function(Application $sender, \Exception $e = NULL); Occurs before the application shuts down */
 45:     public $onShutdown;
 46: 
 47:     /** @var array of function(Application $sender, PresenterRequest $request); Occurs when a new request is ready for dispatch */
 48:     public $onRequest;
 49: 
 50:     /** @var array of function(Application $sender, \Exception $e); Occurs when an unhandled exception occurs in the application */
 51:     public $onError;
 52: 
 53:     /** @var array of string */
 54:     public $allowedMethods = array('GET', 'POST', 'HEAD', 'PUT', 'DELETE');
 55: 
 56:     /** @var array of PresenterRequest */
 57:     private $requests = array();
 58: 
 59:     /** @var Presenter */
 60:     private $presenter;
 61: 
 62:     /** @var Nette\ServiceLocator */
 63:     private $serviceLocator;
 64: 
 65: 
 66: 
 67:     /**
 68:      * Dispatch a HTTP request to a front controller.
 69:      * @return void
 70:      */
 71:     public function run()
 72:     {
 73:         $httpRequest = $this->getHttpRequest();
 74:         $httpResponse = $this->getHttpResponse();
 75: 
 76:         $httpRequest->setEncoding('UTF-8');
 77:         $httpResponse->setHeader('X-Powered-By', 'Nette Framework');
 78: 
 79:         if (Environment::getVariable('baseUri') === NULL) {
 80:             Environment::setVariable('baseUri', $httpRequest->getUri()->getBasePath());
 81:         }
 82: 
 83:         // autostarts session
 84:         $session = $this->getSession();
 85:         if (!$session->isStarted() && $session->exists()) {
 86:             $session->start();
 87:         }
 88: 
 89:         // check HTTP method
 90:         if ($this->allowedMethods) {
 91:             $method = $httpRequest->getMethod();
 92:             if (!in_array($method, $this->allowedMethods, TRUE)) {
 93:                 $httpResponse->setCode(Nette\Web\IHttpResponse::S501_NOT_IMPLEMENTED);
 94:                 $httpResponse->setHeader('Allow', implode(',', $this->allowedMethods));
 95:                 echo '<h1>Method ' . htmlSpecialChars($method) . ' is not implemented</h1>';
 96:                 return;
 97:             }
 98:         }
 99: 
100:         // dispatching
101:         $request = NULL;
102:         $repeatedError = FALSE;
103:         do {
104:             try {
105:                 if (count($this->requests) > self::$maxLoop) {
106:                     throw new ApplicationException('Too many loops detected in application life cycle.');
107:                 }
108: 
109:                 if (!$request) {
110:                     $this->onStartup($this);
111: 
112:                     // default router
113:                     $router = $this->getRouter();
114:                     if ($router instanceof MultiRouter && !count($router)) {
115:                         $router[] = new SimpleRouter(array(
116:                             'presenter' => 'Default',
117:                             'action' => 'default',
118:                         ));
119:                     }
120: 
121:                     // routing
122:                     $request = $router->match($httpRequest);
123:                     if (!($request instanceof PresenterRequest)) {
124:                         $request = NULL;
125:                         throw new BadRequestException('No route for HTTP request.');
126:                     }
127: 
128:                     if (strcasecmp($request->getPresenterName(), $this->errorPresenter) === 0) {
129:                         throw new BadRequestException('Invalid request.');
130:                     }
131:                 }
132: 
133:                 $this->requests[] = $request;
134:                 $this->onRequest($this, $request);
135: 
136:                 // Instantiate presenter
137:                 $presenter = $request->getPresenterName();
138:                 try {
139:                     $class = $this->getPresenterLoader()->getPresenterClass($presenter);
140:                     $request->setPresenterName($presenter);
141:                 } catch (InvalidPresenterException $e) {
142:                     throw new BadRequestException($e->getMessage(), 404, $e);
143:                 }
144:                 $request->freeze();
145: 
146:                 // Execute presenter
147:                 $this->presenter = new $class;
148:                 $response = $this->presenter->run($request);
149: 
150:                 // Send response
151:                 if ($response instanceof ForwardingResponse) {
152:                     $request = $response->getRequest();
153:                     continue;
154: 
155:                 } elseif ($response instanceof IPresenterResponse) {
156:                     $response->send();
157:                 }
158:                 break;
159: 
160:             } catch (\Exception $e) {
161:                 // fault barrier
162:                 if ($this->catchExceptions === NULL) {
163:                     $this->catchExceptions = Environment::isProduction();
164:                 }
165: 
166:                 $this->onError($this, $e);
167: 
168:                 if (!$this->catchExceptions) {
169:                     $this->onShutdown($this, $e);
170:                     throw $e;
171:                 }
172: 
173:                 if ($repeatedError) {
174:                     $e = new ApplicationException('An error occured while executing error-presenter', 0, $e);
175:                 }
176: 
177:                 if (!$httpResponse->isSent()) {
178:                     $httpResponse->setCode($e instanceof BadRequestException ? $e->getCode() : 500);
179:                 }
180: 
181:                 if (!$repeatedError && $this->errorPresenter) {
182:                     $repeatedError = TRUE;
183:                     $request = new PresenterRequest(
184:                         $this->errorPresenter,
185:                         PresenterRequest::FORWARD,
186:                         array('exception' => $e)
187:                     );
188:                     // continue
189: 
190:                 } else { // default error handler
191:                     echo "<meta name='robots' content='noindex'>\n\n";
192:                     if ($e instanceof BadRequestException) {
193:                         echo "<title>404 Not Found</title>\n\n<h1>Not Found</h1>\n\n<p>The requested URL was not found on this server.</p>";
194: 
195:                     } else {
196:                         Nette\Debug::processException($e, FALSE);
197:                         echo "<title>500 Internal Server Error</title>\n\n<h1>Server Error</h1>\n\n",
198:                             "<p>The server encountered an internal error and was unable to complete your request. Please try again later.</p>";
199:                     }
200:                     echo "\n\n<hr>\n<small><i>Nette Framework</i></small>";
201:                     break;
202:                 }
203:             }
204:         } while (1);
205: 
206:         $this->onShutdown($this, isset($e) ? $e : NULL);
207:     }
208: 
209: 
210: 
211:     /**
212:      * Returns all processed requests.
213:      * @return array of PresenterRequest
214:      */
215:     final public function getRequests()
216:     {
217:         return $this->requests;
218:     }
219: 
220: 
221: 
222:     /**
223:      * Returns current presenter.
224:      * @return Presenter
225:      */
226:     final public function getPresenter()
227:     {
228:         return $this->presenter;
229:     }
230: 
231: 
232: 
233:     /********************* services ****************d*g**/
234: 
235: 
236: 
237:     /**
238:      * Gets the service locator (experimental).
239:      * @return Nette\IServiceLocator
240:      */
241:     final public function getServiceLocator()
242:     {
243:         if ($this->serviceLocator === NULL) {
244:             $this->serviceLocator = new Nette\ServiceLocator(Environment::getServiceLocator());
245: 
246:             foreach ($this->defaultServices as $name => $service) {
247:                 if (!$this->serviceLocator->hasService($name)) {
248:                     $this->serviceLocator->addService($name, $service);
249:                 }
250:             }
251:         }
252:         return $this->serviceLocator;
253:     }
254: 
255: 
256: 
257:     /**
258:      * Gets the service object of the specified type.
259:      * @param  string service name
260:      * @param  array  options in case service is not singleton
261:      * @return object
262:      */
263:     final public function getService($name, array $options = NULL)
264:     {
265:         return $this->getServiceLocator()->getService($name, $options);
266:     }
267: 
268: 
269: 
270:     /**
271:      * Returns router.
272:      * @return IRouter
273:      */
274:     public function getRouter()
275:     {
276:         return $this->getServiceLocator()->getService('Nette\\Application\\IRouter');
277:     }
278: 
279: 
280: 
281:     /**
282:      * Changes router.
283:      * @param  IRouter
284:      * @return Application  provides a fluent interface
285:      */
286:     public function setRouter(IRouter $router)
287:     {
288:         $this->getServiceLocator()->addService('Nette\\Application\\IRouter', $router);
289:         return $this;
290:     }
291: 
292: 
293: 
294:     /**
295:      * Returns presenter loader.
296:      * @return IPresenterLoader
297:      */
298:     public function getPresenterLoader()
299:     {
300:         return $this->getServiceLocator()->getService('Nette\\Application\\IPresenterLoader');
301:     }
302: 
303: 
304: 
305:     /********************* service factories ****************d*g**/
306: 
307: 
308: 
309:     /**
310:      * @return IPresenterLoader
311:      */
312:     public static function createPresenterLoader()
313:     {
314:         return new PresenterLoader(Environment::getVariable('appDir'));
315:     }
316: 
317: 
318: 
319:     /********************* request serialization ****************d*g**/
320: 
321: 
322: 
323:     /**
324:      * Stores current request to session.
325:      * @param  mixed  optional expiration time
326:      * @return string key
327:      */
328:     public function storeRequest($expiration = '+ 10 minutes')
329:     {
330:         $session = $this->getSession('Nette.Application/requests');
331:         do {
332:             $key = substr(md5(lcg_value()), 0, 4);
333:         } while (isset($session[$key]));
334: 
335:         $session[$key] = end($this->requests);
336:         $session->setExpiration($expiration, $key);
337:         return $key;
338:     }
339: 
340: 
341: 
342:     /**
343:      * Restores current request to session.
344:      * @param  string key
345:      * @return void
346:      */
347:     public function restoreRequest($key)
348:     {
349:         $session = $this->getSession('Nette.Application/requests');
350:         if (isset($session[$key])) {
351:             $request = clone $session[$key];
352:             unset($session[$key]);
353:             $request->setFlag(PresenterRequest::RESTORED, TRUE);
354:             $this->presenter->terminate(new ForwardingResponse($request));
355:         }
356:     }
357: 
358: 
359: 
360:     /********************* backend ****************d*g**/
361: 
362: 
363: 
364:     /**
365:      * @return Nette\Web\IHttpRequest
366:      */
367:     protected function getHttpRequest()
368:     {
369:         return Environment::getHttpRequest();
370:     }
371: 
372: 
373: 
374:     /**
375:      * @return Nette\Web\IHttpResponse
376:      */
377:     protected function getHttpResponse()
378:     {
379:         return Environment::getHttpResponse();
380:     }
381: 
382: 
383: 
384:     /**
385:      * @return Nette\Web\Session
386:      */
387:     protected function getSession($namespace = NULL)
388:     {
389:         return Environment::getSession($namespace);
390:     }
391: 
392: }
393: 
Nette Framework 0.9.7 API documentation generated by ApiGen 2.3.0