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, Flav, Gaëtan MARROT
  7. @copyright    2005-2013 laurent Jouanneau
  8. @copyright    2007 Thibault Piront
  9. @copyright    2008 Julien Issler
  10. @copyright    2008-2010 Dominique Papin, 2012 Flav, 2013 Gaëtan MARROT
  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 original action when there is an internal redirection to an action
  52.      * different from the one corresponding to the request
  53.      * @var jSelectorAct 
  54.      */
  55.     public $originalAction = null;
  56.  
  57.     /**
  58.      * the current module name
  59.      * @var string 
  60.      */
  61.     public $moduleName;
  62.  
  63.     /**
  64.      * the current action name
  65.      * @var string 
  66.      */
  67.     public $actionName;
  68.  
  69.     /**
  70.      * the current error message
  71.      * @var jLogErrorMessage 
  72.      */
  73.     protected $errorMessage = null;
  74.  
  75.     /**
  76.      * @param  string|object $config filename of the ini file to configure the framework, or the config object itself
  77.      *               this parameter is optional if jApp::loadConfig has been already called
  78.      * @param  boolean $enableErrorHandler enable the error handler of jelix.
  79.      *                  keep it to true, unless you have something to debug
  80.      *                  and really have to use the default handler or an other handler
  81.      */
  82.     function __construct ($configFile=''$enableErrorHandler=true{
  83.  
  84.         if ($configFile)
  85.             jApp::loadConfig($configFile$enableErrorHandler);
  86.  
  87.         $this->_loadPlugins();
  88.     }
  89.  
  90.     /**
  91.      * load the plugins and their configuration file
  92.      */
  93.     private function _loadPlugins(){
  94.  
  95.         $config jApp::config();
  96.         foreach ($config->coordplugins as $name=>$conf{
  97.             if (strpos($name'.'!== false)
  98.                 continue;
  99.             // the config compiler has removed all deactivated plugins
  100.             // so we don't have to check if the value $conf is empty or not
  101.             if ($conf == '1'{
  102.                 $confname 'coordplugin_'.$name;
  103.                 if (isset($config->$confname))
  104.                     $conf $config->$confname;
  105.                 else
  106.                     $conf array();
  107.             }
  108.             else {
  109.                 $conff jApp::configPath($conf);
  110.                 if (false === ($conf parse_ini_file($conff,true)))
  111.                     throw new Exception("Error in a plugin configuration file -- plugin: $name  file: $conff"13);
  112.             }
  113.             include_once($config->_pluginsPathList_coord[$name].$name.'.coord.php');
  114.             $class$name.'CoordPlugin';
  115.             if (isset($config->coordplugins[$name.'.name']))
  116.                 $name $config->coordplugins[$name.'.name'];
  117.             $this->plugins[strtolower($name)new $class($conf);
  118.         }
  119.     }
  120.  
  121.     /**
  122.     * initialize the given request and some properties of the coordinator
  123.     *
  124.     * It extracts information for the request to set the module name and the
  125.     * action name. It doesn't verify if the corresponding controller does
  126.     * exist or not.
  127.     * It enables also the error handler of Jelix, if needed.
  128.     * Does not call this method directly in entry points. Prefer to call
  129.     * process() instead (that will call setRequest).
  130.     * setRequest is mostly used for tests or specific contexts.
  131.     * @param  jRequest  $request the request object
  132.     * @throw jException if the module is unknown or the action name format is not valid
  133.     * @see jCoordinator::process()
  134.     */
  135.     protected function setRequest ($request{
  136.  
  137.         $config jApp::config();
  138.         $this->request = $request;
  139.  
  140.         if ($config->enableErrorHandler{
  141.             set_error_handler(array($this'errorHandler'));
  142.             set_exception_handler(array($this'exceptionHandler'));
  143.  
  144.             // let's log messages appeared during init
  145.             foreach(jBasicErrorHandler::$initErrorMessages as $msg{
  146.                 jLog::log($msg$msg->getCategory());
  147.             }
  148.         }
  149.  
  150.         $this->request->init();
  151.  
  152.         list($this->moduleName$this->actionName$request->getModuleAction();
  153.         jApp::pushCurrentModule($this->moduleName);
  154.  
  155.         $this->action =
  156.         $this->originalAction = new jSelectorActFast($this->request->type$this->moduleName$this->actionName);
  157.  
  158.         if ($config->modules[$this->moduleName.'.access'2{
  159.             throw new jException('jelix~errors.module.untrusted'$this->moduleName);
  160.         }
  161.     }
  162.  
  163.     /**
  164.     * main method : launch the execution of the action.
  165.     *
  166.     * This method should be called in a entry point.
  167.     *
  168.     * @param  jRequest  $request the request object. It is required if a descendant of jCoordinator did not called setRequest before
  169.     */
  170.     public function process ($request=null{
  171.  
  172.         try {
  173.             if ($request)
  174.                 $this->setRequest($request);
  175.  
  176.             jSession::start();
  177.  
  178.             $ctrl $this->getController($this->action);
  179.         }
  180.         catch (jException $e{
  181.             $config jApp::config();
  182.             if ($config->urlengine['notfoundAct'==''{
  183.                 throw $e;
  184.             }
  185.             if (!jSession::isStarted()) {
  186.                 jSession::start();
  187.             }
  188.             try {
  189.                 $this->action = new jSelectorAct($config->urlengine['notfoundAct']);
  190.                 $ctrl $this->getController($this->action);
  191.             }
  192.             catch(jException $e2{
  193.                 throw $e;
  194.             }
  195.         }
  196.  
  197.         jApp::pushCurrentModule ($this->moduleName);
  198.  
  199.         if (count($this->plugins)) {
  200.             $pluginparams array();
  201.             if(isset($ctrl->pluginParams['*'])){
  202.                 $pluginparams $ctrl->pluginParams['*'];
  203.             }
  204.  
  205.             if(isset($ctrl->pluginParams[$this->action->method])){
  206.                 $pluginparams array_merge($pluginparams$ctrl->pluginParams[$this->action->method]);
  207.             }
  208.  
  209.             foreach ($this->plugins as $name => $obj){
  210.                 $result $this->plugins[$name]->beforeAction ($pluginparams);
  211.                 if($result){
  212.                     $this->action = $result;
  213.                     jApp::popCurrentModule();
  214.                     jApp::pushCurrentModule($result->module);
  215.                     $this->moduleName = $result->module;
  216.                     $this->actionName = $result->resource;
  217.                     $ctrl $this->getController($this->action);
  218.                     break;
  219.                 }
  220.             }
  221.         }
  222.  
  223.         $this->response = $ctrl->{$this->action->method}();
  224.         if($this->response == null){
  225.             throw new jException('jelix~errors.response.missing',$this->action->toString());
  226.         }
  227.  
  228.         foreach ($this->plugins as $name => $obj){
  229.             $this->plugins[$name]->beforeOutput ();
  230.         }
  231.  
  232.         $this->response->output();
  233.  
  234.         foreach ($this->plugins as $name => $obj){
  235.             $this->plugins[$name]->afterProcess ();
  236.         }
  237.  
  238.         jApp::popCurrentModule();
  239.         jSession::end();
  240.     }
  241.  
  242.     /**
  243.      * get the controller corresponding to the selector
  244.      * @param jSelectorAct $selector 
  245.      */
  246.     protected function getController($selector){
  247.  
  248.         $ctrlpath $selector->getPath();
  249.         if(!file_exists($ctrlpath)){
  250.             throw new jException('jelix~errors.ad.controller.file.unknown',array($this->actionName,$ctrlpath));
  251.         }
  252.         require_once($ctrlpath);
  253.         $class $selector->getClass();
  254.         if(!class_exists($class,false)){
  255.             throw new jException('jelix~errors.ad.controller.class.unknown',array($this->actionName,$class$ctrlpath));
  256.         }
  257.         $ctrl new $class($this->request);
  258.         if($ctrl instanceof jIRestController){
  259.             $method $selector->method strtolower($_SERVER['REQUEST_METHOD']);
  260.         }elseif(!is_callable(array($ctrl$selector->method))){
  261.             throw new jException('jelix~errors.ad.controller.method.unknown',array($this->actionName$selector->method$class$ctrlpath));
  262.         }
  263.         return $ctrl;
  264.     }
  265.  
  266.     /**
  267.      * says if the currently executed action is the original one
  268.      * @return boolean  true if yes
  269.      */
  270.     public function execOriginalAction({
  271.         if (!$this->originalAction{
  272.             return false;
  273.         }
  274.         return $this->originalAction->isEqualTo($this->action);
  275.     }
  276.  
  277.     /**
  278.      * Error handler using a response object to return the error.
  279.      * Replace the default PHP error handler.
  280.      * @param   integer     $errno      error code
  281.      * @param   string      $errmsg     error message
  282.      * @param   string      $filename   filename where the error appears
  283.      * @param   integer     $linenum    line number where the error appears
  284.      * @param   array       $errcontext 
  285.      * @since 1.4
  286.      */
  287.     function errorHandler($errno$errmsg$filename$linenum$errcontext{
  288.  
  289.         if (error_reporting(== 0)
  290.             return;
  291.  
  292.         if (preg_match('/^\s*\((\d+)\)(.+)$/'$errmsg$m)) {
  293.             $code $m[1];
  294.             $errmsg $m[2];
  295.         }
  296.         else {
  297.             $code 1;
  298.         }
  299.  
  300.         if (!isset (jBasicErrorHandler::$errorCode[$errno])){
  301.             $errno E_ERROR;
  302.         }
  303.         $codestr jBasicErrorHandler::$errorCode[$errno];
  304.  
  305.         $trace debug_backtrace();
  306.         array_shift($trace);
  307.         $this->handleError($codestr$errno$errmsg$filename$linenum$trace);
  308.     }
  309.  
  310.     /**
  311.      * Exception handler using a response object to return the error
  312.      * Replace the default PHP Exception handler
  313.      * @param   Exception   $e  the exception object
  314.      * @since 1.4
  315.      */
  316.     function exceptionHandler($e{
  317.         $this->handleError('error'$e->getCode()$e->getMessage()$e->getFile(),
  318.                           $e->getLine()$e->getTrace());
  319.     }
  320.  
  321.     /**
  322.      * Handle an error event. Called by error handler and exception handler.
  323.      * @param string  $type    error type : 'error', 'warning', 'notice'
  324.      * @param integer $code    error code
  325.      * @param string  $message error message
  326.      * @param string  $file    the file name where the error appear
  327.      * @param integer $line    the line number where the error appear
  328.      * @param array   $trace   the stack trace
  329.      * @since 1.1
  330.      */
  331.     public function handleError($type$code$message$file$line$trace){
  332.  
  333.         $errorLog new jLogErrorMessage($type$code$message$file$line$trace);
  334.  
  335.         $errorLog->setFormat(jApp::config()->error_handling['messageLogFormat']);
  336.         jLog::log($errorLog$type);
  337.  
  338.         // if non fatal error, it is finished, continue the execution of the action
  339.         if ($type != 'error')
  340.             return;
  341.  
  342.         $this->errorMessage = $errorLog;
  343.  
  344.         while (ob_get_level(&& @ob_end_clean());
  345.  
  346.         $resp $this->request->getErrorResponse($this->response);
  347.         $resp->outputErrors();
  348.         jSession::end();
  349.  
  350.         exit(1);
  351.     }
  352.  
  353.     /**
  354.      * return the generic error message (errorMessage in the configuration).
  355.      * Replaced the %code% pattern in the message by the current error code
  356.      * @return string 
  357.      */
  358.     public function getGenericErrorMessage({
  359.         $msg jApp::config()->error_handling['errorMessage'];
  360.         if ($this->errorMessage)
  361.             $code $this->errorMessage->getCode();
  362.         else $code '';
  363.         return str_replace('%code%'$code$msg);
  364.     }
  365.  
  366.     /**
  367.      * @return jLogErrorMessage  the current error
  368.      * @since 1.3a1
  369.      */
  370.     public function getErrorMessage({
  371.         return $this->errorMessage;
  372.     }
  373.  
  374.     /**
  375.     * gets a given coordinator plugin if registered
  376.     * @param string   $pluginName   the name of the plugin
  377.     * @param boolean  $required  says if the plugin is required or not. If true, will generate an exception if the plugin is not registered.
  378.     * @return jICoordPlugin 
  379.     */
  380.     public function getPlugin ($pluginName$required true){
  381.         $pluginName strtolower ($pluginName);
  382.         if (isset ($this->plugins[$pluginName])){
  383.             $plugin $this->plugins[$pluginName];
  384.         }else{
  385.             if ($required){
  386.                 throw new jException('jelix~errors.plugin.unregister'$pluginName);
  387.             }
  388.             $plugin null;
  389.         }
  390.         return $plugin;
  391.     }
  392.  
  393.     /**
  394.     * Says if the given coordinator plugin $name is enabled
  395.     * @param string $pluginName 
  396.     * @return boolean true : plugin is ok
  397.     */
  398.     public function isPluginEnabled ($pluginName){
  399.         return isset ($this->plugins[strtolower ($pluginName)]);
  400.     }
  401. }

Documentation generated on Wed, 04 Jan 2017 22:52:53 +0100 by phpDocumentor 1.4.3