abaace75c9370f83bbc8d6df01f20f5b10dae31b
[core.git] / inc / main / classes / controller / class_BaseController.php
1 <?php
2 // Own namespace
3 namespace CoreFramework\Controller;
4
5 // Import framework stuff
6 use CoreFramework\Factory\ObjectFactory;
7 use CoreFramework\Object\BaseFrameworkSystem;
8 use CoreFramework\Registry\Generic\Registry;
9 use CoreFramework\Registry\Registerable;
10
11 /**
12  * A generic controller class. You should extend this base class if you want to
13  * write your own controller. You get the advantage that you can use the pre and
14  * post filters.
15  *
16  * @author              Roland Haeder <webmaster@shipsimu.org>
17  * @version             0.0.0
18  * @copyright   Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2017 Core Developer Team
19  * @license             GNU GPL 3.0 or any newer version
20  * @link                http://www.shipsimu.org
21  *
22  * This program is free software: you can redistribute it and/or modify
23  * it under the terms of the GNU General Public License as published by
24  * the Free Software Foundation, either version 3 of the License, or
25  * (at your option) any later version.
26  *
27  * This program is distributed in the hope that it will be useful,
28  * but WITHOUT ANY WARRANTY; without even the implied warranty of
29  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
30  * GNU General Public License for more details.
31  *
32  * You should have received a copy of the GNU General Public License
33  * along with this program. If not, see <http://www.gnu.org/licenses/>.
34  */
35 class BaseController extends BaseFrameworkSystem implements Registerable {
36         // Exception constants
37         const EXCEPTION_FILTER_CHAIN_INVALID = 0xf10;
38
39         // Names of controller's own filter chains
40         const FILTER_CHAIN_PRE_COMMAND  = 'controller_pre_command';
41         const FILTER_CHAIN_POST_COMMAND = 'controller_post_command';
42
43         /**
44          * Generic filter chains
45          */
46         private $filterChains = array();
47
48         /**
49          * Protected constructor
50          *
51          * @param       $className      Name of the class
52          * @return      void
53          */
54         protected function __construct ($className) {
55                 // Call parent constructor
56                 parent::__construct($className);
57
58                 // Initialize both filter chains
59                 $this->initFilterChain(self::FILTER_CHAIN_PRE_COMMAND);
60                 $this->initFilterChain(self::FILTER_CHAIN_POST_COMMAND);
61
62                 // Add this controller to the registry
63                 Registry::getRegistry()->addInstance('controller', $this);
64         }
65
66         /**
67          * Executes a command with pre and post filters
68          *
69          * @param       $requestInstance        A Requestable class
70          * @param       $responseInstance       A Responseable class
71          * @return      void
72          */
73         public function executeGenericPrePostCommand (Requestable $requestInstance, Responseable $responseInstance) {
74                 // Get the command instance from the resolver by sending a request instance to the resolver
75                 $commandInstance = $this->getResolverInstance()->resolveCommandByRequest($requestInstance);
76
77                 // Add more filters by the command
78                 $commandInstance->addExtraFilters($this, $requestInstance);
79
80                 // Run the pre filters
81                 $this->executePreFilters($requestInstance, $responseInstance);
82
83                 // This request was valid! :-D
84                 $requestInstance->requestIsValid();
85
86                 // Execute the command
87                 $commandInstance->execute($requestInstance, $responseInstance);
88
89                 // Run the post filters
90                 $this->executePostFilters($requestInstance, $responseInstance);
91
92                 // Flush the response out
93                 $responseInstance->flushBuffer();
94         }
95
96         /**
97          * Handles the given request and response, redirects to login_failed if
98          * UserAuthorizationException is thrown.
99          *
100          * @param       $requestInstance        An instance of a request class
101          * @param       $responseInstance       An instance of a response class
102          * @return      void
103          */
104         public function genericHanleRequestLoginFailedRedirect (Requestable $requestInstance, Responseable $responseInstance) {
105                 // Get the "form action"
106                 $formAction = $requestInstance->getRequestElement('form');
107
108                 // Get command instance from resolver
109                 $commandInstance = $this->getResolverInstance()->resolveCommand($formAction);
110
111                 // Add more filters by the command
112                 $commandInstance->addExtraFilters($this, $requestInstance);
113
114                 // Try to run the pre filters, if auth exceptions come through redirect here
115                 try {
116                         // Run the pre filters
117                         $this->executePreFilters($requestInstance, $responseInstance);
118                 } catch (UserAuthorizationException $e) {
119                         // Redirect to main page
120                         $responseInstance->redirectToConfiguredUrl('login_failed');
121
122                         // Exit here
123                         exit();
124                 }
125
126                 /*
127                  * Is the request still valid? Post filters shall only be executed of
128                  * the request is valid
129                  */
130                 if ($requestInstance->isRequestValid()) {
131                         // Execute the command
132                         $commandInstance->execute($requestInstance, $responseInstance);
133
134                         // Execute *very* generic ppost filters
135                         $this->executePostFilters($requestInstance, $responseInstance);
136                 } // END - if
137
138                 // Flush the buffer out
139                 $responseInstance->flushBuffer();
140         }
141
142         /**
143          * Generic execute of the command: pre and post filters with redirect
144          * but request becomes valid after pre-filters run.
145          *
146          * @param       $requestInstance        An instance of a request class
147          * @param       $responseInstance       An instance of a response class
148          * @return      void
149          */
150         public function genericHanleRequestLoginAreaFailedRedirect (Requestable $requestInstance, Responseable $responseInstance) {
151                 // Get the command instance from the resolver by sending a request instance to the resolver
152                 $commandInstance = $this->getResolverInstance()->resolveCommandByRequest($requestInstance);
153
154                 // Add more filters by the command
155                 $commandInstance->addExtraFilters($this, $requestInstance);
156
157                 // Try to run the pre filters, if auth exceptions come through redirect here
158                 try {
159                         // Run the pre filters
160                         $this->executePreFilters($requestInstance, $responseInstance);
161                 } catch (UserAuthorizationException $e) {
162                         // Redirect to main page
163                         $responseInstance->redirectToConfiguredUrl('login_failed');
164
165                         // Exit here
166                         exit();
167                 }
168
169                 // This request was valid! :-D
170                 $requestInstance->requestIsValid();
171
172                 // Execute the command
173                 $commandInstance->execute($requestInstance, $responseInstance);
174
175                 // Run the pre filters
176                 $this->executePostFilters($requestInstance, $responseInstance);
177
178                 // Flush the response out
179                 $responseInstance->flushBuffer();
180         }
181
182         /**
183          * Private method to initialize a given filter chain
184          *
185          * @param       $filterChain    Name of the filter chain
186          * @return      void
187          */
188         protected function initFilterChain ($filterChain) {
189                 //* DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('CONTROLLER: ' . $filterChain . ' init: START');
190                 $this->filterChains[$filterChain] = ObjectFactory::createObjectByConfiguredName('filter_chain_class');
191                 //* DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('CONTROLLER: ' . $filterChain . ' init: FINISHED');
192         }
193
194         /**
195          * Adds a filter to a given filter chain
196          *
197          * @param       $filterChain    Chain of the filter
198          * @param       $filterInstance         An instance of a filter
199          * @return      void
200          * @throws      InvalidFilterChainException     If the filter chain is invalid
201          */
202         protected function addFilter ($filterChain, Filterable $filterInstance) {
203                 //* DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('CONTROLLER: ' . $filterChain . ',' . $filterInstance->__toString(). ' add: START');
204
205                 // Test if the filter is there
206                 if (!isset($this->filterChains[$filterChain])) {
207                         // Throw an exception here
208                         throw new InvalidFilterChainException(array($this, $filterChain), self::EXCEPTION_FILTER_CHAIN_INVALID);
209                 } // END - if
210
211                 // Add the filter
212                 $this->filterChains[$filterChain]->addFilter($filterInstance);
213                 //* DEBUG: */ self::createDebugInstance(__CLASS__)->debugOutput('CONTROLLER: ' . $filterChain . ',' . $filterInstance->__toString(). ' add: FINISH');
214         }
215
216         /**
217          * Adds a filter to the pre filter chain
218          *
219          * @param       $filterInstance         An instance of a filter
220          * @return      void
221          */
222         public function addPreFilter (Filterable $filterInstance) {
223                 // Add the pre filter
224                 $this->addFilter(self::FILTER_CHAIN_PRE_COMMAND, $filterInstance);
225         }
226
227         /**
228          * Adds a filter to the post filter chain
229          *
230          * @param       $filterInstance         An instance of a filter
231          * @return      void
232          */
233         public function addPostFilter (Filterable $filterInstance) {
234                 // Add the post filter
235                 $this->addFilter(self::FILTER_CHAIN_POST_COMMAND, $filterInstance);
236         }
237
238         /**
239          * Add a shutdown filter
240          *
241          * @param       $filterInstance         A Filterable class
242          * @return      void
243          */
244         public function addShutdownFilter (Filterable $filterInstance) {
245                 $this->addFilter('shutdown', $filterInstance);
246         }
247
248         /**
249          * Executes given filter chain chain
250          *
251          * @param       $filterChain            Chain of the filter to execute
252          * @param       $requestInstance        An instance of a request class
253          * @param       $responseInstance       An instance of a response class
254          * @return      void
255          * @throws      InvalidFilterChainException     If the filter chain is invalid
256          */
257         protected function executeFilters ($filterChain, Requestable $requestInstance, Responseable $responseInstance) {
258                 // Test if the filter is there
259                 if (!isset($this->filterChains[$filterChain])) {
260                         // Throw an exception here
261                         throw new InvalidFilterChainException(array($this, $filterChain), self::EXCEPTION_FILTER_CHAIN_INVALID);
262                 } // END - if
263
264                 // Run all filters
265                 $this->filterChains[$filterChain]->processFilters($requestInstance, $responseInstance);
266         }
267
268         /**
269          * Executes all pre filters
270          *
271          * @param       $requestInstance        An instance of a request class
272          * @param       $responseInstance       An instance of a response class
273          * @return      void
274          */
275         protected function executePreFilters (Requestable $requestInstance, Responseable $responseInstance) {
276                 // Execute all pre filters
277                 $this->executeFilters(self::FILTER_CHAIN_PRE_COMMAND, $requestInstance, $responseInstance);
278         }
279
280         /**
281          * Executes all post filters
282          *
283          * @param       $requestInstance        An instance of a request class
284          * @param       $responseInstance       An instance of a response class
285          * @return      void
286          */
287         protected function executePostFilters (Requestable $requestInstance, Responseable $responseInstance) {
288                 // Execute all post filters
289                 $this->executeFilters(self::FILTER_CHAIN_POST_COMMAND, $requestInstance, $responseInstance);
290         }
291
292         /**
293          * Executes all shutdown filters
294          *
295          * @param       $requestInstance        A Requestable class
296          * @param       $responseInstance       A Responseable class
297          * @return      void
298          */
299         public function executeShutdownFilters (Requestable $requestInstance, Responseable $responseInstance) {
300                 $this->executeFilters('shutdown', $requestInstance, $responseInstance);
301         }
302
303 }