ManiaLib 1.0b1 API Reference

Source for file ActionController.class.php

Documentation is available at ActionController.class.php

  1. <?php
  2. /**
  3.  * MVC framwork magic happens here!
  4.  * 
  5.  * @author Maxime Raoust
  6.  * @copyright 2009-2010 NADEO
  7.  * @package ManiaLib
  8.  * @subpackage MVC
  9.  */
  10.  
  11. /**
  12.  * Action controller
  13.  * This is the base class for all controllers. Extend ActionController to create
  14.  * a new controller for your application.
  15.  * <b>Naming conventions</b>
  16.  * <ul>
  17.  * <li>Controller classes are suffixed by "Controller", naming is regular CamelCase class convention</li>
  18.  * <li>Actions are regular camelCase convention</li>
  19.  * <li>When creating links with the Request engine, use class and method names eg. createLink('SomeController', 'someAction')</li>
  20.  * <li>Views folders and files use the same naming conventions as the classes/methods (eg. view/SomeController/someAction.php)</li>
  21.  * <li>The URLs will be lowercase (camelCase is mapped to underscore-separated names)</li>
  22.  * <li>You can change the default separator ("_") in the config using the APP_MVC_URL_SEPARATOR constant</li>
  23.  * </ul>
  24.  * <b>Example</b>
  25.  * <code>
  26.  * class HomeController extends ActionController
  27.  * {
  28.  *    function __construct()
  29.  *    {
  30.  *        parent::__construct();
  31.  *        $this->addFilter(new RegisterRequestParametersFilter());
  32.  *    }
  33.  *    
  34.  *    function index() {} // mapped by /home/index/
  35.  *    
  36.  *    function anotherAction() {} // mapped by /home/another_action/
  37.  * }
  38.  * </code>
  39.  * @package ManiaLib
  40.  * @subpackage MVC
  41.  */
  42. {
  43.     /**
  44.      * Overrride this to define the controller's default action name
  45.      * @var string 
  46.      */
  47.     protected $defaultAction = APP_MVC_DEFAULT_ACTION;
  48.     /**
  49.      * Current controller name
  50.      */    
  51.     protected $controllerName;
  52.     /**
  53.      * @var array[Filterable] 
  54.      * @ignore
  55.      */
  56.     protected $filters array();
  57.     /**
  58.      * @var array[ReflectionMethod] 
  59.      * @ignore
  60.      */
  61.     protected $reflectionMethods array();
  62.     /**
  63.      * @var RequestEngineMVC 
  64.      */
  65.     protected $request;
  66.     /**
  67.      * @var SessionEngine 
  68.      */
  69.     protected $session;
  70.     /**
  71.      * @var ResponseEngine 
  72.      */
  73.     protected $response;
  74.  
  75.     /**
  76.      * @ignore
  77.      */
  78.     final public static function dispatch()
  79.     {
  80.         $request RequestEngineMVC::getInstance();
  81.         self::getController($request->getController())->launch();
  82.         ResponseEngine::getInstance()->render();
  83.     }
  84.     
  85.     /**
  86.      * @return ActionController 
  87.      * @ignore
  88.      */
  89.     final static public function getController($controllerName)
  90.     {
  91.         $controllerClass $controllerName.'Controller';
  92.         $controllerFilename APP_MVC_CONTROLLERS_PATH.$controllerClass.'.class.php';
  93.  
  94.         if (!file_exists($controllerFilename))
  95.         {
  96.             throw new ControllerNotFoundException($controllerName);
  97.         }
  98.  
  99.         require_once($controllerFilename);
  100.         return new $controllerClass($controllerName);
  101.     }
  102.  
  103.     /**
  104.      * If you want to do stuff at instanciation, override self::onConstruct()
  105.      * @ignore
  106.      */
  107.     function __construct($controllerName)
  108.     {
  109.         $this->controllerName = $controllerName;
  110.         $this->request = RequestEngineMVC::getInstance();
  111.         $this->response = ResponseEngine::getInstance();
  112.         $this->session = SessionEngine::getInstance();
  113.         $this->onConstruct();
  114.     }
  115.     
  116.     /**
  117.      * Stuff to be executed when the controller is instanciated; override this in your controllers
  118.      */
  119.     protected function onConstruct(){}
  120.  
  121.     /**
  122.      * Add a filter to the curent controller
  123.      * Typically you should call that in your controller's onConstruct() method
  124.      * 
  125.      * Example:
  126.      * <code>
  127.      * class SomeStuffController extends ActionController
  128.      * {
  129.      *     //...
  130.      *     function onConstruct()
  131.      *     {
  132.      *            $this->addFilter(new UserAgentCheckFilter());
  133.      *     }
  134.      *     //...
  135.      * }
  136.      * </code>
  137.      */
  138.     final protected function addFilter(Filterable $filter)
  139.     {
  140.         $this->filters[$filter;
  141.     }
  142.  
  143.     /**
  144.      * @return array[Filterable] 
  145.      * @ignore
  146.      */
  147.     final public function getFilters()
  148.     {
  149.         return $this->filters;
  150.     }
  151.  
  152.     /**
  153.      * Executes an action from within another action
  154.      */
  155.     final protected function chainAction($controllerName$actionName)
  156.     {
  157.         if($controllerName==null ||  $controllerName == $this->controllerName)
  158.         {
  159.             $this->checkActionExists($actionName);
  160.             $this->executeAction($actionName);
  161.         }
  162.         else
  163.         {
  164.             $this->executeActionCrossController($controllerName,$actionName);
  165.         }
  166.     }
  167.  
  168.     /**
  169.      * Executes an action from within another action and override the view from the first action
  170.      */
  171.     final protected function chainActionAndView($controllerName$actionName$resetViews true)
  172.     {
  173.         if($resetViews)
  174.         {
  175.             $this->response->resetViews();
  176.         }
  177.         if($controllerName==null || $controllerName == $this->controllerName)
  178.         {
  179.             $this->checkActionExists($actionName);
  180.             $this->response->registerView($this->controllerName$actionName);
  181.             $this->executeAction($actionName);
  182.         }
  183.         else
  184.         {
  185.             $this->response->registerView($controllerName$actionName);
  186.             $this->executeActionCrossController($controllerName$actionName);
  187.         }
  188.     }
  189.  
  190.     /**
  191.      * @ignore
  192.      */
  193.     final public function checkActionExists($actionName)
  194.     {
  195.         if(!array_key_exists($actionName$this->reflectionMethods))
  196.         {
  197.             try
  198.             {
  199.                 $this->reflectionMethods[$actionNamenew ReflectionMethod(get_class($this),$actionName);
  200.             }
  201.             catch(Exception $e)
  202.             {
  203.                 throw new ActionNotFoundException($actionName);
  204.             }
  205.         }
  206.         if(!$this->reflectionMethods[$actionName]->isPublic())
  207.         {
  208.             throw new ActionNotFoundException($actionName.' (Method "'.$actionName.'()" must be public)');
  209.         }
  210.         if($this->reflectionMethods[$actionName]->isFinal())
  211.         {
  212.             throw new Exception($actionName.' (Method "'.$actionName.'()" must not be final)');
  213.         }
  214.     }
  215.  
  216.     /**
  217.      * @ignore
  218.      */
  219.     final protected function executeActionCrossController($controllerName$actionName)
  220.     {
  221.         $controller self::getController($controllerName);
  222.         $controller->checkActionExists($actionName);
  223.         $controllerFilters $controller->getFilters();
  224.         foreach($controllerFilters as $controllerFilter)
  225.         {
  226.             if(!in_array($controllerFilter,$this->filters))
  227.             {
  228.                 $controllerFilter->preFilter();
  229.             }
  230.         }
  231.         $controller->executeAction($actionName);
  232.         foreach($controllerFilters as $controllerFilter)
  233.         {
  234.             if(!in_array($controllerFilter,$this->filters))
  235.             {
  236.                 $controllerFilter->postFilter();
  237.             }
  238.         }
  239.     }
  240.  
  241.     /**
  242.      * @ignore
  243.      */
  244.     final public function executeAction($actionName)
  245.     {
  246.         if(!array_key_exists($actionName$this->reflectionMethods))
  247.         {
  248.             try
  249.             {
  250.                 $this->reflectionMethods[$actionName=
  251.                 new ReflectionMethod(get_class($this),$actionName);
  252.             }
  253.             catch(Exception $e)
  254.             {
  255.                 throw new ActionNotFoundException($actionName);
  256.             }
  257.         }
  258.  
  259.         $callParameters array();
  260.         $requiredParameters $this->reflectionMethods[$actionName]->getParameters();
  261.         foreach($requiredParameters as $parameter)
  262.         {
  263.             if($parameter->isDefaultValueAvailable())
  264.             {
  265.                 $callParameters[$this->request->get($parameter->getName()$parameter->getDefaultValue());
  266.             }
  267.             else
  268.             {
  269.                 $pname $parameter->getName();
  270.                 $pmessage 'Undefined parameter: $<$o'.$pname.'$>';
  271.                 $callParameters[$this->request->getStrict($pname$pmessage);
  272.             }
  273.         }
  274.         
  275.         call_user_func_array(array($this$actionName)$callParameters);
  276.     }
  277.  
  278.     /**
  279.      * @ignore
  280.      */
  281.     final protected function launch()
  282.     {
  283.         $actionName $this->request->getAction($this->defaultAction);
  284.         if(!$actionName$actionName $this->defaultAction;
  285.  
  286.         $this->checkActionExists($actionName);
  287.  
  288.         $this->response->registerView($this->controllerName$actionName);
  289.  
  290.         foreach($this->filters as $filter)
  291.         {
  292.             $filter->preFilter();
  293.         }
  294.  
  295.         $this->executeAction($actionName);
  296.  
  297.         foreach(array_reverse($this->filtersas $filter)
  298.         {
  299.             $filter->postFilter();
  300.         }
  301.     }
  302. }
  303.  
  304. /**
  305.  * @package ManiaLib
  306.  * @subpackage MVC
  307.  * @ignore
  308.  */
  309. class ControllerNotFoundException extends MVCException {}
  310.  
  311. /**
  312.  * @package ManiaLib
  313.  * @subpackage MVC
  314.  * @ignore
  315.  */
  316. class ActionNotFoundException extends MVCException {}
  317.  
  318. ?>