1*64ab5140SAndreas Gohr<?php 2*64ab5140SAndreas Gohr/** 3*64ab5140SAndreas Gohr * Created by IntelliJ IDEA. 4*64ab5140SAndreas Gohr * User: andi 5*64ab5140SAndreas Gohr * Date: 2/10/17 6*64ab5140SAndreas Gohr * Time: 3:18 PM 7*64ab5140SAndreas Gohr */ 8*64ab5140SAndreas Gohr 9*64ab5140SAndreas Gohrnamespace dokuwiki; 10*64ab5140SAndreas Gohr 11*64ab5140SAndreas Gohruse dokuwiki\Action\AbstractAction; 12*64ab5140SAndreas Gohruse dokuwiki\Action\Exception\ActionDisabledException; 13*64ab5140SAndreas Gohruse dokuwiki\Action\Exception\ActionException; 14*64ab5140SAndreas Gohruse dokuwiki\Action\Exception\FatalException; 15*64ab5140SAndreas Gohruse dokuwiki\Action\Exception\NoActionException; 16*64ab5140SAndreas Gohr 17*64ab5140SAndreas Gohrclass ActionRouter { 18*64ab5140SAndreas Gohr 19*64ab5140SAndreas Gohr /** @var AbstractAction */ 20*64ab5140SAndreas Gohr protected $action; 21*64ab5140SAndreas Gohr 22*64ab5140SAndreas Gohr /** @var ActionRouter */ 23*64ab5140SAndreas Gohr protected $instance; 24*64ab5140SAndreas Gohr 25*64ab5140SAndreas Gohr /** 26*64ab5140SAndreas Gohr * ActionRouter constructor. Singleton, thus protected! 27*64ab5140SAndreas Gohr */ 28*64ab5140SAndreas Gohr protected function __construct() { 29*64ab5140SAndreas Gohr } 30*64ab5140SAndreas Gohr 31*64ab5140SAndreas Gohr /** 32*64ab5140SAndreas Gohr * Get the singleton instance 33*64ab5140SAndreas Gohr * 34*64ab5140SAndreas Gohr * @param bool $reinit 35*64ab5140SAndreas Gohr * @return ActionRouter 36*64ab5140SAndreas Gohr */ 37*64ab5140SAndreas Gohr public function getInstance($reinit = false) { 38*64ab5140SAndreas Gohr if(($this->instance === null) || $reinit) { 39*64ab5140SAndreas Gohr $this->instance = new ActionRouter(); 40*64ab5140SAndreas Gohr } 41*64ab5140SAndreas Gohr return $this->instance; 42*64ab5140SAndreas Gohr } 43*64ab5140SAndreas Gohr 44*64ab5140SAndreas Gohr /** 45*64ab5140SAndreas Gohr * Setup the given action 46*64ab5140SAndreas Gohr * 47*64ab5140SAndreas Gohr * Instantiates the right class, runs permission checks and pre-processing and 48*64ab5140SAndreas Gohr * seta $action 49*64ab5140SAndreas Gohr * 50*64ab5140SAndreas Gohr * @param string $actionname 51*64ab5140SAndreas Gohr * @fixme implement redirect on action change with post 52*64ab5140SAndreas Gohr */ 53*64ab5140SAndreas Gohr protected function setupAction($actionname) { 54*64ab5140SAndreas Gohr try { 55*64ab5140SAndreas Gohr $this->action = $this->loadAction($actionname); 56*64ab5140SAndreas Gohr $this->action->checkPermissions(); 57*64ab5140SAndreas Gohr $this->ensureMinimumPermission($this->action->minimumPermission()); 58*64ab5140SAndreas Gohr $this->action->preProcess(); 59*64ab5140SAndreas Gohr 60*64ab5140SAndreas Gohr } catch(ActionException $e) { 61*64ab5140SAndreas Gohr // we should have gotten a new action 62*64ab5140SAndreas Gohr $newaction = $e->getNewAction(); 63*64ab5140SAndreas Gohr 64*64ab5140SAndreas Gohr // no infinite recursion 65*64ab5140SAndreas Gohr if($newaction === $actionname) { 66*64ab5140SAndreas Gohr // FIXME this doesn't catch larger circles 67*64ab5140SAndreas Gohr $this->handleFatalException(new FatalException('Infinite loop in actions', 500, $e)); 68*64ab5140SAndreas Gohr } 69*64ab5140SAndreas Gohr 70*64ab5140SAndreas Gohr // this one should trigger a user message 71*64ab5140SAndreas Gohr if(is_a($e, ActionDisabledException::class)) { 72*64ab5140SAndreas Gohr msg('Action disabled: ' . hsc($actionname), -1); 73*64ab5140SAndreas Gohr } 74*64ab5140SAndreas Gohr 75*64ab5140SAndreas Gohr // do setup for new action 76*64ab5140SAndreas Gohr $this->setupAction($newaction); 77*64ab5140SAndreas Gohr 78*64ab5140SAndreas Gohr } catch(NoActionException $e) { 79*64ab5140SAndreas Gohr // FIXME here the unknown event needs to be run 80*64ab5140SAndreas Gohr $this->action = $this->loadAction('show'); 81*64ab5140SAndreas Gohr 82*64ab5140SAndreas Gohr } catch(\Exception $e) { 83*64ab5140SAndreas Gohr $this->handleFatalException($e); 84*64ab5140SAndreas Gohr } 85*64ab5140SAndreas Gohr } 86*64ab5140SAndreas Gohr 87*64ab5140SAndreas Gohr /** 88*64ab5140SAndreas Gohr * Check that the given minimum permissions are reached 89*64ab5140SAndreas Gohr * 90*64ab5140SAndreas Gohr * @param int $permneed 91*64ab5140SAndreas Gohr * @throws ActionException 92*64ab5140SAndreas Gohr */ 93*64ab5140SAndreas Gohr protected function ensureMinimumPermission($permneed) { 94*64ab5140SAndreas Gohr global $INFO; 95*64ab5140SAndreas Gohr if($INFO['perm'] < $permneed) { 96*64ab5140SAndreas Gohr throw new ActionException('denied'); 97*64ab5140SAndreas Gohr } 98*64ab5140SAndreas Gohr } 99*64ab5140SAndreas Gohr 100*64ab5140SAndreas Gohr /** 101*64ab5140SAndreas Gohr * Aborts all processing with a message 102*64ab5140SAndreas Gohr * 103*64ab5140SAndreas Gohr * When a FataException instanc is passed, the code is treated as Status code 104*64ab5140SAndreas Gohr * 105*64ab5140SAndreas Gohr * @param \Exception|FatalException $e 106*64ab5140SAndreas Gohr */ 107*64ab5140SAndreas Gohr protected function handleFatalException(\Exception $e) { 108*64ab5140SAndreas Gohr if(is_a($e, FatalException::class)) { 109*64ab5140SAndreas Gohr http_status($e->getCode()); 110*64ab5140SAndreas Gohr } else { 111*64ab5140SAndreas Gohr http_status(500); 112*64ab5140SAndreas Gohr } 113*64ab5140SAndreas Gohr $msg = 'Something unforseen has happened: ' . $e->getMessage(); 114*64ab5140SAndreas Gohr nice_die(hsc($msg)); 115*64ab5140SAndreas Gohr } 116*64ab5140SAndreas Gohr 117*64ab5140SAndreas Gohr /** 118*64ab5140SAndreas Gohr * Load the given action 119*64ab5140SAndreas Gohr * 120*64ab5140SAndreas Gohr * @param $actionname 121*64ab5140SAndreas Gohr * @return AbstractAction 122*64ab5140SAndreas Gohr * @throws NoActionException 123*64ab5140SAndreas Gohr */ 124*64ab5140SAndreas Gohr protected function loadAction($actionname) { 125*64ab5140SAndreas Gohr $class = 'dokuwiki\\Action\\' . ucfirst(strtolower($actionname)); 126*64ab5140SAndreas Gohr if(class_exists($class)) { 127*64ab5140SAndreas Gohr return new $class; 128*64ab5140SAndreas Gohr } 129*64ab5140SAndreas Gohr throw new NoActionException(); 130*64ab5140SAndreas Gohr } 131*64ab5140SAndreas Gohr 132*64ab5140SAndreas Gohr /** 133*64ab5140SAndreas Gohr * Returns the action handling the current request 134*64ab5140SAndreas Gohr * 135*64ab5140SAndreas Gohr * @return AbstractAction 136*64ab5140SAndreas Gohr */ 137*64ab5140SAndreas Gohr public function getAction() { 138*64ab5140SAndreas Gohr return $this->action; 139*64ab5140SAndreas Gohr } 140*64ab5140SAndreas Gohr} 141