Packages

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

Classes

  • NAppForm
  • NApplication
  • NCliRouter
  • NControl
  • NDownloadResponse
  • NForwardingResponse
  • NJsonResponse
  • NLink
  • NMultiRouter
  • NPresenter
  • NPresenterComponent
  • NPresenterLoader
  • NPresenterRequest
  • NRedirectingResponse
  • NRenderResponse
  • NRoute
  • NSimpleRouter

Interfaces

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

Exceptions

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