Completed
Push — 4.0 ( ad8a54...ed771a )
by Marco
06:33
created

Dispatcher::extra()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 4
Bugs 1 Features 0
Metric Value
c 4
b 1
f 0
dl 0
loc 5
ccs 2
cts 2
cp 1
rs 9.4285
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php namespace Comodojo\Dispatcher;
2
3
use \Psr\Log\LoggerInterface;
4
use \Comodojo\Dispatcher\Components\Configuration;
5
use \Comodojo\Dispatcher\Components\DefaultConfiguration;
6
use \Comodojo\Dispatcher\Components\EventsManager;
7
use \Comodojo\Dispatcher\Components\Timestamp as TimestampTrait;
8
use \Comodojo\Dispatcher\Components\CacheManager as DispatcherCache;
9
use \Comodojo\Dispatcher\Components\LogManager;
10
use \Comodojo\Dispatcher\Request\Model as Request;
11
use \Comodojo\Dispatcher\Router\Model as Router;
12
use \Comodojo\Dispatcher\Response\Model as Response;
13
use \Comodojo\Dispatcher\Extra\Model as Extra;
14
use \Comodojo\Dispatcher\Output\Processor;
15
use \Comodojo\Dispatcher\Events\DispatcherEvent;
16
use \Comodojo\Dispatcher\Events\ServiceEvent;
17
use \Comodojo\Cache\CacheManager;
18
use \Comodojo\Exception\DispatcherException;
19
use \Exception;
20
21
/**
22
 * @package     Comodojo Dispatcher
23
 * @author      Marco Giovinazzi <[email protected]>
24
 * @author      Marco Castiello <[email protected]>
25
 * @license     GPL-3.0+
26
 *
27
 * LICENSE:
28
 *
29
 * This program is free software: you can redistribute it and/or modify
30
 * it under the terms of the GNU Affero General Public License as
31
 * published by the Free Software Foundation, either version 3 of the
32
 * License, or (at your option) any later version.
33
 *
34
 * This program is distributed in the hope that it will be useful,
35
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
36
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
37
 * GNU Affero General Public License for more details.
38
 *
39
 * You should have received a copy of the GNU Affero General Public License
40
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
41
 */
42
43
class Dispatcher {
44
45
    use TimestampTrait;
46
47
    private $configuration;
48
49
    private $request;
50
51
    private $router;
52
53
    private $response;
54
55
    private $extra;
56
57
    private $logger;
58
59
    private $cache;
60
61
    private $events;
62
63
    private $route;
64
65 1
    public function __construct(
66
        $configuration = array(),
67
        EventsManager $events = null,
68
        CacheManager $cache = null,
69
        LoggerInterface $logger = null
70
    ) {
71
72
        // starting output buffer
73 1
        ob_start();
74
75
        // fix current timestamp
76 1
        $this->setTimestamp();
77
78
        // parsing configuration
79 1
        $this->configuration = new Configuration( DefaultConfiguration::get() );
80
81 1
        $this->configuration()->merge($configuration);
82
83
        // init core components
84 1
        $this->logger = is_null($logger) ? LogManager::create($this->configuration()) : $logger;
85
86 1
        $this->events = is_null($events) ? new EventsManager($this->logger()) : $events;
87
88 1
        $this->cache = is_null($cache) ? DispatcherCache::create($this->configuration(), $this->logger()) : $cache;
89
90
        // init models
91 1
        $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...
92
93 1
        $this->request = new Request($this->configuration(), $this->logger());
94
95 1
        $this->router = new Router($this->configuration(), $this->logger(), $this->cache(), $this->extra());
96
97 1
        $this->response = new Response($this->configuration(), $this->logger());
98
99
        // we're ready!
100 1
        $this->logger()->debug("Dispatcher ready, current date ".date('c', $this->getTimestamp()));
101
102 1
    }
103
104 1
    public function configuration() {
105
106 1
        return $this->configuration;
107
108
    }
109
110 1
    public function events() {
111
112 1
        return $this->events;
113
114
    }
115
116 1
    public function cache() {
117
118 1
        return $this->cache;
119
120
    }
121
122 1
    public function request() {
123
124 1
        return $this->request;
125
126
    }
127
128 1
    public function router() {
129
130 1
        return $this->router;
131
132
    }
133
134 1
    public function response() {
135
136 1
        return $this->response;
137
138
    }
139
140 1
    public function extra() {
141
142 1
        return $this->extra;
143
144
    }
145
146 1
    public function logger() {
147
148 1
        return $this->logger;
149
150
    }
151
152 1
    public function dispatch() {
153
154 1
        $this->logger()->debug("Starting to dispatch.");
155
156 1
        $this->logger()->debug("Emitting global dispatcher event.");
157
158 1
        $this->events()->emit( new DispatcherEvent($this) );
159
160 1
        if ( $this->configuration()->get('enabled') === false ) {
161
162
            $this->logger()->debug("Dispatcher disabled, shutting down gracefully.");
163
164
            $status = $this->configuration()->get('disabled-status');
165
166
            $content = $this->configuration()->get('disabled-message');
167
168
            $this->response()->status()->set($status);
169
170
            $this->response()->content()->set($content);
171
172
            return $this->shutdown();
173
174
        }
175
176 1
        $this->events()->emit( $this->emitServiceSpecializedEvents('dispatcher.request') );
177
178 1
        $this->events()->emit( $this->emitServiceSpecializedEvents('dispatcher.request.'.$this->request()->method()->get()) );
179
180 1
        $this->events()->emit( $this->emitServiceSpecializedEvents('dispatcher.request.#') );
181
182 1
        if ( $this->readCache() ) {
183
184
            return $this->shutdown();
185
186
        }
187
188 1
        $this->logger()->debug("Starting router.");
189
190
        try {
191
192 1
            $route = $this->router()->route($this->request());
193
194
            $this->route = $route;
195
196 1
        } catch (DispatcherException $de) {
197
198 1
            $this->logger()->debug("Route error (".$de->getStatus()."), shutting down dispatcher.");
199
200 1
            $this->processDispatcherException($de);
201
202 1
            return $this->shutdown();
203
204
        }
205
206
        $route_type = $route->getType();
207
208
        $route_service = $route->getServiceName();
209
210
        $this->logger()->debug("Route acquired, type $route_type directed to $route_service.");
211
212
        $this->events()->emit( $this->emitServiceSpecializedEvents('dispatcher.route') );
213
214
        $this->events()->emit( $this->emitServiceSpecializedEvents('dispatcher.route.'.$route_type) );
215
216
        $this->events()->emit( $this->emitServiceSpecializedEvents('dispatcher.route.'.$route_service) );
217
218
        $this->events()->emit( $this->emitServiceSpecializedEvents('dispatcher.route.#') );
219
220
        // translate route to service
221
222
        $this->logger()->debug("Running $route_service service.");
223
224
        try {
225
226
            $this->router()->compose($this->response());
227
228
        } catch (DispatcherException $de) {
229
230
            $this->logger()->debug("Service exception (".$de->getStatus()."), shutting down dispatcher.");
231
232
            $this->processDispatcherException($de);
233
234
        }
235
236
        $this->processConfigurationParameters($route);
237
238
        $this->dumpCache($route);
239
240
        return $this->shutdown();
241
242
    }
243
244 1
    private function readCache() {
245
246 1
        $name = (string) $this->request()->uri();
247
248 1
        $cache = $this->cache()->setNamespace('dispatcherservice')->get($name);
249
250 1
        if ( is_null($cache) ) return false;
251
252
        $this->response = $cache;
253
254
        return true;
255
256
    }
257
258
    private function dumpCache($route) {
259
260
        $cache = strtoupper($route->getParameter('cache'));
261
        $ttl = $route->getParameter('ttl');
262
        $name = (string) $this->request()->uri();
263
        $method = $this->request()->method()->get();
0 ignored issues
show
Unused Code introduced by
$method is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
264
        $status = $this->response()->status()->get();
0 ignored issues
show
Unused Code introduced by
$status is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
265
266
        // @NOTE: Server cache will not consider cacheable POST or PUT requests
267
        //        because of dispatcher internal structure: if post request is cached
268
        //        subsequent requests will never reach the service.
269
        if (
270
            ( $cache == 'SERVER' || $cache == 'BOTH' ) &&
271
            in_array($request->method()->get(), array('GET', 'HEAD')) &&
0 ignored issues
show
Bug introduced by
The variable $request does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
272
            in_array($this->status()->get(), array(200, 203, 300, 301, 302, 404, 410))
0 ignored issues
show
Bug introduced by
The method status() does not seem to exist on object<Comodojo\Dispatcher\Dispatcher>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
273
        ){
274
275
            $this->cache()->setNamespace('dispatcherservice')->set($name, $this->response(), $ttl);
276
277
        }
278
279
    }
280
281
    private function processConfigurationParameters($route) {
282
283
        $params = $route->getParameter('headers');
284
285
        if ( !empty($params) && is_array($params) ) {
286
287
            foreach($params as $name=>$value) $this->response()->headers()->set($name, $value);
288
        }
289
290
    }
291
292 1
    private function emitServiceSpecializedEvents($name) {
293
294 1
        $this->logger()->debug("Emitting $name service-event.");
295
296 1
        return new ServiceEvent(
297 1
            $name,
298 1
            $this->logger(),
0 ignored issues
show
Compatibility introduced by
$this->logger() of type object<Psr\Log\LoggerInterface> is not a sub-type of object<Monolog\Logger>. It seems like you assume a concrete implementation of the interface Psr\Log\LoggerInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
299 1
            $this->request(),
300 1
            $this->router(),
301 1
            $this->response(),
302 1
            $this->extra()
303 1
        );
304
305
    }
306
307 1
    private function processDispatcherException(DispatcherException $de) {
308
309 1
        $status = $de->getStatus();
310
311 1
        $message = $de->getMessage();
312
313 1
        $headers = $de->getHeaders();
0 ignored issues
show
Bug introduced by
The method getHeaders() does not seem to exist on object<Comodojo\Exception\DispatcherException>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
314
315 1
        $this->response()->status()->set($status);
316
317 1
        $this->response()->content()->set($message);
318
319 1
        $this->response()->headers()->merge($headers);
320
321 1
    }
322
323 1
    private function shutdown() {
324
325 1
        $this->response()->consolidate($this->request, $this->route);
326
327 1
        $this->events()->emit( $this->emitServiceSpecializedEvents('dispatcher.response') );
328
329 1
        $this->events()->emit( $this->emitServiceSpecializedEvents('dispatcher.response.'.$this->response()->status()->get()) );
330
331 1
        $this->events()->emit( $this->emitServiceSpecializedEvents('dispatcher.response.#') );
332
333 1
        $this->logger()->debug("Composing return value.");
334
335 1
        $return = Processor::parse($this->configuration(), $this->logger(), $this->request(), $this->response());
336
337 1
        $this->logger()->debug("Dispatcher run-cycle ends.");
338
339 1
        if ( function_exists('fastcgi_finish_request') ) fastcgi_finish_request();
340 1
        else ob_end_clean();
341
342 1
        return $return;
343
344
    }
345
346
}
347