Source for file jCoordinator.class.php

Documentation is available at jCoordinator.class.php

  1. <?php
  2. /**
  3. @package      jelix
  4. @subpackage   core
  5. @author       Laurent Jouanneau
  6. @contributor  Thibault Piront (nuKs), Julien Issler, Dominique Papin
  7. @copyright    2005-2010 laurent Jouanneau
  8. @copyright    2007 Thibault Piront
  9. @copyright    2008 Julien Issler
  10. @copyright    2008-2010 Dominique Papin
  11. @link         http://www.jelix.org
  12. @licence      GNU Lesser General Public Licence see LICENCE file or http://www.gnu.org/licenses/lgpl.html
  13. */
  14.  
  15. /**
  16.  * the main class of the jelix core
  17.  *
  18.  * this is the "chief orchestra" of the framework. Its goal is
  19.  * to load the configuration, to get the request parameters
  20.  * used to instancie the correspondant controllers and to run the right method.
  21.  * @package  jelix
  22.  * @subpackage core
  23.  */
  24. class jCoordinator {
  25.  
  26.     /**
  27.      * plugin list
  28.      * @var  array 
  29.      */
  30.     public $plugins = array();
  31.  
  32.     /**
  33.      * current response object
  34.      * @var jResponse 
  35.      */
  36.     public $response = null;
  37.  
  38.     /**
  39.      * current request object
  40.      * @var jRequest 
  41.      */
  42.     public $request = null;
  43.  
  44.     /**
  45.      * the selector of the current action
  46.      * @var jSelectorAct 
  47.      */
  48.     public $action = null;
  49.  
  50.     /**
  51.      * the current module name
  52.      * @var string 
  53.      */
  54.     public $moduleName;
  55.  
  56.     /**
  57.      * the current action name
  58.      * @var string 
  59.      */
  60.     public $actionName;
  61.  
  62.     /**
  63.      * List of all errors
  64.      * @var array 
  65.      */
  66.     public $errorMessages=array();
  67.  
  68.     /**
  69.      * List of all log messages
  70.      * @var array 
  71.      * @since 1.0
  72.      */
  73.     public $logMessages=array();
  74.  
  75.     /**
  76.      * @param  string $configFile name of the ini file to configure the framework
  77.      * @param  boolean $enableErrorHandler enable the error handler of jelix.
  78.      *                  keep it to true, unless you have something to debug
  79.      *                  and really have to use the default handler or an other handler
  80.      */
  81.     function __construct ($configFile$enableErrorHandler=true{
  82.         global $gJCoord$gJConfig;
  83.  
  84.         $gJCoord =  $this;
  85.  
  86.         if ($enableErrorHandler{
  87.             set_error_handler('jErrorHandler');
  88.             set_exception_handler('JExceptionHandler');
  89.         }
  90.  
  91.         // load configuration data
  92.         $gJConfig jConfig::load($configFile);
  93.  
  94.         date_default_timezone_set($gJConfig->timeZone);
  95.         $this->_loadPlugins();
  96.     }
  97.  
  98.     /**
  99.      * load the plugins and their configuration file
  100.      */
  101.     private function _loadPlugins(){
  102.         global $gJConfig;
  103.  
  104.         foreach ($gJConfig->coordplugins as $name=>$conf{
  105.             // the config compiler has removed all deactivated plugins
  106.             // so we don't have to check if the value $conf is empty or not
  107.             if ($conf == '1'{
  108.                 $conf array();
  109.             }
  110.             else {
  111.                 $conff JELIX_APP_CONFIG_PATH.$conf;
  112.                 if (false === ($conf parse_ini_file($conff,true)))
  113.                     throw new Exception("Error in the configuration file of plugin $name ($conff)!"13);
  114.             }
  115.             include$gJConfig->_pluginsPathList_coord[$name].$name.'.coord.php');
  116.             $class$name.'CoordPlugin';
  117.             $this->plugins[strtolower($name)new $class($conf);
  118.         }
  119.     }
  120.  
  121.     /**
  122.     * main method : launch the execution of the action.
  123.     *
  124.     * This method should be called in a entry point.
  125.     * @param  jRequest  $request the request object
  126.     */
  127.     public function process ($request){
  128.         global $gJConfig;
  129.  
  130.         $this->request = $request;
  131.         $this->request->init();
  132.         jSession::start();
  133.  
  134.         $this->moduleName = $request->getParam('module');
  135.         $this->actionName = $request->getParam('action');
  136.  
  137.         if(empty($this->moduleName)){
  138.             $this->moduleName = $gJConfig->startModule;
  139.         }
  140.         if(empty($this->actionName)){
  141.             if($this->moduleName == $gJConfig->startModule)
  142.                 $this->actionName = $gJConfig->startAction;
  143.             else {
  144.                 $this->actionName = 'default:index';
  145.             }
  146.         }
  147.  
  148.         jContext::push ($this->moduleName);
  149.         try{
  150.             $this->action = new jSelectorActFast($this->request->type$this->moduleName$this->actionName);
  151.  
  152.             if($gJConfig->modules[$this->moduleName.'.access'2){
  153.                 throw new jException('jelix~errors.module.untrusted',$this->moduleName);
  154.             }
  155.  
  156.             $ctrl $this->getController($this->action);
  157.         }catch(jException $e){
  158.             if ($gJConfig->urlengine['notfoundAct'==''{
  159.                 throw $e;
  160.             }
  161.             try {
  162.                 $this->action = new jSelectorAct($gJConfig->urlengine['notfoundAct']);
  163.                 $ctrl $this->getController($this->action);
  164.             }catch(jException $e2){
  165.                 throw $e;
  166.             }
  167.         }
  168.  
  169.         if (count($this->plugins)) {
  170.             $pluginparams array();
  171.             if(isset($ctrl->pluginParams['*'])){
  172.                 $pluginparams $ctrl->pluginParams['*'];
  173.             }
  174.  
  175.             if(isset($ctrl->pluginParams[$this->action->method])){
  176.                 $pluginparams array_merge($pluginparams$ctrl->pluginParams[$this->action->method]);
  177.             }
  178.  
  179.             foreach ($this->plugins as $name => $obj){
  180.                 $result $this->plugins[$name]->beforeAction ($pluginparams);
  181.                 if($result){
  182.                     $this->action = $result;
  183.                     jContext::pop();
  184.                     jContext::push($result->module);
  185.                     $this->moduleName = $result->module;
  186.                     $this->actionName = $result->resource;
  187.                     $ctrl $this->getController($this->action);
  188.                     break;
  189.                 }
  190.             }
  191.         }
  192.         $this->response = $ctrl->{$this->action->method}();
  193.  
  194.         if($this->response == null){
  195.             throw new jException('jelix~errors.response.missing',$this->action->toString());
  196.         }
  197.  
  198.         foreach ($this->plugins as $name => $obj){
  199.             $this->plugins[$name]->beforeOutput ();
  200.         }
  201.  
  202.         if(!$this->response->output()){
  203.             $this->response->outputErrors();
  204.         }
  205.  
  206.         foreach ($this->plugins as $name => $obj){
  207.             $this->plugins[$name]->afterProcess ();
  208.         }
  209.  
  210.         jContext::pop();
  211.         jSession::end();
  212.     }
  213.  
  214.     /**
  215.      * get the controller corresponding to the selector
  216.      * @param jSelectorAct $selector 
  217.      */
  218.     private function getController($selector){
  219.  
  220.         $ctrlpath $selector->getPath();
  221.         if(!file_exists($ctrlpath)){
  222.             throw new jException('jelix~errors.ad.controller.file.unknown',array($this->actionName,$ctrlpath));
  223.         }
  224.         require_once($ctrlpath);
  225.         $class $selector->getClass();
  226.         if(!class_exists($class,false)){
  227.             throw new jException('jelix~errors.ad.controller.class.unknown',array($this->actionName,$class$ctrlpath));
  228.         }
  229.         $ctrl new $class($this->request);
  230.         if($ctrl instanceof jIRestController){
  231.             $method $selector->method strtolower($_SERVER['REQUEST_METHOD']);
  232.         }elseif(!method_exists($ctrl$selector->method)){
  233.             throw new jException('jelix~errors.ad.controller.method.unknown',array($this->actionName$selector->method$class$ctrlpath));
  234.         }
  235.         return $ctrl;
  236.     }
  237.  
  238.  
  239.     /**
  240.      * instancy a response object corresponding to the default response type
  241.      * of the current resquest
  242.      * @param boolean $originalResponse TRUE to get the original, non overloaded response
  243.      * @return mixed  error string or false
  244.      */
  245.     public function initDefaultResponseOfRequest($originalResponse false){
  246.         if($originalResponse)
  247.             $responses &$GLOBALS['gJConfig']->_coreResponses;
  248.         else
  249.             $responses &$GLOBALS['gJConfig']->responses;
  250.  
  251.         $type $this->request->defaultResponseType;
  252.  
  253.         if(!isset($responses[$type]))
  254.             throw new jException('jelix~errors.default.response.type.unknown',array($this->moduleName.'~'.$this->actionName,$type));
  255.  
  256.         try{
  257.             $respclass $responses[$type];
  258.             require_once ($responses[$type.'.path']);
  259.             $this->response = new $respclass();
  260.             return false;
  261.         }
  262.         catch(Exception $e){
  263.             return $this->initDefaultResponseOfRequest(true);
  264.         }
  265.     }
  266.  
  267.     /**
  268.      * Handle an error event. Called by error handler and exception handler.
  269.      * Responses object should take care of the errorMessages property to display errors.
  270.      * @param string  $toDo    a string which contains keyword indicating what to do with the error
  271.      * @param string  $type    error type : 'error', 'warning', 'notice'
  272.      * @param integer $code    error code
  273.      * @param string  $message error message
  274.      * @param string  $file    the file name where the error appear
  275.      * @param integer $line    the line number where the error appear
  276.      * @param array   $trace   the stack trace
  277.      * @since 1.1
  278.      */
  279.     public function handleError($toDo$type$code$message$file$line$trace){
  280.         global $gJConfig;
  281.         if ($gJConfig)
  282.             $conf $gJConfig->error_handling;
  283.         else {
  284.             $conf array(
  285.                 'messageLogFormat'=>'%date%\t[%code%]\t%msg%\t%file%\t%line%\n\t%url%\n',
  286.                 'quietMessage'=>'A technical error has occured. Sorry for this trouble.',
  287.                 'logFile'=>'error.log',
  288.             );
  289.         }
  290.  
  291.         $url = isset($_SERVER['REQUEST_URI'])?$_SERVER['REQUEST_URI']:'Unknow requested URI';
  292.         // url params including module and action
  293.         if ($this->request{
  294.             $params str_replace("\n"' 'var_export($this->request->paramstrue));
  295.             $remoteAddr $this->request->getIP();
  296.         }
  297.         else {
  298.             $params = isset($_SERVER['QUERY_STRING'])?$_SERVER['QUERY_STRING']:'';
  299.             // When we are in cmdline we need to fix the remoteAddr
  300.             $remoteAddr = isset($_SERVER['REMOTE_ADDR']$_SERVER['REMOTE_ADDR''127.0.0.1';
  301.         }
  302.  
  303.         // formatting message
  304.         $messageLog strtr($conf['messageLogFormat']array(
  305.             '%date%' => @date("Y-m-d H:i:s")// @ because if the timezone is not set, we will have an error here
  306.             '%ip%'   => $remoteAddr,
  307.             '%typeerror%'=>$type,
  308.             '%code%' => $code,
  309.             '%msg%'  => $message,
  310.             '%url%'  => $url,
  311.             '%params%'=>$params,
  312.             '%file%' => $file,
  313.             '%line%' => $line,
  314.             '\t' =>"\t",
  315.             '\n' => "\n"
  316.         ));
  317.  
  318.         $traceLog '';
  319.         if(strpos($toDo 'TRACE'!== false){
  320.             $messageLog.="\ttrace:";
  321.             foreach($trace as $k=>$t){
  322.                 $traceLog.="\n\t$k\t".(isset($t['class'])?$t['class'].$t['type']:'').$t['function']."()\t";
  323.                 $traceLog.=(isset($t['file'])?$t['file']:'[php]').' : '.(isset($t['line'])?$t['line']:'');
  324.             }
  325.             $messageLog.=$traceLog."\n";
  326.         }
  327.  
  328.         // the error should be shown by the response
  329.         $doEchoByResponse true;
  330.  
  331.         if ($this->request == null{
  332.             $message 'JELIX PANIC ! Error during initialization !! '.$message;
  333.             $doEchoByResponse false;
  334.             $toDo.= ' EXIT';
  335.         }
  336.         elseif ($this->response == null{
  337.             try {
  338.                 $this->initDefaultResponseOfRequest();
  339.             }
  340.             catch(Exception $e{
  341.                 $message 'Double error ! 1)'$e->getMessage().'; 2)'.$message;
  342.                 $doEchoByResponse false;
  343.             }
  344.         }
  345.  
  346.         $echoAsked false;
  347.         // traitement du message
  348.         if(strpos($toDo 'ECHOQUIET'!== false){
  349.             $echoAsked true;
  350.             if(!$doEchoByResponse){
  351.                 while (ob_get_level(&& @ob_end_clean());
  352.                 header("HTTP/1.1 500 Internal jelix error");
  353.                 header('Content-type: text/plain');
  354.                 echo 'JELIX PANIC ! Error during initialization !! ';
  355.             }elseif($this->addErrorMsg($type$code$conf['quietMessage']'''''')){
  356.                 $toDo.=' EXIT';
  357.             }
  358.         }elseif(strpos($toDo 'ECHO'!== false){
  359.             $echoAsked true;
  360.             if(!$doEchoByResponse){
  361.                 while (ob_get_level(&& @ob_end_clean());
  362.                 header("HTTP/1.1 500 Internal jelix error");
  363.                 header('Content-type: text/plain');
  364.                 echo $messageLog;
  365.             }elseif($this->addErrorMsg($type$code$message$file$line$traceLog)){
  366.                 $toDo.=' EXIT';
  367.             }
  368.         }
  369.  
  370.         if(strpos($toDo 'LOGFILE'!== false){
  371.             @error_log($messageLog,3JELIX_APP_LOG_PATH.$conf['logFile']);
  372.         }
  373.         if(strpos($toDo 'MAIL'!== false && $gJConfig){
  374.             error_log(wordwrap($messageLog,70),1$conf['email']str_replace(array('\\r','\\n'),array("\r","\n"),$conf['emailHeaders']));
  375.         }
  376.         if(strpos($toDo 'SYSLOG'!== false){
  377.             error_log($messageLog,0);
  378.         }
  379.  
  380.         if(strpos($toDo 'EXIT'!== false){
  381.             if($doEchoByResponse{
  382.                 while (ob_get_level(&& @ob_end_clean());
  383.                 if ($this->response)
  384.                     $this->response->outputErrors();
  385.                 else if($echoAsked{
  386.                     header("HTTP/1.1 500 Internal jelix error");
  387.                     header('Content-type: text/plain');
  388.                     foreach($this->errorMessages as $msg)
  389.                         echo $msg."\n";
  390.                 }
  391.             }
  392.             jSession::end();
  393.             exit(1);
  394.         }
  395.     }
  396.  
  397.     /**
  398.      * Store an error/warning/notice message.
  399.      * @param  string $type  error type : 'error', 'warning', 'notice'
  400.      * @param  integer $code  error code
  401.      * @param  string $message error message
  402.      * @param  string $file    the file name where the error appear
  403.      * @param  integer $line  the line number where the error appear
  404.      * @return boolean    true= the process should stop now, false = the error manager do its job
  405.      */
  406.     protected function addErrorMsg($type$code$message$file$line$trace){
  407.         $this->errorMessages[array($type$code$message$file$line$trace);
  408.         return !$this->response->acceptSeveralErrors();
  409.     }
  410.  
  411.     /**
  412.      * Store a log message. Responses object should take care
  413.      * of the logMessages properties to display them.
  414.      * @param  string $message error message
  415.      * @since 1.0
  416.      */
  417.     public function addLogMsg($message$type='default'){
  418.         $this->logMessages[$type][$message;
  419.     }
  420.  
  421.     /**
  422.     * gets a given plugin if registered
  423.     * @param string   $pluginName   the name of the plugin
  424.     * @param boolean  $required  says if the plugin is required or not. If true, will generate an exception if the plugin is not registered.
  425.     * @return jICoordPlugin 
  426.     */
  427.     public function getPlugin ($pluginName$required true){
  428.         $pluginName strtolower ($pluginName);
  429.         if (isset ($this->plugins[$pluginName])){
  430.             $plugin $this->plugins[$pluginName];
  431.         }else{
  432.             if ($required){
  433.                 throw new jException('jelix~errors.plugin.unregister'$pluginName);
  434.             }
  435.             $plugin null;
  436.         }
  437.         return $plugin;
  438.     }
  439.  
  440.     /**
  441.     * Says if the given plugin $name is enabled
  442.     * @param string $pluginName 
  443.     * @return boolean true : plugin is ok
  444.     */
  445.     public function isPluginEnabled ($pluginName){
  446.         return isset ($this->plugins[strtolower ($pluginName)]);
  447.     }
  448.  
  449.     /**
  450.     * Says if the given module $name is enabled
  451.     * @param string $moduleName 
  452.     * @param boolean $includingExternal  true if we want to know if the module
  453.     *                is also an external module, e.g. in an other entry point
  454.     * @return boolean true : module is ok
  455.     */
  456.     public function isModuleEnabled ($moduleName$includingExternal false{
  457.         if ($includingExternal && isset($GLOBALS['gJConfig']->_externalModulesPathList[$moduleName])) {
  458.             return true;
  459.         }
  460.         return isset($GLOBALS['gJConfig']->_modulesPathList[$moduleName]);
  461.     }
  462.  
  463.     /**
  464.      * return the real path of a module
  465.      * @param string $module a module name
  466.      * @param boolean $includingExternal  true if we want to know if the module
  467.      *                is also an external module, e.g. in an other entry point
  468.      * @return string the corresponding path
  469.      */
  470.     public function getModulePath($module$includingExternal false){
  471.         global $gJConfig;
  472.         if (!isset($gJConfig->_modulesPathList[$module])) {
  473.             if ($includingExternal && isset($gJConfig->_externalModulesPathList[$module])) {
  474.                 return $gJConfig->_externalModulesPathList[$module];
  475.             }
  476.             throw new Exception('getModulePath : invalid module name');
  477.         }
  478.         return $gJConfig->_modulesPathList[$module];
  479.     }
  480. }

Documentation generated on Thu, 19 Sep 2013 00:03:02 +0200 by phpDocumentor 1.4.3