Completed
Push — 4.0 ( 75a76e...0161d2 )
by Marco
14:59
created

Dispatcher   B

Complexity

Total Complexity 27

Size/Duplication

Total Lines 284
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 16

Importance

Changes 25
Bugs 7 Features 4
Metric Value
wmc 27
c 25
b 7
f 4
lcom 1
cbo 16
dl 0
loc 284
rs 8.4614

13 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 32 4
A configuration() 0 11 2
A events() 0 11 2
A cache() 0 11 2
A request() 0 11 2
A router() 0 11 2
A response() 0 11 2
A extra() 0 11 2
A logger() 0 13 2
B dispatch() 0 79 4
A emitServiceSpecializedEvents() 0 14 1
A processDispatcherException() 0 16 1
A shutdown() 0 19 1
1
<?php namespace Comodojo\Dispatcher;
2
3
use \Monolog\Logger;
4
use \Comodojo\Dispatcher\Components\Configuration;
5
use \Comodojo\Dispatcher\Components\DefaultConfiguration;
6
use \Comodojo\Dispatcher\Request\Model as Request;
7
use \Comodojo\Dispatcher\Router\Collector as RouteCollector;
8
use \Comodojo\Dispatcher\Response\Model as Response;
9
use \Comodojo\Dispatcher\Extra\Model as Extra;
10
use \Comodojo\Dispatcher\Components\Timestamp as TimestampTrait;
11
use \Comodojo\Dispatcher\Output\Processor;
12
use \Comodojo\Dispatcher\Events\DispatcherEvent;
13
use \Comodojo\Dispatcher\Events\ServiceEvent;
14
use \Comodojo\Dispatcher\Router\RoutingTableInterface;
15
use \Comodojo\Dispatcher\Log\DispatcherLogger;
16
use \Comodojo\Dispatcher\Cache\DispatcherCache;
17
use \Comodojo\Dispatcher\Events\EventsManager;
18
use \Comodojo\Cache\CacheManager;
19
use \League\Event\Emitter;
20
use \Comodojo\Exception\DispatcherException;
21
use \Exception;
22
23
/**
24
 * @package     Comodojo Dispatcher
25
 * @author      Marco Giovinazzi <[email protected]>
26
 * @author      Marco Castiello <[email protected]>
27
 * @license     GPL-3.0+
28
 *
29
 * LICENSE:
30
 *
31
 * This program is free software: you can redistribute it and/or modify
32
 * it under the terms of the GNU Affero General Public License as
33
 * published by the Free Software Foundation, either version 3 of the
34
 * License, or (at your option) any later version.
35
 *
36
 * This program is distributed in the hope that it will be useful,
37
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
38
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
39
 * GNU Affero General Public License for more details.
40
 *
41
 * You should have received a copy of the GNU Affero General Public License
42
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
43
 */
44
45
class Dispatcher {
46
47
    use TimestampTrait;
48
49
    private $configuration;
50
51
    private $request;
52
53
    private $router;
54
55
    private $response;
56
57
    private $extra;
58
59
    private $logger;
60
61
    private $cache;
62
63
    private $events;
64
65
    public function __construct(
66
        $configuration = array(),
67
        Emitter $emitter = null,
68
        CacheManager $cache = null,
69
        Logger $logger = null
70
    ) {
71
72
        ob_start();
73
74
        $this->setTimestamp();
75
76
        $this->configuration()->merge($configuration);
77
78
        if (!is_null($emitter)) {
79
            
80
            $this->events = $emitter;
81
            
82
        }
83
84
        if (!is_null($logger)) {
85
            
86
            $this->logger = $logger;
87
            
88
        }
89
90
        if (!is_null($cache)) {
91
            
92
            $this->cache = $cache;
93
            
94
        }
95
        
96
    }
97
98
    public function configuration() {
99
        
100
        if (empty($this->configuration)) {
101
            
102
            $this->configuration = new Configuration( DefaultConfiguration::get() );
103
            
104
        }
105
106
        return $this->configuration;
107
108
    }
109
110
    public function events() {
111
        
112
        if (empty($this->events)) {
113
            
114
            $this->events = new EventsManager();
115
            
116
        }
117
118
        return $this->events;
119
120
    }
121
122
    public function cache() {
123
        
124
        if (empty($this->cache)) {
125
            
126
            $this->cache = DispatcherCache::create($this->configuration(), $this->logger());
127
            
128
        }
129
        
130
        return $this->cache;
131
132
    }
133
134
    public function request() {
135
        
136
        if (empty($this->request)) {
137
            
138
            $this->request = new Request($this->configuration(), $this->logger());
139
            
140
        }
141
142
        return $this->request;
143
144
    }
145
146
    public function router() {
147
        
148
        if (empty($this->router)) {
149
            
150
            $this->router = new RouteCollector($this->configuration(), $this->logger(), $this->cache(), $this->extra());
151
            
152
        }
153
154
        return $this->router;
155
156
    }
157
158
    public function response() {
159
        
160
        if (empty($this->response)) {
161
            
162
            $this->response = new Response($this->configuration(), $this->logger());
163
            
164
        }
165
166
        return $this->response;
167
168
    }
169
170
    public function extra() {
171
        
172
        if (empty($this->extra)) {
173
            
174
            $this->extra = new Extra($this->logger());
0 ignored issues
show
Unused Code introduced by
The call to Model::__construct() has too many arguments starting with $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.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
175
            
176
        }
177
178
        return $this->extra;
179
180
    }
181
182
    public function logger() {
183
        
184
        if (empty($this->logger)) {
185
            
186
            $this->logger = DispatcherLogger::create($this->configuration());
187
            
188
            $this->logger()->debug("Dispatcher ready, current date ".date('c', $this->getTimestamp()));
189
            
190
        }
191
192
        return $this->logger;
193
194
    }
195
196
    public function dispatch() {
197
198
        $this->logger()->debug("Starting to dispatch.");
199
200
        $this->logger()->debug("Emitting global dispatcher event.");
201
202
        $this->events()->emit( new DispatcherEvent($this) );
203
204
        if ( $this->configuration()->get('enabled') === false ) {
205
206
            $this->logger()->debug("Dispatcher disabled, shutting down gracefully.");
207
208
            $status = $this->configuration()->get('disabled-status');
209
210
            $content = $this->configuration()->get('disabled-message');
211
212
            $this->response()->status()->set($status);
213
214
            $this->response()->content()->set($content);
215
216
            return $this->shutdown();
217
218
        }
219
220
        $this->events()->emit( $this->emitServiceSpecializedEvents('dispatcher.request') );
221
222
        $this->events()->emit( $this->emitServiceSpecializedEvents('dispatcher.request.'.$this->request()->method()->get()) );
223
224
        $this->events()->emit( $this->emitServiceSpecializedEvents('dispatcher.request.#') );
225
226
        $this->logger()->debug("Starting router.");
227
228
        try {
229
230
            $this->router()->route($this->request());
231
232
        } catch (DispatcherException $de) {
233
234
            $this->logger()->debug("Route error (".$de->getStatus()."), shutting down dispatcher.");
235
236
            $this->processDispatcherException($de);
237
238
            return $this->shutdown();
239
240
        }
241
242
        $route_type = $this->router()->getType();
243
244
        $route_service = $this->router()->getService();
245
246
        $this->logger()->debug("Route acquired, type $route_type directed to $route_service.");
247
248
        $this->events()->emit( $this->emitServiceSpecializedEvents('dispatcher.route') );
249
250
        $this->events()->emit( $this->emitServiceSpecializedEvents('dispatcher.route.'.$route_type) );
251
252
        $this->events()->emit( $this->emitServiceSpecializedEvents('dispatcher.route.'.$route_service) );
253
254
        $this->events()->emit( $this->emitServiceSpecializedEvents('dispatcher.route.#') );
255
256
        // translate route to service
257
258
        $this->logger()->debug("Running $route_service service.");
259
260
        try {
261
262
            $this->router()->compose($this->response());
263
264
        } catch (DispatcherException $de) {
265
266
            $this->logger()->debug("Service exception (".$de->getStatus()."), shutting down dispatcher.");
267
268
            $this->processDispatcherException($de);
269
270
        }
271
272
        return $this->shutdown();
273
274
    }
275
276
    private function emitServiceSpecializedEvents($name) {
277
278
        $this->logger()->debug("Emitting $name service-event.");
279
280
        return new ServiceEvent(
281
            $name,
282
            $this->logger(),
283
            $this->request(),
284
            $this->router(),
285
            $this->response(),
286
            $this->extra()
287
        );
288
289
    }
290
291
    private function processDispatcherException(DispatcherException $de) {
292
293
        $status = $de->getStatus();
294
295
        $message = $de->getMessage();
296
297
        //$headers = $de->getHeaders();
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
298
        $headers = array();
299
300
        $this->response()->status()->set($status);
301
302
        $this->response()->content()->set($message);
303
304
        $this->response()->headers()->merge($headers);
305
306
    }
307
308
    private function shutdown() {
309
310
        $this->events()->emit( $this->emitServiceSpecializedEvents('dispatcher.response') );
311
312
        $this->events()->emit( $this->emitServiceSpecializedEvents('dispatcher.response.'.$this->response()->status()->get()) );
313
314
        $this->events()->emit( $this->emitServiceSpecializedEvents('dispatcher.response.#') );
315
316
        $this->logger()->debug("Composing return value.");
317
318
        $return = Processor::parse($this->configuration(), $this->logger(), $this->response());
319
320
        $this->logger()->debug("Dispatcher run-cycle ends.");
321
322
        ob_end_clean();
323
324
        return $return;
325
326
    }
327
328
}
329