<?php namespace elanpl\L3; class Application{ public $Config; // L3 Config object public $Request; // build from received HTTP request public $Response; // response to be send public $Router; // routing engine public $Serialization; // serialization engine public $BaseDirectory; // directory root of the application public $ConfigDirectory; // directory containing application configuration files public $ControllersDirectory; // subdirectory/namespace part added to controller class public $ViewsDirectory; // subdirectory to search for the view files public $ApplicationDirectory; // subdirectory/namespace part of the application //public $Controller; //Active controller //public $Module; //Active module //public $Action; //Active action public function __construct($config){ //set L3 application config $this->Config = $config; //create request object $this->Request = $this->Config->getRequest(); //create router object $this->Router = new Router($this->Config->getRouting()); //create response objcet $this->Response = new Response(); //create serialization object $this->Serialization = new Serialization(); } public function basePath(){ return strstr($_SERVER['REQUEST_URI'], $this->Request->Path, true); } public function relPath($file){ return ($this->Router->depth>0 ? str_repeat("../", substr($this->Request->Path,-1)=='/'?$this->Router->depth:$this->Router->depth-1) : "" ).$file; } public function link($name, $parameters){ return $this->Router->link($name, $parameters); } public function LoadApplicationConfiguration(){ //include routing configuration include_once($this->ConfigDirectory."routing.php"); //include the application configuration include_once($this->ConfigDirectory.'app.php'); } public function LoadConfigFile($file){ //include configuration file return include_once($this->ConfigDirectory.$file); } public function IncludeFromConfigDir($file){ //include configuration file return include($this->ConfigDirectory.$file); } /* //not need - PSR-4 autoload handles that function IncludeControler($Controller){ include_once(_L3_CONTROLLER_PATH.$Controller.'.php'); }*/ public function FindControllerInCallStack($search_level=5){ //search for controller, action and module if present $controller = ""; $module = ""; $action = ""; $match = array(); //analize the call stack $call_stack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, $search_level); for($i=0; $i<$search_level; $i++){ if(preg_match( $pattern = '#('.$this->ApplicationDirectory.')(\\\\(?P<module>.+))?\\\\'.$this->ControllersDirectory.'\\\\(?P<controller>.+)#', $call_stack[$i]['class'], $match ) ){ $action = $call_stack[$i]['function']; $module = $match['module']; $controller = $match['controller']; break; } } return array( 'module' => $module, 'controller' => $controller, 'action' => $action ); } function RunControllerAction($ControllerAction, $Parameters){ //prepare object and action name /* TODO ... if(is_object($this->controler) && (is_a($this->controler,'L2_controler') || is_subclass_of($this->controler,'L2_controler'))){ if(is_string($this->action)){ $controler_object = $this->controler; $controler_action = $this->action; } } else if(is_string($this->controler)){ if(is_string($this->action)){ $this->includeControler($this->controler); $controler_object = new $this->controler(); $controler_action = $this->action; } }*/ if(is_array($ControllerAction)){ //$this->IncludeControler($ControllerAction['controller']); $controller_class = "\\".$this->ApplicationDirectory."\\" .(isset($ControllerAction['module'])?$ControllerAction['module']."\\":"") .$this->ControllersDirectory."\\" .$ControllerAction['controller']; $controller_object = new $controller_class; $controller_action = $ControllerAction['action']; } //fire the action if(isset($controller_object) && isset($controller_action)){ $this->Module = (isset($ControllerAction['module'])?$ControllerAction['module']:""); $this->Controller = $ControllerAction['controller']; $this->Action = $controller_action; // prepare args and start the action if(!isset($reflection)){ $reflection = new \ReflectionMethod($controller_object, $controller_action); } if($reflection->getNumberOfParameters()){ $fire_args=array(); foreach($reflection->getParameters() AS $arg) { if(isset($Parameters[$arg->name]) || (is_array($ControllerAction) && isset($ControllerAction['defaults'][$arg->name]))) if(isset($Parameters[$arg->name])) $fire_args[$arg->name]=$Parameters[$arg->name]; else $fire_args[$arg->name]=$ControllerAction['defaults'][$arg->name]; else { if($arg->isDefaultValueAvailable()){ $fire_args[$arg->name]=$arg->getDefaultValue(); } else{ $fire_args[$arg->name]=null; } } } return $reflection->invokeArgs ($controller_object , $fire_args ); } else{ return $reflection->invoke($controller_object); } } } public function HandleActionResult($result){ if(is_string($result)){ $content = $result; } else if(is_object($result)){ if($result instanceof ViewModel){ if($SerializationContentType = $this->Serialization->Match($this->Request->AcceptTypes, $result)){ $content = $this->Serialization->Serialize($SerializationContentType, $result); if(is_object($content)){ if($content instanceof Response){ $this->Response = $content; unset($content); } } } else{ echo "Serializer not defined for Content-Type: ".$this->Request->Accept."<br>".PHP_EOL; throw new \Exception("Not implemented!"); } } else if($result instanceof View){ $content = $result->render(); } else if($result instanceof Response){ $this->Response = $result; } } if(isset($content)) $this->Response->withBody($content); $this->Response->send(); } public function BeforeAction(){ if(!empty($this->Router->RouteInfo->BeforeAction)){ foreach($this->Router->RouteInfo->BeforeAction as $event_handler){ $this->Router->RouteInfo::EventHandlerFormatCheck($event_handler, $eh); if(isset($eh['class'])){ $object = new $eh['class']; $reflection = new \ReflectionMethod($object, $eh['function']); $fire_args = array(); $fire_args[] = $this->Request; $fire_args[] = $this->Router->RouteInfo; if(isset($eh['arguments'])){ $this->Router->RouteInfo::EventHandlerArgumentsFormatCheck($eh['arguments'], $args); $fire_args = array_merge($fire_args, $args); } $result = $reflection->invokeArgs ($object , $fire_args ); } else if (is_callable($eh['function'])){ throw new \Exception("Not implemented!"); } if(isset($result)){ if(is_object($result)){ if($result instanceof Response){ $this->HandleActionResult($result); exit(); } } } } } } public function Run(){ // Check if routing path is found if($action = $this->Router->match($this->Request)){ // routing match found decide what to do next... // BeforeAction event $this->BeforeAction(); // function -> call it... if(is_callable($action)){ $reflection = new \ReflectionFunction($action); if($reflection->getNumberOfParameters()){ $fire_args=array(); foreach($reflection->getParameters() AS $arg) { if(isset($this->Router->parsedParameters[$arg->name])) $fire_args[$arg->name]=$this->Router->parsedParameters[$arg->name]; else $fire_args[$arg->name]=null; } $result = call_user_func_array($action, $fire_args); } else{ $result = call_user_func($action); } } else if(is_object($action) && is_a($action, 'L2_controler_info')){ // not implemented yet. throw new \Exception("Not implemented!"); ///$action->runControlerAction($this->routing->param); } // array with controller, and action -> run the controller action else if(is_array($action) && array_key_exists('controller',$action) && array_key_exists('action', $action)){ $result = $this->RunControllerAction($action, $this->Router->parsedParameters); } // string else if(is_string($action)){ $result = $action; } // Handle the action result if(isset($result)){ $this->HandleActionResult($result); } } // routing path not found -> generate 404 response else{ echo "Routing not found!<br>".PHP_EOL; throw new \Exception("Not implemented!"); } } }