elkarte /
Elkarte
| 1 | <?php |
||
| 2 | |||
| 3 | /** |
||
| 4 | * Defines an action with its associated sub-actions |
||
| 5 | * |
||
| 6 | * @package ElkArte Forum |
||
| 7 | * @copyright ElkArte Forum contributors |
||
| 8 | * @license BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file) |
||
| 9 | * |
||
| 10 | * @version 2.0 dev |
||
| 11 | * |
||
| 12 | */ |
||
| 13 | |||
| 14 | namespace ElkArte; |
||
| 15 | |||
| 16 | use ElkArte\Helper\HttpReq; |
||
| 17 | |||
| 18 | /** |
||
| 19 | * Action class defines an action with its associated sub-actions. |
||
| 20 | * |
||
| 21 | * Object-oriented controllers (with sub-actions) use it to set their action-subaction arrays, and have it call the |
||
| 22 | * right function or method handlers. |
||
| 23 | * |
||
| 24 | * Replaces the sub-actions arrays in every dispatching function. |
||
| 25 | * (the $subActions = ... etc., and calls for $_REQUEST['sa']) |
||
| 26 | * |
||
| 27 | */ |
||
| 28 | class Action |
||
| 29 | { |
||
| 30 | /** @var array All the subactions we understand */ |
||
| 31 | protected $_subActions = []; |
||
| 32 | |||
| 33 | /** @var string The default subAction. */ |
||
| 34 | protected $_default; |
||
| 35 | |||
| 36 | /** @var string A (unique !!) id that triggers a hook */ |
||
| 37 | protected $_name; |
||
| 38 | |||
| 39 | /** @var HttpReq Access to post/get data */ |
||
| 40 | protected $req; |
||
| 41 | |||
| 42 | /** |
||
| 43 | * Constructor! |
||
| 44 | * |
||
| 45 | * @param string|null $name Hook name |
||
| 46 | * @param HttpReq $req Access to post/get data |
||
| 47 | */ |
||
| 48 | public function __construct(string $name = null, $req = null) |
||
| 49 | { |
||
| 50 | $this->_name = $name; |
||
| 51 | $this->req = $req ?: HttpReq::instance(); |
||
| 52 | } |
||
| 53 | |||
| 54 | /** |
||
| 55 | * Initialize the instance with an array of sub-actions. |
||
| 56 | * |
||
| 57 | 18 | * - Sets a valid default action if none is supplied. |
|
| 58 | * - Returns the cleaned subaction or the default action if the subaction is not valid / available |
||
| 59 | 18 | * - Calls generic integration hook integrate_sa_XYZ where XYZ is the optional named passed via new Action('XYZ') |
|
| 60 | 18 | * |
|
| 61 | 18 | * @param array $subActions array of known subactions |
|
| 62 | * The accepted array format is: |
||
| 63 | * 'sub_action name' => 'function name' |
||
| 64 | * or |
||
| 65 | * 'sub_action name' => array('function' => 'function name') |
||
| 66 | * or |
||
| 67 | * 'sub_action name' => array( |
||
| 68 | * 'controller' => 'controller name', |
||
| 69 | * 'function' => 'method name', |
||
| 70 | * 'enabled' => true/false, |
||
| 71 | * 'permission' => area), |
||
| 72 | * or |
||
| 73 | * 'sub_action name' => array( |
||
| 74 | * 'controller object, i.e. $this', |
||
| 75 | * 'method name', |
||
| 76 | * 'enabled' => true/false |
||
| 77 | * 'permission' => area), |
||
| 78 | * or |
||
| 79 | * 'sub_action name' => array( |
||
| 80 | * 'controller' => 'controller name', |
||
| 81 | * 'function' => 'method name', |
||
| 82 | * 'enabled' => true/false, |
||
| 83 | * 'permission' => area) |
||
| 84 | * |
||
| 85 | * If `enabled` is not present, it is assumed to be true. |
||
| 86 | * |
||
| 87 | * @param string $default default action if an unknown sa is requested |
||
| 88 | * @param string $requestParam key to check for the HTTP GET value, defaults to `sa` |
||
| 89 | * |
||
| 90 | * @event integrate_sa_ the name specified in the constructor is appended to this |
||
| 91 | * |
||
| 92 | * @return string the valid subaction |
||
| 93 | */ |
||
| 94 | public function initialize(array $subActions, string $default = '', string $requestParam = 'sa'): string |
||
| 95 | { |
||
| 96 | // Controller action initialized as new Action('xyz'), then call xyz integration hook |
||
| 97 | if ($this->_name !== null) |
||
| 98 | { |
||
| 99 | call_integration_hook('integrate_sa_' . $this->_name, [&$subActions]); |
||
| 100 | } |
||
| 101 | 18 | ||
| 102 | $this->_subActions = array_filter( |
||
| 103 | 18 | $subActions, |
|
| 104 | static function ($subAction) { |
||
| 105 | 12 | if (isset($subAction['disabled']) && ($subAction['disabled'] === true || $subAction['disabled'] === 'true')) |
|
| 106 | { |
||
| 107 | return false; |
||
| 108 | 18 | } |
|
| 109 | 18 | ||
| 110 | return !(isset($subAction['enabled']) && ($subAction['enabled'] === false || $subAction['enabled'] === 'false')); |
||
| 111 | 18 | } |
|
| 112 | ); |
||
| 113 | |||
| 114 | $this->_default = $default ?: key($this->_subActions); |
||
| 115 | |||
| 116 | 18 | $subAction = $this->req->getRequest($requestParam, 'trim|strval', $this->_default); |
|
| 117 | |||
| 118 | return isset($this->_subActions[$subAction]) ? $subAction : $this->_default; |
||
|
0 ignored issues
–
show
Bug
Best Practice
introduced
by
Loading history...
|
|||
| 119 | } |
||
| 120 | |||
| 121 | 18 | /** |
|
| 122 | 18 | * Call the function or method for the selected subaction. |
|
| 123 | * |
||
| 124 | * - Both the controller and the method are set up in the subactions array. |
||
| 125 | 18 | * - If a controller is not specified, the function is assumed to be a regular callable. |
|
| 126 | * - Checks on permission of the $sub_id IF a permission area/check was passed. |
||
| 127 | 18 | * |
|
| 128 | * @param string $sub_id a valid index in the subactions array |
||
| 129 | 18 | */ |
|
| 130 | public function dispatch(string $sub_id): void |
||
| 131 | { |
||
| 132 | $subAction = $this->_subActions[$sub_id] ?? $this->_subActions[$this->_default]; |
||
| 133 | $this->isAllowedTo($sub_id); |
||
| 134 | |||
| 135 | // Start off by assuming that this is a callable of some kind. |
||
| 136 | $call = $subAction['function'] ?? $subAction; |
||
| 137 | |||
| 138 | // Why was this here? It ignores directory location if provided. |
||
| 139 | // if (isset($subAction['file'])) |
||
| 140 | // { |
||
| 141 | 18 | // require_once($subAction['file']); |
|
| 142 | // } |
||
| 143 | 18 | ||
| 144 | 18 | // Calling a method within a controller? |
|
| 145 | if (isset($subAction['controller'], $subAction['function'])) |
||
| 146 | { |
||
| 147 | 18 | // Instance of a class |
|
| 148 | if (is_object($subAction['controller'])) |
||
| 149 | 18 | { |
|
| 150 | $controller = $subAction['controller']; |
||
| 151 | } |
||
| 152 | 6 | else |
|
| 153 | { |
||
| 154 | // Pointer to a controller to load |
||
| 155 | $controller = ($subAction['namespace'] ?? '') . $subAction['controller']; |
||
| 156 | 18 | $controller = new $controller(new EventManager()); |
|
| 157 | |||
| 158 | // always set up the environment |
||
| 159 | 6 | $controller->getHook(); |
|
| 160 | $controller->setUser(User::$info); |
||
| 161 | $controller->pre_dispatch(); |
||
| 162 | } |
||
| 163 | |||
| 164 | // Modify the call accordingly |
||
| 165 | $call = [$controller, $subAction['function']]; |
||
| 166 | 6 | } |
|
| 167 | 6 | // Callable directly within the array? Discard invalid entries. |
|
| 168 | elseif (isset($subAction[0], $subAction[1])) |
||
| 169 | { |
||
| 170 | 6 | $call = [$subAction[0], $subAction[1]]; |
|
| 171 | } |
||
| 172 | |||
| 173 | $call(); |
||
| 174 | 6 | } |
|
| 175 | |||
| 176 | /** |
||
| 177 | 12 | * Security check: verify that the user has the permission to perform the |
|
| 178 | * given action, and throw an error otherwise. |
||
| 179 | 12 | * |
|
| 180 | * @param string $sub_id The sub action |
||
| 181 | */ |
||
| 182 | 18 | protected function isAllowedTo(string $sub_id): bool |
|
| 183 | 18 | { |
|
| 184 | if (isset($this->_subActions[$sub_id]['permission'])) |
||
| 185 | { |
||
| 186 | isAllowedTo($this->_subActions[$sub_id]['permission']); |
||
| 187 | } |
||
| 188 | |||
| 189 | return true; |
||
| 190 | } |
||
| 191 | } |
||
| 192 |