3 namespace Org\Mxchange\CoreFramework\Controller;
5 // Import framework stuff
6 use Org\Mxchange\CoreFramework\Chain\Filter\InvalidFilterChainException;
7 use Org\Mxchange\CoreFramework\Factory\Object\ObjectFactory;
8 use Org\Mxchange\CoreFramework\Filter\Filterable;
9 use Org\Mxchange\CoreFramework\Object\BaseFrameworkSystem;
10 use Org\Mxchange\CoreFramework\Registry\GenericRegistry;
11 use Org\Mxchange\CoreFramework\Registry\Registerable;
12 use Org\Mxchange\CoreFramework\Request\Requestable;
13 use Org\Mxchange\CoreFramework\Response\Responseable;
14 use Org\Mxchange\CoreFramework\Traits\Resolver\ResolverTrait;
17 * A generic controller class. You should extend this base class if you want to
18 * write your own controller. You get the advantage that you can use the pre and
21 * @author Roland Haeder <webmaster@shipsimu.org>
23 * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2023 Core Developer Team
24 * @license GNU GPL 3.0 or any newer version
25 * @link http://www.shipsimu.org
27 * This program is free software: you can redistribute it and/or modify
28 * it under the terms of the GNU General Public License as published by
29 * the Free Software Foundation, either version 3 of the License, or
30 * (at your option) any later version.
32 * This program is distributed in the hope that it will be useful,
33 * but WITHOUT ANY WARRANTY; without even the implied warranty of
34 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35 * GNU General Public License for more details.
37 * You should have received a copy of the GNU General Public License
38 * along with this program. If not, see <http://www.gnu.org/licenses/>.
40 abstract class BaseController extends BaseFrameworkSystem implements Registerable {
44 // Exception constants
45 const EXCEPTION_FILTER_CHAIN_INVALID = 0xf10;
47 // Names of controller's own filter chains
48 const FILTER_CHAIN_PRE_COMMAND = 'controller_pre_command';
49 const FILTER_CHAIN_POST_COMMAND = 'controller_post_command';
52 * Generic filter chains
54 private $filterChains = [];
57 * Protected constructor
59 * @param $className Name of the class
62 protected function __construct (string $className) {
63 // Call parent constructor
64 parent::__construct($className);
66 // Initialize both filter chains
67 $this->initFilterChain(self::FILTER_CHAIN_PRE_COMMAND);
68 $this->initFilterChain(self::FILTER_CHAIN_POST_COMMAND);
70 // Add this controller to the registry
71 GenericRegistry::getRegistry()->addInstance('controller', $this);
75 * Executes a command with pre and post filters
77 * @param $requestInstance A Requestable class
78 * @param $responseInstance A Responseable class
81 public function executeGenericPrePostCommand (Requestable $requestInstance, Responseable $responseInstance) {
82 // Get the command instance from the resolver by sending a request instance to the resolver
83 $commandInstance = $this->getResolverInstance()->resolveCommandByRequest($requestInstance);
85 // Add more filters by the command
86 $commandInstance->addExtraFilters($this, $requestInstance);
88 // Run the pre filters
89 $this->executePreFilters($requestInstance, $responseInstance);
91 // This request was valid! :-D
92 $requestInstance->setIsRequestValid(TRUE);
94 // Execute the command
95 $commandInstance->execute($requestInstance, $responseInstance);
97 // Run the post filters
98 $this->executePostFilters($requestInstance, $responseInstance);
100 // Flush the response out
101 $responseInstance->flushBuffer();
105 * Handles the given request and response, redirects to login_failed if
106 * UserAuthorizationException is thrown.
108 * @param $requestInstance An instance of a Requestable class
109 * @param $responseInstance An instance of a Responseable class
112 public function genericHanleRequestLoginFailedRedirect (Requestable $requestInstance, Responseable $responseInstance) {
113 // Get the "form action"
114 $formAction = $requestInstance->getRequestElement('form');
116 // Get command instance from resolver
117 $commandInstance = $this->getResolverInstance()->resolveCommand('Org\Mxchange\CoreFramework\Command\Failed', $formAction);
119 // Add more filters by the command
120 $commandInstance->addExtraFilters($this, $requestInstance);
122 // Try to run the pre filters, if auth exceptions come through redirect here
124 // Run the pre filters
125 $this->executePreFilters($requestInstance, $responseInstance);
126 } catch (UserAuthorizationException $e) {
127 // Redirect to main page
128 $responseInstance->redirectToConfiguredUrl('login_failed');
135 * Is the request still valid? Post filters shall only be executed of
136 * the request is valid
138 if ($requestInstance->isRequestValid()) {
139 // Execute the command
140 $commandInstance->execute($requestInstance, $responseInstance);
142 // Execute *very* generic post filters
143 $this->executePostFilters($requestInstance, $responseInstance);
146 // Flush the buffer out
147 $responseInstance->flushBuffer();
151 * Generic execute of the command: pre and post filters with redirect
152 * but request becomes valid after pre-filters run.
154 * @param $requestInstance An instance of a Requestable class
155 * @param $responseInstance An instance of a Responseable class
158 public function genericHanleRequestLoginAreaFailedRedirect (Requestable $requestInstance, Responseable $responseInstance) {
159 // Get the command instance from the resolver by sending a request instance to the resolver
160 $commandInstance = $this->getResolverInstance()->resolveCommandByRequest($requestInstance);
162 // Add more filters by the command
163 $commandInstance->addExtraFilters($this, $requestInstance);
165 // Try to run the pre filters, if auth exceptions come through redirect here
167 // Run the pre filters
168 $this->executePreFilters($requestInstance, $responseInstance);
169 } catch (UserAuthorizationException $e) {
170 // Redirect to main page
171 $responseInstance->redirectToConfiguredUrl('login_failed');
177 // This request was valid! :-D
178 $requestInstance->setIsRequestValid(TRUE);
180 // Execute the command
181 $commandInstance->execute($requestInstance, $responseInstance);
183 // Run the post filters
184 $this->executePostFilters($requestInstance, $responseInstance);
186 // Flush the response out
187 $responseInstance->flushBuffer();
191 * Private method to initialize a given filter chain
193 * @param $filterChain Name of the filter chain
196 protected function initFilterChain (string $filterChain) {
197 //* DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('CONTROLLER: ' . $filterChain . ' init: START');
198 $this->filterChains[$filterChain] = ObjectFactory::createObjectByConfiguredName('filter_chain_class');
199 //* DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('CONTROLLER: ' . $filterChain . ' init: FINISHED');
203 * Adds a filter to a given filter chain
205 * @param $filterChain Chain of the filter
206 * @param $filterInstance An instance of a filter
208 * @throws InvalidFilterChainException If the filter chain is invalid
210 protected function addFilter (string $filterChain, Filterable $filterInstance) {
211 //* DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('CONTROLLER: ' . $filterChain . ',' . $filterInstance->__toString(). ' add: START');
213 // Test if the filter is there
214 if (!isset($this->filterChains[$filterChain])) {
215 // Throw an exception here
216 throw new InvalidFilterChainException(array($this, $filterChain), self::EXCEPTION_FILTER_CHAIN_INVALID);
220 $this->filterChains[$filterChain]->addFilter($filterInstance);
221 //* DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('CONTROLLER: ' . $filterChain . ',' . $filterInstance->__toString(). ' add: FINISH');
225 * Adds a filter to the pre filter chain
227 * @param $filterInstance An instance of a filter
230 public function addPreFilter (Filterable $filterInstance) {
231 // Add the pre filter
232 $this->addFilter(self::FILTER_CHAIN_PRE_COMMAND, $filterInstance);
236 * Adds a filter to the post filter chain
238 * @param $filterInstance An instance of a filter
241 public function addPostFilter (Filterable $filterInstance) {
242 // Add the post filter
243 $this->addFilter(self::FILTER_CHAIN_POST_COMMAND, $filterInstance);
247 * Add a shutdown filter
249 * @param $filterInstance A Filterable class
252 public function addShutdownFilter (Filterable $filterInstance) {
253 $this->addFilter('shutdown', $filterInstance);
257 * Executes given filter chain chain
259 * @param $filterChain Chain of the filter to execute
260 * @param $requestInstance An instance of a Requestable class
261 * @param $responseInstance An instance of a Responseable class
263 * @throws InvalidFilterChainException If the filter chain is invalid
265 protected function executeFilters (string $filterChain, Requestable $requestInstance, Responseable $responseInstance) {
266 // Test if the filter is there
267 if (!isset($this->filterChains[$filterChain])) {
268 // Throw an exception here
269 throw new InvalidFilterChainException(array($this, $filterChain), self::EXCEPTION_FILTER_CHAIN_INVALID);
273 $this->filterChains[$filterChain]->processFilters($requestInstance, $responseInstance);
277 * Executes all pre filters
279 * @param $requestInstance An instance of a Requestable class
280 * @param $responseInstance An instance of a Responseable class
283 protected function executePreFilters (Requestable $requestInstance, Responseable $responseInstance) {
284 // Execute all pre filters
285 $this->executeFilters(self::FILTER_CHAIN_PRE_COMMAND, $requestInstance, $responseInstance);
289 * Executes all post filters
291 * @param $requestInstance An instance of a Requestable class
292 * @param $responseInstance An instance of a Responseable class
295 protected function executePostFilters (Requestable $requestInstance, Responseable $responseInstance) {
296 // Execute all post filters
297 $this->executeFilters(self::FILTER_CHAIN_POST_COMMAND, $requestInstance, $responseInstance);
301 * Executes all shutdown filters
303 * @param $requestInstance A Requestable class
304 * @param $responseInstance A Responseable class
307 public function executeShutdownFilters (Requestable $requestInstance, Responseable $responseInstance) {
308 $this->executeFilters('shutdown', $requestInstance, $responseInstance);