Example #1
0
 /**
  * Run application
  *
  * @staticvar boolean $is_init
  * @staticvar array $routes
  * @param $route (optional, ex: 'my/route->action')
  * @return void
  */
 public function run($route = null)
 {
     static $is_init = false;
     static $routes = [];
     // routes stack for current request
     if (!$is_init) {
         $this->log->trace('Initializing', Logger::CATEGORY_DRONE);
         // param default values
         $default = [self::KEY_DEBUG => true, self::KEY_ERROR_BACKTRACE => true, self::KEY_ERROR_HANDLER => ['\\Drone\\Core', 'errorHandler'], self::KEY_ERROR_LOG => false, self::KEY_EXT_TEMPLATE => '.tpl', self::KEY_EXT_WEB => '.htm', self::KEY_PATH_CONTROLLER => PATH_ROOT . '_app/mod', self::KEY_PATH_TEMPLATE => PATH_ROOT . '_app/tpl', self::KEY_PATH_TEMPLATE_GLOBAL => PATH_ROOT . '_app/tpl/_global'];
         // init param default values
         foreach ($default as $k => $v) {
             if (!Registry::has($k)) {
                 Registry::set($k, $v);
             }
         }
         // set default error handler
         if (is_array(Registry::get(self::KEY_ERROR_HANDLER))) {
             set_error_handler(Registry::get(self::KEY_ERROR_HANDLER));
         }
         // init paths
         $this->__formatDir(Registry::get(self::KEY_PATH_CONTROLLER));
         $this->__formatDir(Registry::get(self::KEY_PATH_TEMPLATE));
         $this->__formatDir(Registry::get(self::KEY_PATH_TEMPLATE_GLOBAL));
         $is_init = true;
     }
     Registry::set(self::KEY_ROUTE_CONTROLLER, false);
     // init controller
     if ($route !== null) {
         $routes[] = $route;
         // cache route
         $route = new Route(null, $route);
         Registry::set([self::KEY_ROUTE_CONTROLLER => $route->getController(), self::KEY_ROUTE_CLASS => $route->getClass(), self::KEY_ROUTE_TEMPLATE => $route->getController()]);
         if ($route->isAction()) {
             Registry::set(self::KEY_ROUTE_ACTION, $route->getAction());
         }
         $this->log->trace('Route set: \'' . Registry::get(self::KEY_ROUTE_CONTROLLER) . '\'', Logger::CATEGORY_DRONE);
     } else {
         $is_index = false;
         $request = $_SERVER['REQUEST_URI'];
         $this->log->trace('Process request: \'' . $request . '\'', Logger::CATEGORY_DRONE);
         Registry::set(self::KEY_REQUEST, $request);
         if (($pos = strpos($request, '?')) !== false) {
             $request = substr($request, 0, $pos);
         }
         unset($pos);
         $routes[] = $request;
         if (substr($request, -1) != '/') {
             // ensure request has web extension
             if (substr($request, -strlen(Registry::get(self::KEY_EXT_WEB))) === Registry::get(self::KEY_EXT_WEB)) {
                 // do not allow direct access to index like '/path/index.htm'
                 if (basename($request) === 'index' . Registry::get(self::KEY_EXT_WEB)) {
                     $this->error(self::ERROR_404);
                     // kick direct index request
                     return;
                 }
                 // rm web extension
                 $request = substr($request, 0, strlen($request) - strlen(Registry::get(self::KEY_EXT_WEB)));
             } else {
                 $this->error(self::ERROR_404);
                 // kick request
                 return;
             }
         } else {
             $is_index = true;
         }
         $r = null;
         foreach ($this->__routes as $r) {
             if ($rf = $r->matchFile($request)) {
                 $this->log->trace('Route file loaded: \'' . $r->getController() . '\'', Logger::CATEGORY_DRONE);
                 foreach ($rf as $k => $v) {
                     $r = new Route($k, $v);
                     if ($r->match($request)) {
                         break 2;
                         // match
                     }
                 }
             } else {
                 if ($r->match($request)) {
                     break;
                     // match
                 }
             }
             $r = null;
             // no match
         }
         if ($r) {
             $this->log->trace('Route (mapped) detected: \'' . $r->getPath() . '\'', Logger::CATEGORY_DRONE);
             Registry::set([self::KEY_ROUTE_CONTROLLER => $r->getController(), self::KEY_ROUTE_CLASS => $r->getClass(), self::KEY_ROUTE_TEMPLATE => $r->getController()]);
             if ($r->isAction()) {
                 Registry::set(self::KEY_ROUTE_ACTION, $r->getAction());
             }
             $this->view->setRouteParams($r->getParams());
             // set route params
         }
         unset($r);
         // test static routes
         if (Registry::get(self::KEY_ROUTE_CONTROLLER) === false) {
             $request = str_replace('/', DIRECTORY_SEPARATOR, $request);
             if ($is_index) {
                 $request .= 'index';
             }
             Registry::set([self::KEY_ROUTE_CONTROLLER => $request, self::KEY_ROUTE_TEMPLATE => $request]);
             $this->log->trace('Route (static) detected: \'' . Registry::get(self::KEY_ROUTE_CONTROLLER) . '\'', Logger::CATEGORY_DRONE);
         }
         // cleanup
         unset($is_index, $request);
     }
     if (max(array_count_values($routes)) > 1) {
         $routes = [];
         // reset
         $this->error(self::ERROR_500, 'Route loop detected');
         return;
     }
     // set full paths + extensions
     Registry::set(self::KEY_ROUTE_CONTROLLER, Registry::get(self::KEY_PATH_CONTROLLER) . ltrim(Registry::get(self::KEY_ROUTE_CONTROLLER), DIRECTORY_SEPARATOR) . '.php');
     Registry::set(self::KEY_ROUTE_TEMPLATE, Registry::get(self::KEY_PATH_TEMPLATE) . ltrim(Registry::get(self::KEY_ROUTE_TEMPLATE), DIRECTORY_SEPARATOR) . Registry::get(self::KEY_EXT_TEMPLATE));
     try {
         $this->view->resetTemplate();
         // reset template (for multiple runs like errors)
         $this->view->setDefaultTemplate(Registry::get(self::KEY_ROUTE_TEMPLATE));
         // set default template
         $this->error(false);
         // reset error flag
         if (is_file(Registry::get(self::KEY_ROUTE_CONTROLLER))) {
             ob_start();
             // buffer output
             $this->__hooks(self::HOOK_BEFORE, 'before');
             if (isset($this->__hooks[self::HOOK_BEFORE])) {
                 foreach ($this->__hooks[self::HOOK_BEFORE] as $hook) {
                     require $hook;
                 }
             }
             $this->log->trace('Loading controller: \'' . Registry::get(self::KEY_ROUTE_CONTROLLER) . '\'', Logger::CATEGORY_DRONE);
             require_once Registry::get(self::KEY_ROUTE_CONTROLLER);
             $this->__headersSend();
             // send headers
             $controller_class = Registry::get(self::KEY_ROUTE_CLASS);
             // call controller action
             if (Registry::has(self::KEY_ROUTE_ACTION)) {
                 $this->log->trace('Calling action: \'' . Registry::get(self::KEY_ROUTE_ACTION) . '\' on controller class \'' . $controller_class . '\'', Logger::CATEGORY_DRONE);
                 if (!class_exists($controller_class, false)) {
                     if (count($routes) > 1) {
                         $this->log->fatal('Multiple route controllers not found loop detected', Logger::CATEGORY_DRONE);
                         $this->stop();
                     }
                     $this->error(self::ERROR_500, 'Class \'' . $controller_class . '\' not found when calling route action');
                     return;
                 }
                 if (!method_exists($controller_class, Registry::get(self::KEY_ROUTE_ACTION))) {
                     $this->error(self::ERROR_500, 'Method \'' . $controller_class . '::' . Registry::get(self::KEY_ROUTE_ACTION) . '\' not found when calling route action');
                     return;
                 }
                 // set controller instance
                 $controller = new $controller_class();
                 if (method_exists($controller, '__before')) {
                     $controller->__before();
                 }
                 // call controller action
                 $controller->{Registry::get(self::KEY_ROUTE_ACTION)}();
                 if (method_exists($controller, '__after')) {
                     $controller->__after();
                 }
             } else {
                 if ($this->deny(null)) {
                     $this->error(self::ERROR_404, 'Deny no action');
                     return;
                 }
             }
             unset($controller_class);
             // cleanup
             if (!Registry::get(self::KEY_DEBUG)) {
                 $this->__bufferClean();
             }
             $this->__hooks(self::HOOK_MIDDLE, 'middle');
             if (isset($this->__hooks[self::HOOK_MIDDLE])) {
                 foreach ($this->__hooks[self::HOOK_MIDDLE] as $hook) {
                     require $hook;
                 }
             }
             // view display template
             if (!is_null($this->view->getTemplate())) {
                 $this->log->trace('Loading view template: \'' . $this->view->getTemplate() . '\'', Logger::CATEGORY_DRONE);
                 if (!is_file($this->view->getTemplate())) {
                     $this->error(self::ERROR_500, 'View template \'' . $this->view->getTemplate() . '\' not found');
                     return;
                 }
                 if (isset($controller)) {
                     extract(get_object_vars($controller), EXTR_OVERWRITE);
                 }
                 // extract all view public properties for variable use in template
                 extract(get_object_vars($this->view), EXTR_OVERWRITE);
                 if (strlen($this->view->getTemplateHeader()) > 0) {
                     include $this->view->getTemplateHeader();
                 }
                 require $this->view->getTemplate();
                 if (strlen($this->view->getTemplateFooter()) > 0) {
                     include $this->view->getTemplateFooter();
                 }
             }
             if (!$this->error()) {
                 ob_end_flush();
                 // flush buffer
                 $this->stop();
                 // finalize application
             } else {
                 ob_end_clean();
                 // clean buffer
                 $this->error(self::ERROR_500);
                 // call 500 error handler
             }
         } else {
             $this->error(self::ERROR_404);
         }
     } catch (\Exception $ex) {
         $this->error($ex);
     }
 }