Completed
Push — master ( 8df946...5e7000 )
by Marco
05:17
created

Dispatcher::processRedirect()   C

Complexity

Conditions 7
Paths 10

Size

Total Lines 35
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 0
Metric Value
dl 0
loc 35
c 0
b 0
f 0
ccs 0
cts 24
cp 0
rs 6.7272
cc 7
eloc 23
nc 10
nop 1
crap 56

2 Methods

Rating   Name   Duplication   Size   Complexity  
A Dispatcher::processDispatcherException() 0 11 1
A Dispatcher::processConfigurationParameters() 0 7 4
1
<?php namespace Comodojo\Dispatcher;
2
3
use \Comodojo\Dispatcher\Components\AbstractModel;
4
use \Comodojo\Dispatcher\Components\DefaultConfiguration;
5
use \Comodojo\Dispatcher\Cache\ServerCache;
6
use \Comodojo\Dispatcher\Request\Model as Request;
7
use \Comodojo\Dispatcher\Router\Model as Router;
8
use \Comodojo\Dispatcher\Router\Route;
9
use \Comodojo\Dispatcher\Response\Model as Response;
10
use \Comodojo\Dispatcher\Extra\Model as Extra;
11
use \Comodojo\Dispatcher\Output\Processor;
12
use \Comodojo\Dispatcher\Output\Redirect;
13
use \Comodojo\Dispatcher\Output\Error;
14
use \Comodojo\Dispatcher\Events\DispatcherEvent;
15
use \Comodojo\Dispatcher\Events\ServiceEvent;
16
use \Comodojo\Dispatcher\Traits\CacheTrait;
17
use \Comodojo\Dispatcher\Traits\ServerCacheTrait;
18
use \Comodojo\Dispatcher\Traits\RequestTrait;
19
use \Comodojo\Dispatcher\Traits\ResponseTrait;
20
use \Comodojo\Dispatcher\Traits\RouterTrait;
21
use \Comodojo\Dispatcher\Traits\RouteTrait;
22
use \Comodojo\Dispatcher\Traits\ExtraTrait;
23
use \Comodojo\Foundation\Events\EventsTrait;
24
use \Comodojo\Foundation\Base\Configuration;
25
use \Comodojo\Foundation\Timing\TimingTrait;
26
use \Comodojo\Foundation\Events\Manager as EventsManager;
27
use \Comodojo\Foundation\Logging\Manager as LogManager;
28
use \Comodojo\SimpleCache\Manager as SimpleCacheManager;
29
use \Psr\Log\LoggerInterface;
30
use \Comodojo\Exception\DispatcherException;
31
use \Exception;
32
33
/**
34
 * @package     Comodojo Dispatcher
35
 * @author      Marco Giovinazzi <[email protected]>
36
 * @author      Marco Castiello <[email protected]>
37
 * @license     MIT
38
 *
39
 * LICENSE:
40
 *
41
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
43
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
44
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
45
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
46
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
47
 * THE SOFTWARE.
48
 */
49
50
class Dispatcher extends AbstractModel {
51
52
    use TimingTrait;
53
    use CacheTrait;
54
    use ServerCacheTrait;
55
    use RequestTrait;
56
    use ResponseTrait;
57
    use RouterTrait;
58
    use RouteTrait;
59
    use ExtraTrait;
60
    use EventsTrait;
61
62
    /**
63
     * The main dispatcher constructor.
64
     */
65 1
    public function __construct(
66
        array $configuration = [],
67
        EventsManager $events = null,
68
        SimpleCacheManager $cache = null,
69
        LoggerInterface $logger = null
70
    ) {
71
72
        // starting output buffer
73 1
        ob_start();
74
75
        // fix current timestamp
76 1
        $this->setTiming();
77
78
        // init core components
79
        // create new configuration object and merge configuration
80 1
        $configuration_object = new Configuration(DefaultConfiguration::get());
81 1
        $configuration_object->merge($configuration);
82
83 1
        $logger = is_null($logger) ? LogManager::createFromConfiguration($configuration_object)->getLogger() : $logger;
84
85 1
        parent::__construct($configuration_object, $logger);
86
87 1
        $this->logger->debug("--------------------------------------------------------");
88 1
        $this->logger->debug("Dispatcher run-cycle starts at ".$this->getTime()->format('c'));
89
90
        try {
91
92
            // init other components
93 1
            $this->setEvents(is_null($events) ? EventsManager::create($this->logger) : $events);
94 1
            $this->setCache(is_null($cache) ? SimpleCacheManager::createFromConfiguration($this->configuration, $this->logger) : $cache);
95 1
            $this->setServerCache(new ServerCache($this->getCache()));
96
97
            // init models
98 1
            $this->setExtra(new Extra($this->logger));
0 ignored issues
show
Unused Code introduced by
The call to Comodojo\Dispatcher\Extra\Model::__construct() has too many arguments starting with $this->logger. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

98
            $this->setExtra(/** @scrutinizer ignore-call */ new Extra($this->logger));

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
99 1
            $this->setRequest(new Request($this->configuration, $this->logger));
100 1
            $this->setRouter(new Router($this->configuration, $this->logger, $this->cache, $this->events, $this->extra));
101 1
            $this->setResponse(new Response($this->configuration, $this->logger));
102
103 1
        } catch (Exception $e) {
104
105 1
            $this->logger->critical($e->getMessage(), $e->getTrace());
106
107
            throw $e;
108
109
        }
110
111
        // we're ready!
112 1
        $this->logger->debug("Dispatcher ready");
113
114 1
    }
115
116 1
    public function dispatch() {
117
118 1
        $configuration = $this->getConfiguration();
119 1
        $logger = $this->getLogger();
120 1
        $events = $this->getEvents();
121 1
        $request = $this->getRequest();
0 ignored issues
show
Unused Code introduced by
The assignment to $request is dead and can be removed.
Loading history...
122 1
        $response = $this->getResponse();
123
124 1
        $logger->debug("Starting to dispatch.");
125 1
        $logger->debug("Emitting global dispatcher event.");
126 1
        $events->emit(new DispatcherEvent($this));
127
128
        // if dispatcher is administratively disabled, halt the process immediately
129 1
        if ($configuration->get('enabled') === false) {
130
131
            $logger->debug("Dispatcher disabled, shutting down gracefully.");
132
133
            $status = $configuration->get('disabled-status');
134
            $content = $configuration->get('disabled-message');
135
136
            $response
137
                ->getStatus()
138
                ->set($status === null ? 503 : $status);
139
            $response
140
                ->getContent()
141
                ->set($content === null ? 'Service unavailable (dispatcher disabled)' : $content);
142
143
            return $this->shutdown();
144
145
        }
146
147 1
        $cache = $this->getServerCache();
148
149 1
        $events->emit($this->createServiceSpecializedEvents('dispatcher.request'));
150 1
        $events->emit($this->createServiceSpecializedEvents('dispatcher.request.'.$this->request->getMethod()->get()));
151 1
        $events->emit($this->createServiceSpecializedEvents('dispatcher.request.#'));
152
153 1
        $logger->debug("Starting router");
154
155
        try {
156
157 1
            $route = $this->getRouter()
158 1
                ->route($this->request);
159
            $this->setRoute($route);
160
161 1
        } catch (DispatcherException $de) {
162
163 1
            $logger->debug("Route error (".$de->getStatus()."), shutting down dispatcher");
164 1
            $this->processDispatcherException($de);
165 1
            return $this->shutdown();
166
167
        }
168
169
        $route_type = $route->getType();
170
        $route_service = $route->getServiceName();
171
172
        $logger->debug("Route acquired, type $route_type");
173
174
        $events->emit($this->createServiceSpecializedEvents('dispatcher.route'));
175
        $events->emit($this->createServiceSpecializedEvents('dispatcher.route.'.$route_type));
176
177
        if ( $route_type === 'ROUTE' ) {
178
            $logger->debug("Route leads to service $route_service");
179
            $events->emit($this->createServiceSpecializedEvents('dispatcher.route.'.$route_service));
180
        }
181
182
        $events->emit($this->createServiceSpecializedEvents('dispatcher.route.#'));
183
184
        if ($cache->read($this->request, $this->response)) {
185
            // we have a cache!
186
            // shutdown immediately
187
            return $this->shutdown();
188
        }
189
190
        try {
191
192
            switch ($route_type) {
193
194 1
                case 'ROUTE':
195
196
                    $logger->debug("Running $route_service service");
197
198
                    // translate route to service
199
                    $this->router->compose($this->response);
200
201
                    $this->processConfigurationParameters($this->route);
202
203
                    $cache->dump($this->request, $this->response, $this->route);
204
205
                    break;
206
207
                case 'REDIRECT':
208
209
                    $logger->debug("Redirecting response...");
210
211
                    Redirect::compose(
212
                        $this->getRequest(),
213
                        $this->getResponse(),
214
                        $this->getRoute()
215
                    );
216
217
                    break;
218
219
                case 'ERROR':
220
221
                    $logger->debug("Sending error message...");
222
223
                    Error::compose($this->route);
224
225
                    break;
226
            }
227
228
        } catch (DispatcherException $de) {
229
230
            $logger->debug("Service exception (".$de->getStatus()."), shutting down dispatcher");
231
            $this->processDispatcherException($de);
232
233
        }
234
235
        return $this->shutdown();
236
237
    }
238
239
    private function processConfigurationParameters($route) {
240
241
        $params = $route->getParameter('headers');
242
243
        if ( !empty($params) && is_array($params) ) {
244
            foreach($params as $name => $value) {
245
                $this->getResponse()->getHeaders()->set($name, $value);
246
            }
247
        }
248
249
    }
250
251 1
    private function processDispatcherException(DispatcherException $de) {
252
253 1
        $status = $de->getStatus();
254 1
        $message = $de->getMessage();
255 1
        $headers = $de->getHeaders();
256
257 1
        $response = $this->getResponse();
258
259 1
        $response->getStatus()->set($status);
260 1
        $response->getContent()->set($message);
261 1
        $response->getHeaders()->merge($headers);
262
263 1
    }
264
265
    /**
266
     * @param string $name
267
     */
268 1
    private function createServiceSpecializedEvents($name) {
269
270 1
        $this->logger->debug("Emitting $name service-event");
271
272 1
        return new ServiceEvent(
273 1
            $name,
274 1
            $this->getConfiguration(),
275 1
            $this->getLogger(),
276 1
            $this->getCache(),
277 1
            $this->getServerCache(),
278 1
            $this->getEvents(),
279 1
            $this->getRequest(),
280 1
            $this->getRouter(),
281 1
            $this->getResponse(),
282 1
            $this->getExtra()
283 1
        );
284
285
    }
286
287 1
    private function shutdown() {
288
289 1
        $configuration = $this->getConfiguration();
290 1
        $logger = $this->getLogger();
291 1
        $events = $this->getEvents();
292 1
        $request = $this->getRequest();
293 1
        $response = $this->getResponse();
294
295 1
        $response->consolidate($request, $this->route);
296
297 1
        $events->emit($this->createServiceSpecializedEvents('dispatcher.response'));
298 1
        $events->emit($this->createServiceSpecializedEvents('dispatcher.response.'.$response->getStatus()->get()));
299 1
        $events->emit($this->createServiceSpecializedEvents('dispatcher.response.#'));
300
301 1
        $logger->debug("Composing return value");
302
303 1
        $return = Processor::parse(
304 1
            $configuration,
305 1
            $logger,
306 1
            $request,
307
            $response
308 1
        );
309
310 1
        $logger->debug("Dispatcher run-cycle ends");
311
312
        // This could cause WSOD with some PHP-FPM configurations
313
        // if ( function_exists('fastcgi_finish_request') ) fastcgi_finish_request();
314
        // else ob_end_clean();
315 1
        ob_end_clean();
316
317 1
        return $return;
318
319
    }
320
321
}
322