* @version 0.4 * @copyright GNU Lesser General Public License (LGPL) version 3 */ /** * Front Controller * * The is the root class of the application, the mother of initialization process * It's a singleton, defining mostly static methods * @since 0.1 */ class FrontController extends HelpableSingleton { private static $instance; protected $autoPath; public $controller; public $action; public $request; public $settings; public $user; public $db; /** * private constructor (singleton) */ private function __construct() { $this->autoPath = $authoPath = array(); include APP_CONFIG_PATH.'path.php'; $this->autoPath = $autoPath; unset($autoPath); $this->controller = $GLOBALS['config']['app']['default_controller']; $this->action = $GLOBALS['config']['app']['default_action']; $this->request = array(); $this->_helpers = array(); $this->db = array(); if (!isset($_SESSION['appVariables'])) { $_SESSION['appVariables'] = array(); } } /** * the getInstance() method returns a single instance of the object */ public static function getInstance() { if(!isset(self::$instance)){ spl_autoload_register(array('FrontController','autoLoad')); $object= __CLASS__; self::$instance=new $object; self::$instance->initApp(); } return self::$instance; } // ---- APP INITIALIZATION --------------------------------------------------- /** * app initialization (from config) */ protected function initApp() { if (APP_SETUP_DATABASE) { // load up database settings (host, username, etc...) include APP_CONFIG_PATH.'db.php'; // connect to database $this->initDatabase(); } if (APP_SETUP_MESSAGING) { // initialize messaging (trans-pages messages) $this->initMessaging(); } if (APP_SETUP_DATABASE) { // load general settings if (APP_SETUP_GLOBAL_SETTINGS) { $this->loadSettings(); } // load user (if needed) $this->loadUser(APP_SETUP_USER_MODEL); // load user preferences if (APP_SETUP_USER_SETTINGS) { $this->loadUserSettings(); } } if (APP_SETUP_TRANSLATOR) { // initialize translations system $this->initTranslator(); } if (APP_SETUP_NAVI) { // initialize navigation (referers, redirects and URL manipulation) $this->initNavi(); } } /** * initialize database connection */ public function initDatabase() { $i = count($this->db); $this->db[$i] = new DbConnector(); $this->db[$i]->connect(); } /** * load application settings * @todo load settings * @todo set default controller and action */ public function loadSettings() { $this->settings = new SettingModel(); // -TODO- load 'em up } /** * load and authenticate user */ public function loadUser($class) { if (empty($class)) { return false; } $class = StringHelper::flatToCamel($class,true).'Model'; $this->user = new $class; $this->user->enableAuthentication(); $this->user->connectDb(); $this->user->checkLogin(); } /** * load user settings * @todo load user settings and override global settings */ public function loadUserSettings() { // might overload default controller and action // and language // -TODO- if ($this->user->isLoggedIn()) { $this->setSessionDefault('usertask', $this->user->getUid()); } } /** * initialize messaging system */ public function initMessaging() { $this->addHelper('messaging'); } /** * initialize referrers system */ public function initNavi() { $this->addHelper('navi'); } /** * initialize translator */ public function initTranslator() { $this->addHelper('translator'); $this->loadLangConfig(); $this->loadLangFilesFromConfig(); } /** * launch application controller */ public function run() { // parse URL : look for controller, action, parameters... $this->parseUrl(); // load up requested Application Controller $con = self::loadController($this->controller); if (!$con) { // controller not found, throw exception if (isset($GLOBALS['config']['error']['not_found'])) { $this->_sendErrorCodeToRobots('404'); include $GLOBALS['config']['error']['not_found']; exit; } else { try { throw new AppException('Controller '.$this->controller.' not defined in '.implode(', ', $this->autoPath['controller'])); } catch(Exception $e) { self::log_debug('error loading controller '.$this->controller); echo $e; exit; } } } $obj = new $con; $act = $this->action; // if submitted, call requested action (mainReaction by default) if (!empty($_POST)) { if (method_exists($obj, $act.'Reaction')) { if (!call_user_func(array($obj,$act.'Reaction'))) { // stop here return true; } } else { self::log_error('method '.$act.'Reaction not defined in controller '.$this->controller); } } // if still needed, call requested action (mainAction by default) if (method_exists($obj, $act.'Action')) { call_user_func(array($obj, $act.'Action')); } else { if (isset($GLOBALS['config']['error']['not_found'])) { $this->_sendErrorCodeToRobots('404'); include $GLOBALS['config']['error']['not_found']; exit; } self::log_error('method '.$act.'Action not defined in controller '.$this->controller); return false; } return true; } // ---- HTTP QUERY PARSER ---------------------------------------------------- /** * clean $_POST, $_GET and $_REQUEST if magic quotes are on */ protected static function cleanRequest() { if (!get_magic_quotes_gpc()) { return true; } $arrReq = array('_POST','_GET','_REQUEST'); foreach ($arrReq as $var) { if (count($GLOBALS[$var])) { foreach($GLOBALS[$var] as $key => $val) { if (is_string($val)) { $GLOBALS[$var][$key] = stripslashes($val); } } } } return true; } /** * gets HTTP variable * @return null if not found, value if set */ public function getReqVar($key) { if (isset($this->request[$key])) { return $this->request[$key]; } else { return null; } } /** * checks if variable is submitted by HTTP request * @param $mix an array or string containing key(s) to be checked * @return first found in request */ public function chkReqVar($mix) { $arr = StringHelper::mixedToArray($mix); foreach($arr as $key) { if (isset($this->request[$key])) { return $key; } } return false; } /** * parse request for controller, action and other parameters */ public function parseUrl() { // clean ugly magic quotes self::cleanRequest(); $req = $_SERVER['REQUEST_URI']; // remove subfolder setup if non virtual host if (strlen(APP_WWW_URI) > 1) { $req = str_ireplace(APP_WWW_URI,'',$req); } // remove trailing slashes $req = trim($req,'/'); // parse if non empty if ($req) { if ($pos = strrpos($req,'.html')) { $req = substr($req, 0, $pos); } else if ($pos = strrpos($req,'?')) { $req = substr($req, 0, $pos); } $arrReq = explode('/',$req); if (count($arrReq)) { $this->controller = array_shift($arrReq); } if (count($arrReq)) { $this->action = array_shift($arrReq); } else { $this->action = 'main'; } while(count($arrReq)) { $key = array_shift($arrReq); if (count($arrReq)) { $val = array_shift($arrReq); $this->request[$key] = urldecode($val); } else { $this->request[$key] = ''; } } } // parse query string if (count($_REQUEST)) { foreach($_REQUEST as $key => $val) { switch($key) { case 'c' : $this->controller = $val; break; case 'a' : $this->action = $val; break; default : $this->request[$key] = $val; break; } } } // get real names $this->controller = StringHelper::flatToCamel($this->controller, true,'-'); $this->action = StringHelper::flatToCamel($this->action, false,'-'); } /** * generate URL */ public static function getUrl($controller='', $action = '', $params = '') { $url = APP_WWW_URI; if (!$controller) { return $url; } if (@constant('APP_URL_REWRITE')) { $url .= StringHelper::camelToFlat($controller,'-'); if ($action) { $url .= '/'.StringHelper::camelToFlat($action,'-'); } } else { $url .= 'index.php?c='.StringHelper::camelToFlat($controller,'-'); if ($action) { $url .= '&a='.StringHelper::camelToFlat($action,'-'); } } if (is_array($params)) { if (@constant('APP_URL_REWRITE')) { foreach ($params as $key => $val) { $url .= '/'.urlencode($key).'/'.urlencode($val); } } else { foreach ($params as $key => $val) { $url .= '&'.urlencode($key).'='.urlencode($val); } } } return $url; } /** * returns current URL * @param mixed params false if no parameter, true if all current parameters, array to submit other parameters */ public function thisUrl($params=false) { if (is_array($params)) { return self::getUrl($this->controller, $this->action, $params); } else { return self::getUrl($this->controller, $this->action, $params?$this->request:false); } } /** * return navigation menu */ public function menu($id='pages') { $str = '
".parent::__toString().""; return __CLASS__; } }