From 73522543bc6b95590563b07feeb1b3d0113a2018 Mon Sep 17 00:00:00 2001
From: Andreas Gohr <andi@splitbrain.org>
Date: Sat, 11 Mar 2017 12:50:40 +0100
Subject: [PATCH] fixed export action by supporting underscores in actions

Now underscores can be used to have sub actions. The loader will try to
find an exact match first, then begin removing parts from the end until
a matching action is found.
---
 inc/Action/AbstractAction.php | 12 +++++++++---
 inc/Action/Export.php         |  4 +---
 inc/Action/Plugin.php         | 13 -------------
 inc/ActionRouter.php          | 23 ++++++++++++++++++-----
 4 files changed, 28 insertions(+), 24 deletions(-)

diff --git a/inc/Action/AbstractAction.php b/inc/Action/AbstractAction.php
index 4effc1253..4fe6a59a6 100644
--- a/inc/Action/AbstractAction.php
+++ b/inc/Action/AbstractAction.php
@@ -20,10 +20,11 @@ abstract class AbstractAction {
 
     /**
      * AbstractAction constructor.
+     *
+     * @param string $actionname the name of this action (see getActioName() for caveats)
      */
-    public function __construct() {
-        // http://stackoverflow.com/a/27457689/172068
-        $this->actionname = strtolower(substr(strrchr(get_class($this), '\\'), 1));
+    public function __construct($actionname) {
+        $this->actionname = $actionname;
     }
 
     /**
@@ -70,6 +71,11 @@ abstract class AbstractAction {
     }
 
     /**
+     * Returns the name of this action
+     *
+     * This is usually the lowercased class name, but may differ for some actions.
+     * eg. the export_ modes or for the Plugin action.
+     *
      * @return string
      */
     public function getActionName() {
diff --git a/inc/Action/Export.php b/inc/Action/Export.php
index 5e013f3ed..e27f67f57 100644
--- a/inc/Action/Export.php
+++ b/inc/Action/Export.php
@@ -18,8 +18,6 @@ class Export extends AbstractAction {
         return AUTH_READ;
     }
 
-    // FIXME proper mode should be checked
-
     /**
      * Export a wiki page for various formats
      *
@@ -48,7 +46,7 @@ class Export extends AbstractAction {
         // search engines: never cache exported docs! (Google only currently)
         $headers['X-Robots-Tag'] = 'noindex';
 
-        $mode = substr('FIXME', 7); // FIXME how to pass the proper mode?
+        $mode = substr($this->actionname, 7);
         switch($mode) {
             case 'raw':
                 $headers['Content-Type'] = 'text/plain; charset=utf-8';
diff --git a/inc/Action/Plugin.php b/inc/Action/Plugin.php
index 4ab67cfce..fea45f3bb 100644
--- a/inc/Action/Plugin.php
+++ b/inc/Action/Plugin.php
@@ -29,17 +29,4 @@ class Plugin extends AbstractAction {
         }
         $evt->advise_after();
     }
-
-    /**
-     * Set the action name
-     *
-     * This class handles arbitrary names by passing them to action plugins
-     * later in tplContent(). The actual name (=$ACT) is via this function
-     * in ActionRouter::setupAction()
-     *
-     * @param string $actionname
-     */
-    public function setActionName($actionname) {
-        $this->actionname = $actionname;
-    }
 }
diff --git a/inc/ActionRouter.php b/inc/ActionRouter.php
index 8f87ac993..2e7e9a07c 100644
--- a/inc/ActionRouter.php
+++ b/inc/ActionRouter.php
@@ -95,8 +95,7 @@ class ActionRouter {
                 $this->transitionAction($presetup, $actionname);
             } else {
                 // event said the action should be kept, assume action plugin will handle it later
-                $this->action = new Plugin();
-                $this->action->setActionName($actionname);
+                $this->action = new Plugin($actionname);
             }
             $evt->advise_after();
 
@@ -173,15 +172,29 @@ class ActionRouter {
     /**
      * Load the given action
      *
+     * This translates the given name to a class name by uppercasing the first letter.
+     * Underscores translate to camelcase names. For actions with underscores, the different
+     * parts are removed beginning from the end until a matching class is found. The instatiated
+     * Action will always have the full original action set as Name
+     *
+     * Example: 'export_raw' -> ExportRaw then 'export' -> 'Export'
+     *
      * @param $actionname
      * @return AbstractAction
      * @throws NoActionException
      */
     protected function loadAction($actionname) {
-        $class = 'dokuwiki\\Action\\' . ucfirst(strtolower($actionname));
-        if(class_exists($class)) {
-            return new $class;
+        $actionname = strtolower($actionname); // FIXME is this needed here? should we run a cleanup somewhere else?
+        $parts = explode('_', $actionname);
+        while($parts) {
+            $load = join('_', $parts);
+            $class = 'dokuwiki\\Action\\' . str_replace('_', '', ucwords($load, '_'));
+            if(class_exists($class)) {
+                return new $class($actionname);
+            }
+            array_pop($parts);
         }
+
         throw new NoActionException();
     }
 
-- 
GitLab