Completed
Push — 4.0 ( 6e7e32...0ca36c )
by Marco
12:30
created

Collector::loadFromYaml()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 17
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 17
rs 9.4285
cc 3
eloc 6
nc 2
nop 1
1
<?php namespace Comodojo\Dispatcher\Router;
2
3
use \Comodojo\Dispatcher\Components\Model as DispatcherClassModel;
4
use \Comodojo\Dispatcher\Router\RoutingTable;
5
use \Comodojo\Dispatcher\Components\Timestamp as TimestampTrait;
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 \Symfony\Component\Yaml\Yaml;
12
use \Monolog\Logger;
13
use \Comodojo\Exception\DispatcherException;
14
use \Exception;
15
16
/**
17
 * @package     Comodojo Dispatcher
18
 * @author      Marco Giovinazzi <[email protected]>
19
 * @author      Marco Castiello <[email protected]>
20
 * @license     GPL-3.0+
21
 *
22
 * LICENSE:
23
 *
24
 * This program is free software: you can redistribute it and/or modify
25
 * it under the terms of the GNU Affero General Public License as
26
 * published by the Free Software Foundation, either version 3 of the
27
 * License, or (at your option) any later version.
28
 *
29
 * This program is distributed in the hope that it will be useful,
30
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
31
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
32
 * GNU Affero General Public License for more details.
33
 *
34
 * You should have received a copy of the GNU Affero General Public License
35
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
36
 */
37
38
class Collector extends DispatcherClassModel {
39
40
    use TimestampTrait;
41
42
    private $bypass = false;
43
44
    private $classname = "";
45
46
    private $type = "";
47
48
    private $service = "";
49
50
    private $cache;
51
52
    private $request;
53
54
    private $response;
55
56
    private $table;
57
58
    public function __construct(
59
        Configuration $configuration,
60
        Logger $logger,
61
        CacheManager $cache,
62
        Extra $extra = null
63
    ) {
64
65
        parent::__construct($configuration, $logger);
66
67
        $this->table = new RoutingTable($logger);
68
69
        $this->cache = $cache;
70
71
        $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...
72
73
        $this->setTimestamp();
74
75
    }
76
77
    public function getType() {
78
79
        return $this->type;
80
81
    }
82
83
    public function getService() {
84
85
        return $this->service;
86
87
    }
88
89
    public function getParameters() {
90
91
        return $this->parameters;
0 ignored issues
show
Bug introduced by
The property parameters 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...
92
93
    }
94
95
    public function getClassName() {
96
97
        return $this->classname;
98
99
    }
100
101
    public function getInstance() {
102
103
        $class = $this->classname;
104
105
        if (class_exists($class)) {
106
107
            return new $class(
108
                $this->configuration,
0 ignored issues
show
Bug introduced by
The property configuration cannot be accessed from this context as it is declared private in class Comodojo\Dispatcher\Components\Model.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
109
                $this->logger,
0 ignored issues
show
Bug introduced by
The property logger cannot be accessed from this context as it is declared private in class Comodojo\Dispatcher\Components\Model.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
110
                $this->request,
111
                $this,
112
                $this->response,
113
                $this->extra
114
            );
115
116
        }
117
        else return null;
118
119
    }
120
121
    public function add($route, $type, $class, $parameters = array()) {
122
123
        $routeData = $this->get($route);
124
125
        if (is_null($routeData)) {
126
127
            $this->table->put($route, $type, $class, $parameters);
128
129
        } else {
130
131
            $this->table->set($route, $type, $class, $parameters);
132
133
        }
134
135
    }
136
137
    public function get($route) {
138
139
        return $this->table->get($route);
140
141
    }
142
143
    public function remove($route) {
144
145
        return $this->table->remove($route);
146
147
    }
148
149
    public function bypass($mode = true) {
150
151
        $this->bypass = filter_var($mode, FILTER_VALIDATE_BOOLEAN);
152
153
        return $this;
154
155
    }
156
157
    public function route(Request $request) {
158
159
        $this->request = $request;
160
161
        if (!$this->parse()) {
162
163
            throw new DispatcherException("Unable to find a valid route for the specified uri", 1, null, 404);
164
165
        }
166
167
168
    }
169
170
    public function compose(Response $response) {
171
172
        $this->response = $response;
173
174
        $service = $this->getInstance();
175
176
        if (!is_null($service)) {
177
178
            $result = "";
179
180
            $method = $this->request->method()->get();
181
182
            if (in_array($method, $service->getImplementedMethods())) {
183
184
                $callable = $service->getMethod($method);
185
186
                try {
187
188
                    $result = call_user_func(array($service, $callable));
189
190
                } catch (DispatcherException $de) {
191
192
                    throw new DispatcherException(sprintf("Service '%s' exception for method '%s': %s", $this->service, $method, $de->getMessage()), 1, $de, 500);
193
194
                } catch (Exception $e) {
195
196
                    throw new DispatcherException(sprintf("Service '%s' execution failed for method '%s': %s", $this->service, $method, $e->getMessage()), 1, $e, 500);
197
198
                }
199
200
            } else {
201
202
                throw new DispatcherException(sprintf("Service '%s' doesn't implement method '%s'", $this->service, $method), 1, null, 500);
203
204
            }
205
206
            $this->response->content()->set($result);
207
208
        } else {
209
210
            throw new DispatcherException(sprintf("Unable to execute service '%s'", $this->service), 1, null, 500);
211
212
        }
213
214
215
    }
216
217
    public function loadFromYaml($yaml) {
218
219
        $routes = Yaml::parse($yaml);
220
221
        if ( !empty($routes) ) {
222
223
            foreach( $routes as $name => $route ) {
224
225
                $this->add($route['route'], $route['type'], $route['class'], $route['parameters']);
226
227
            }
228
229
        }
230
231
        return $this;
232
233
    }
234
235
    private function parse() {
236
237
        $path = $this->request->uri()->getPath();
238
239
        foreach ($this->table->routes() as $regex => $value) {
240
241
            if (preg_match("/" . $regex . "/", $path, $matches)) {
242
243
                $this->evalUri($value['query'], $matches);
244
245
                foreach ($value['parameters'] as $parameter => $value) {
246
247
                    $this->request->query()->set($parameter, $value);
248
249
                }
250
251
                $this->classname  = $value['class'];
252
                $this->type       = $value['type'];
253
                $this->service    = implode('.', $value['service']);
254
                $this->service    = empty($this->service)?"default":$this->service;
255
256
                return true;
257
258
            }
259
260
        }
261
262
        return false;
263
264
    }
265
266
    private function evalUri($parameters, $bits) {
267
268
        $count  = 0;
0 ignored issues
show
Unused Code introduced by
$count 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...
269
270
        foreach ($parameters as $key => $value) {
271
272
            if (isset($bits[$key])) {
273
274
                if (preg_match('/^' . $value['regex'] . '$/', $bits[$key], $matches)) {
275
276
                    if (count($matches) == 1) $matches = $matches[0];
277
278
                    $this->request->query()->set($key, $matches);
279
280
                }
281
282
            } elseif ($value['required']) {
283
284
                throw new DispatcherException(sprintf("Required parameter '%s' not specified.", $key), 1, null, 500);
285
286
            }
287
288
        }
289
290
    }
291
292
}
293