From 50701b661ac16d144bf9c99dce7abc68848c5021 Mon Sep 17 00:00:00 2001 From: Andreas Gohr <andi@splitbrain.org> Date: Sat, 11 Mar 2017 11:20:39 +0100 Subject: [PATCH] better action transitions It should now catch any circular loops (by having a maxiumum recursion depth) and it handles the automatic redirect after save (and others) --- inc/ActionRouter.php | 52 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/inc/ActionRouter.php b/inc/ActionRouter.php index 626731edf..d3ab2772d 100644 --- a/inc/ActionRouter.php +++ b/inc/ActionRouter.php @@ -21,6 +21,12 @@ class ActionRouter { /** @var ActionRouter */ protected $instance; + /** @var int transition counter */ + protected $transitions = 0; + + /** maximum loop */ + const MAX_TRANSITIONS = 5; + /** * ActionRouter constructor. Singleton, thus protected! * @@ -55,7 +61,6 @@ class ActionRouter { * * @param string $actionname * @triggers ACTION_ACT_PREPROCESS - * @fixme implement redirect on action change with post */ protected function setupAction($actionname) { $presetup = $actionname; @@ -70,19 +75,13 @@ class ActionRouter { // we should have gotten a new action $actionname = $e->getNewAction(); - // no infinite recursion - if($actionname == $presetup) { - // FIXME this doesn't catch larger circles - $this->handleFatalException(new FatalException('Infinite loop in actions', 500, $e)); - } - // this one should trigger a user message if(is_a($e, ActionDisabledException::class)) { msg('Action disabled: ' . hsc($presetup), -1); } // do setup for new action - $this->setupAction($actionname); + $this->transitionAction($presetup, $actionname); } catch(NoActionException $e) { // give plugins an opportunity to process the actionname @@ -93,7 +92,7 @@ class ActionRouter { msg('Action unknown: ' . hsc($actionname), -1); $actionname = 'show'; } - $this->setupAction($actionname); + $this->transitionAction($presetup, $actionname); } else { // event said the action should be kept, assume action plugin will handle it later $this->action = new Plugin(); @@ -106,6 +105,41 @@ class ActionRouter { } } + /** + * Transitions from one action to another + * + * Basically just calls setupAction() again but does some checks before. Also triggers + * redirects for POST to show transitions + * + * @param string $from current action name + * @param string $to new action name + * @param null|ActionException $e any previous exception that caused the transition + */ + protected function transitionAction($from, $to, $e = null) { + global $INPUT; + global $ID; + + $this->transitions++; + + // no infinite recursion + if($from == $to) { + $this->handleFatalException(new FatalException('Infinite loop in actions', 500, $e)); + } + + // larger loops will be caught here + if($this->transitions >= self::MAX_TRANSITIONS) { + $this->handleFatalException(new FatalException('Maximum action transitions reached', 500, $e)); + } + + // POST transitions to show should be a redirect + if($to == 'show' && $from != $to && strtolower($INPUT->server->str('REQUEST_METHOD')) == 'post') { + act_redirect($ID, $from); // FIXME we may want to move this function to the class + } + + // do the recursion + $this->setupAction($to); + } + /** * Check that the given minimum permissions are reached * -- GitLab