Completed
Push — 4.0 ( bf6233...a1234e )
by Marco
13:59
created

Model   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 191
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 8

Test Coverage

Coverage 69.12%

Importance

Changes 8
Bugs 1 Features 1
Metric Value
wmc 23
c 8
b 1
f 1
lcom 1
cbo 8
dl 0
loc 191
ccs 47
cts 68
cp 0.6912
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 26 1
A bypassRouting() 0 9 1
A bypassService() 0 7 1
A getRoute() 0 5 1
B route() 0 25 6
B getServiceInstance() 0 24 3
B compose() 0 61 7
A parse() 0 23 3
1
<?php namespace Comodojo\Dispatcher\Router;
2
3
use \Comodojo\Dispatcher\Components\Model as DispatcherClassModel;
4
use \Comodojo\Dispatcher\Router\Table;
5
use \Comodojo\Dispatcher\Router\Route;
6
use \Comodojo\Dispatcher\Request\Model as Request;
7
use \Comodojo\Dispatcher\Response\Model as Response;
8
use \Comodojo\Dispatcher\Extra\Model as Extra;
9
use \Comodojo\Dispatcher\Components\Configuration;
10
use \Comodojo\Cache\CacheManager;
11
use \Psr\Log\LoggerInterface;
12
use \Comodojo\Exception\DispatcherException;
13
use \Exception;
14
15
/**
16
 * @package     Comodojo Dispatcher
17
 * @author      Marco Giovinazzi <[email protected]>
18
 * @author      Marco Castiello <[email protected]>
19
 * @license     GPL-3.0+
20
 *
21
 * LICENSE:
22
 *
23
 * This program is free software: you can redistribute it and/or modify
24
 * it under the terms of the GNU Affero General Public License as
25
 * published by the Free Software Foundation, either version 3 of the
26
 * License, or (at your option) any later version.
27
 *
28
 * This program is distributed in the hope that it will be useful,
29
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
31
 * GNU Affero General Public License for more details.
32
 *
33
 * You should have received a copy of the GNU Affero General Public License
34
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
35
 */
36
37
class Model extends DispatcherClassModel {
38
39
    public function __construct(
40
        Configuration $configuration,
41
        LoggerInterface $logger,
42
        CacheManager $cache,
43
        Extra $extra
44
    ) {
45
46
        parent::__construct($configuration, $logger);
47
48
        $this->route = null;
0 ignored issues
show
Bug introduced by
The property route does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
49
50
        $this->request = null;
0 ignored issues
show
Bug introduced by
The property request does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
51
52
        $this->response = null;
0 ignored issues
show
Bug introduced by
The property response does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
53
54
        $this->table = new Table($cache, $this);
0 ignored issues
show
Bug introduced by
The property table does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
55
56 1
        $this->cache = $cache;
0 ignored issues
show
Bug introduced by
The property cache does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
57
58
        $this->extra = $extra;
0 ignored issues
show
Bug introduced by
The property extra does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
59
60
        $this->bypass_routing = false;
0 ignored issues
show
Bug introduced by
The property bypass_routing does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
61
62
        $this->bypass_service = false;
0 ignored issues
show
Bug introduced by
The property bypass_service does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
63 1
64
    }
65 1
66
    public function bypassRouting(Route $route) {
67 1
68
        $this->bypass_routing = true;
69 1
70
        $this->route = $route;
71 1
72
        return $this;
73 1
74
    }
75 1
76
    public function bypassService() {
77 1
78
        $this->bypass_service = true;
79
80
        return $this;
81 1
82
    }
83 1
84
    public function getRoute() {
85 1
86
        return $this->route;
87 1
88
    }
89
90
    public function route(Request $request) {
91
92
        $method = $request->method()->get();
93
94
        $methods = $this->configuration->get('allowed-http-methods');
95
96
        if ( ( $methods != null || !empty($methods) ) && in_array($method, $methods) === false ) {
97
98
            throw new DispatcherException("Method not allowed", 0, null, 405, array(
0 ignored issues
show
Unused Code introduced by
The call to DispatcherException::__construct() has too many arguments starting with array('Allow' => implode(',', $methods)).

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...
99
                "Allow" => implode(",",$methods)
100
            ));
101
102
        }
103
104
        $this->request = $request;
105 2
106
        if (!$this->bypass_routing) {
107 2
108
            if (!$this->parse()) throw new DispatcherException("Unable to find a valid route for the specified uri", 0, null, 404);
109 2
110
        }
111 2
112
        return $this->route;
113
114
    }
115
    
116
    public function getServiceInstance() {
117
        
118
        $class = $this->route->getClassName();
119 2
120
        if (class_exists($class)) {
121 2
122
            // All the route parameters are also added to the query parameters
123 1
            foreach ($this->route->getParameters() as $parameter => $value) {
124
                $this->request->query()->set($parameter, $value);
125
            }
126
127 1
            return new $class(
128
                $this->configuration,
129
                $this->logger,
130
                $this->request,
131 1
                $this,
132
                $this->response,
133 1
                $this->extra
134
            );
135 1
136
        }
137
        else return null;
138
        
139
    }
140
141 1
    public function compose(Response $response) {
142
143
        $this->response = $response;
144
145
        if (is_null($this->route)) {
146
147 1
            throw new DispatcherException("Route has not been loaded!");
148 1
149 1
        }
150 1
151 1
        if ( $this->bypass_service ) {
152
153 1
            return;
154
155 1
        }
156
157 1
        $service = $this->getServiceInstance();
158
159 1
        if (!is_null($service)) {
160
161 1
            $result = "";
162
163 1
            $method = $this->request->method()->get();
164
165
            $methods = $service->getImplementedMethods();
166
167 1
            if ( in_array($method, $methods) ) {
168
169 1
                $callable = $service->getMethod($method);
170
171
                try {
172
173
                    $result = call_user_func(array($service, $callable));
174
175
                } catch (DispatcherException $de) {
176
177
                    throw new DispatcherException(sprintf("Service '%s' exception for method '%s': %s", $this->route->getClassName(), $method, $de->getMessage()), 0, $de, 500);
178
179 1
                } catch (Exception $e) {
180
181
                    throw new DispatcherException(sprintf("Service '%s' execution failed for method '%s': %s", $this->route->getClassName(), $method, $e->getMessage()), 0, $e, 500);
182
183
                }
184
185
            } else {
186
187 1
                throw new DispatcherException(sprintf("Service '%s' doesn't implement method '%s'", $this->route->getServiceName(), $method), 0, null, 501, array(
0 ignored issues
show
Unused Code introduced by
The call to DispatcherException::__construct() has too many arguments starting with array('Allow' => implode(',', $methods)).

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...
188
                    "Allow" => implode(",", $methods)
189 1
                ));
190
191
            }
192
193
            $this->response->content()->set($result);
194
195 1
        } else {
196
197 1
            throw new DispatcherException(sprintf("Unable to execute service '%s'", $this->route->getClassName()), 0, null, 500);
198
199 1
        }
200
201 1
    }
202
203
    private function parse() {
204
205
        $path = $this->request->route();
206
207
        foreach ($this->table->routes as $regex => $value) {
208
209
            // The current uri is checked against all the global regular expressions associated with the routes
210
            if (preg_match("/" . $regex . "/", $path, $matches)) {
211
212
                /* If a route is matched, all the bits of the route string are evalued in order to create
213
                 * new query parameters which will be available for the service class
214
                 */
215 1
                $this->route = $value->path($matches);
216
217 1
                return true;
218
219
            }
220
221
        }
222
223
        return false;
224
225
    }
226
227
}
228