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
![]() |
|||
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 | // Calling a method within a controller? |
||
139 | if (isset($subAction['controller'], $subAction['function'])) |
||
140 | { |
||
141 | 18 | // Instance of a class |
|
142 | if (is_object($subAction['controller'])) |
||
143 | 18 | { |
|
144 | 18 | $controller = $subAction['controller']; |
|
145 | } |
||
146 | else |
||
147 | 18 | { |
|
148 | // Pointer to a controller to load |
||
149 | 18 | $controller = new $subAction['controller'](new EventManager()); |
|
150 | |||
151 | // always set up the environment |
||
152 | 6 | $controller->getHook(); |
|
153 | $controller->setUser(User::$info); |
||
154 | $controller->pre_dispatch(); |
||
155 | } |
||
156 | 18 | ||
157 | // Modify the call accordingly |
||
158 | $call = [$controller, $subAction['function']]; |
||
159 | 6 | } |
|
160 | // Callable directly within the array? Discard invalid entries. |
||
161 | elseif (isset($subAction[0], $subAction[1])) |
||
162 | { |
||
163 | $call = [$subAction[0], $subAction[1]]; |
||
164 | } |
||
165 | |||
166 | 6 | $call(); |
|
167 | 6 | } |
|
168 | |||
169 | /** |
||
170 | 6 | * Security check: verify that the user has the permission to perform the |
|
171 | * given action, and throw an error otherwise. |
||
172 | * |
||
173 | * @param string $sub_id The sub action |
||
174 | 6 | */ |
|
175 | protected function isAllowedTo(string $sub_id): bool |
||
176 | { |
||
177 | 12 | if (isset($this->_subActions[$sub_id]['permission'])) |
|
178 | { |
||
179 | 12 | isAllowedTo($this->_subActions[$sub_id]['permission']); |
|
180 | } |
||
181 | |||
182 | 18 | return true; |
|
183 | 18 | } |
|
184 | } |
||
185 |