Completed
Push — 4.0 ( cafdfc...affd8b )
by Marco
02:49
created

Model   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 208
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 11

Test Coverage

Coverage 72.62%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 24
c 2
b 0
f 0
lcom 1
cbo 11
dl 0
loc 208
ccs 61
cts 84
cp 0.7262
rs 10

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 17 1
A getTable() 0 5 1
A setTable() 0 5 1
A bypassRouting() 0 9 1
A bypassService() 0 7 1
A getRoute() 0 5 1
B route() 0 25 5
B getServiceInstance() 0 27 3
B compose() 0 61 7
A parse() 0 23 3
1
<?php namespace Comodojo\Dispatcher\Router;
2
3
use \Comodojo\Dispatcher\Traits\CacheTrait;
4
use \Comodojo\Dispatcher\Traits\EventsTrait;
5
use \Comodojo\Dispatcher\Traits\RequestTrait;
6
use \Comodojo\Dispatcher\Traits\ResponseTrait;
7
use \Comodojo\Dispatcher\Traits\ExtraTrait;
8
use \Comodojo\Dispatcher\Components\AbstractModel;
9
use \Comodojo\Dispatcher\Request\Model as Request;
10
use \Comodojo\Dispatcher\Response\Model as Response;
11
use \Comodojo\Dispatcher\Extra\Model as Extra;
12
use \Comodojo\Foundation\Base\Configuration;
13
use \Comodojo\Foundation\Events\Manager as EventsManager;
14
use \Comodojo\SimpleCache\Manager as SimpleCacheManager;
15
use \Psr\Log\LoggerInterface;
16
use \Comodojo\Exception\DispatcherException;
17
use \Exception;
18
19
/**
20
 * @package     Comodojo Dispatcher
21
 * @author      Marco Giovinazzi <[email protected]>
22
 * @author      Marco Castiello <[email protected]>
23
 * @license     GPL-3.0+
24
 *
25
 * LICENSE:
26
 *
27
 * This program is free software: you can redistribute it and/or modify
28
 * it under the terms of the GNU Affero General Public License as
29
 * published by the Free Software Foundation, either version 3 of the
30
 * License, or (at your option) any later version.
31
 *
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 Affero General Public License for more details.
36
 *
37
 * You should have received a copy of the GNU Affero General Public License
38
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
39
 */
40
41
class Model extends AbstractModel {
42
43
    use CacheTrait;
44
    use EventsTrait;
45
    use RequestTrait;
46
    use ResponseTrait;
47
    use ExtraTrait;
48
49
    protected $bypass_routing = false;
50
    protected $bypass_service = false;
51
    protected $table;
52
    protected $route;
53
54 1
    public function __construct(
55
        Configuration $configuration,
56
        LoggerInterface $logger,
57
        SimpleCacheManager $cache,
58
        EventsManager $events,
59
        Extra $extra
60
    ) {
61
62 1
        parent::__construct($configuration, $logger);
63
64 1
        $this->setCache($cache);
65 1
        $this->setExtra($extra);
66 1
        $this->setEvents($events);
67
68 1
        $this->setTable(new Table($cache, $this));
69
70 1
    }
71
72 1
    public function getTable() {
73
74 1
        return $this->table;
75
76
    }
77
78 1
    public function setTable(Table $table) {
79
80 1
        $this->table = $table;
81
82 1
    }
83
84 1
    public function bypassRouting(Route $route) {
85
86 1
        $this->bypass_routing = true;
87
88 1
        $this->route = $route;
89
90 1
        return $this;
91
92
    }
93
94
    public function bypassService() {
95
96
        $this->bypass_service = true;
97
98
        return $this;
99
100
    }
101
102
    public function getRoute() {
103
104
        return $this->route;
105
106
    }
107
108 2
    public function route(Request $request) {
109
110 2
        $method = (string) $request->getMethod();
111
112 2
        $methods = $this->configuration->get('allowed-http-methods');
113
114 2
        if ( !empty($methods) && in_array($method, $methods) === false ) {
115
116
            throw new DispatcherException("Method not allowed", 0, null, 405, array(
117
                "Allow" => implode(",",$methods)
118
            ));
119
120
        }
121
122 2
        $this->setRequest($request);
123
124 2
        if ( $this->bypass_routing === false ) {
125
126 1
            if ( !$this->parse() ) throw new DispatcherException("Unable to find a valid route for the specified uri", 0, null, 404);
127
128
        }
129
130 1
        return $this->route;
131
132
    }
133
134 1
    public function getServiceInstance() {
135
136 1
        $class = $this->route->getClassName();
137
138 1
        if ( class_exists($class) ) {
139
140
            // All the route parameters are also added to the query parameters
141 1
            foreach ($this->route->getRequestParameters() as $parameter => $value) {
142
                $this->getRequest()->getQuery()->set($parameter, $value);
143 1
            }
144
145 1
            return new $class(
146 1
                $this->getConfiguration(),
147 1
                $this->getLogger(),
148 1
                $this->getCache(),
149 1
                $this->getEvents(),
150 1
                $this->getRequest(),
151 1
                $this,
152 1
                $this->getResponse(),
153 1
                $this->getExtra()
154 1
            );
155
156
        }
157
158
        return null;
159
160
    }
161
162 1
    public function compose(Response $response) {
163
164 1
        $this->setResponse($response);
165
166 1
        if ( is_null($this->route) ) {
167
168
            throw new DispatcherException("Route has not been loaded!");
169
170
        }
171
172 1
        if ( $this->bypass_service ) {
173
174
            return;
175
176
        }
177
178 1
        $service = $this->getServiceInstance();
179
180 1
        if ( !is_null($service) ) {
181
182 1
            $result = "";
183
184 1
            $method = (string) $this->getRequest()->getMethod();
185
186 1
            $methods = $service->getImplementedMethods();
187
188 1
            if ( in_array($method, $methods) ) {
189
190 1
                $callable = $service->getMethod($method);
191
192
                try {
193
194 1
                    $result = call_user_func([$service, $callable]);
195
196 1
                } catch (DispatcherException $de) {
197
198
                    throw $de;
199
200
                } catch (Exception $e) {
201
202
                    throw new DispatcherException(sprintf("Service '%s' execution failed for method '%s': %s", $this->route->getClassName(), $method, $e->getMessage()), 0, $e, 500);
203
204
                }
205
206 1
            } else {
207
208
                throw new DispatcherException(sprintf("Service '%s' doesn't implement method '%s'", $this->route->getServiceName(), $method), 0, null, 501, array(
209
                    "Allow" => implode(",", $methods)
210
                ));
211
212
            }
213
214 1
            $this->getResponse()->getContent()->set($result);
215
216 1
        } else {
217
218
            throw new DispatcherException(sprintf("Unable to execute service '%s'", $this->route->getClassName()), 0, null, 500);
219
220
        }
221
222 1
    }
223
224 1
    private function parse() {
225
226 1
        $path = $this->getRequest()->route();
227
228 1
        foreach ($this->table->getRoutes() as $regex => $value) {
229
230
            // The current uri is checked against all the global regular expressions associated with the routes
231
            if ( preg_match("/" . $regex . "/", $path, $matches) ) {
232
233
                /* If a route is matched, all the bits of the route string are evalued in order to create
234
                 * new query parameters which will be available for the service class
235
                 */
236
                $this->route = $value->path($matches);
237
238
                return true;
239
240
            }
241
242 1
        }
243
244 1
        return false;
245
246
    }
247
248
}
249