Completed
Push — master ( 8f6f9d...d708fb )
by Sinnarasa
02:41
created

ArrayMatcher::matchTemplate()   D

Complexity

Conditions 10
Paths 17

Size

Total Lines 31
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
c 4
b 0
f 0
dl 0
loc 31
rs 4.8196
cc 10
eloc 24
nc 17
nop 1

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace JetFire\Routing\Matcher;
4
5
6
use JetFire\Routing\Router;
7
8
/**
9
 * Class RoutesMatch
10
 * @package JetFire\Routing\Match
11
 */
12
class ArrayMatcher implements MatcherInterface
13
{
14
15
    /**
16
     * @var
17
     */
18
    private $router;
19
    /**
20
     * @var array
21
     */
22
    private $request = [];
23
24
    /**
25
     * @var array
26
     */
27
    private $matcher = ['matchClosure','matchController','matchTemplate'];
28
29
    /**
30
     * @var array
31
     */
32
    private $dispatcher = [
33
        'matchClosure' => 'JetFire\Routing\Dispatcher\ClosureDispatcher',
34
        'matchController' => 'JetFire\Routing\Dispatcher\ControllerDispatcher',
35
        'matchTemplate' => 'JetFire\Routing\Dispatcher\TemplateDispatcher',
36
    ];
37
38
    /**
39
     * @param Router $router
40
     */
41
    public function __construct(Router $router)
42
    {
43
        $this->router = $router;
44
    }
45
46
    /**
47
     * @param string $matcher
48
     */
49
    public function addMatcher($matcher){
50
        $this->matcher[] = $matcher;
51
    }
52
53
    /**
54
     * @return array
55
     */
56
    public function getMatcher()
57
    {
58
        return $this->matcher;
59
    }
60
61
    /**
62
     * @param array $dispatcher
63
     */
64
    public function setDispatcher($dispatcher = []){
65
        $this->dispatcher = $dispatcher;
66
    }
67
68
    /**
69
     * @param $method
70
     * @param $class
71
     * @return mixed|void
72
     * @internal param array $dispatcher
73
     */
74
    public function addDispatcher($method,$class){
75
        $this->dispatcher[$method] = $class;
76
    }
77
78
    /**
79
     * @return bool
80
     */
81
    public function match()
82
    {
83
        $this->request = [];
84
        for ($i = 0; $i < $this->router->collection->countRoutes; ++$i) {
85
            $this->request['prefix'] = ($this->router->collection->getRoutes('prefix_' . $i) != '') ? $this->router->collection->getRoutes('prefix_' . $i) : '';
86
            foreach ($this->router->collection->getRoutes('routes_' . $i) as $route => $params) {
87
                $this->request['params'] = $params;
88
                $this->request['collection_index'] = $i;
89
                $this->request['route'] = preg_replace_callback('#:([\w]+)#', [$this, 'paramMatch'], '/' . trim(trim($this->request['prefix'], '/') . '/' . trim($route, '/'), '/'));
90
                if ($this->routeMatch('#^' . $this->request['route'] . '$#')) {
91
                    $this->setRoute();
92
                    return $this->generateTarget();
93
                }
94
            }
95
        }
96
        unset($this->request);
97
        return false;
98
    }
99
100
    /**
101
     * @param $match
102
     * @return string
103
     */
104
    private function paramMatch($match)
105
    {
106
        if (is_array($this->request['params']) && isset($this->request['params']['arguments'][$match[1]])) {
107
            $this->request['params']['arguments'][$match[1]] = str_replace('(', '(?:', $this->request['params']['arguments'][$match[1]]);
108
            return '(' . $this->request['params']['arguments'][$match[1]] . ')';
109
        }
110
        return '([^/]+)';
111
    }
112
113
    /**
114
     * @param $regex
115
     * @return bool
116
     */
117
    private function routeMatch($regex)
118
    {
119
        if (substr($this->request['route'], -1) == '*') {
120
            $pos = strpos($this->request['route'], '*');
121 View Code Duplication
            if (substr($this->router->route->getUrl(), 0, $pos) == substr($this->request['route'], 0, $pos) && isset($this->request['params']))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
122
                return true;
123
        }
124 View Code Duplication
        if (preg_match($regex, $this->router->route->getUrl(), $this->request['parameters'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
125
            array_shift($this->request['parameters']);
126
            return true;
127
        }
128
        return false;
129
    }
130
131
    /**
132
     * @return bool
133
     */
134
    private function generateTarget()
135
    {
136
        if($this->validMethod()) {
137
            foreach($this->matcher as $match)
138
                if(call_user_func_array([$this,$match],[$this->router->route->getCallback()])) break;
139
            $index = isset($this->request['collection_index']) ? $this->request['collection_index'] : 0;
140
            $this->router->route->addTarget('block',$this->router->collection->getRoutes('block_'.$index));
141
            $this->router->route->addTarget('view_dir',$this->router->collection->getRoutes('view_dir_'.$index));
142
            $this->router->response->setStatusCode(202);
143
        }else
144
            $this->router->response->setStatusCode(405);
145
        return $this->router->route->hasTarget();
146
    }
147
148
    /**
149
     *
150
     */
151
    private function setRoute(){
152
        if (isset($this->request['params'])) {
153
            if(is_callable($this->request['params']))
154
                $this->router->route->setCallback($this->request['params']);
155
            else {
156
                (is_array($this->request['params']) && isset($this->request['params']['use']))
157
                    ? $this->router->route->setCallback($this->request['params']['use'])
158
                    : $this->router->route->setCallback($this->request['params']);
159
                if (isset($this->request['params']['name'])) $this->router->route->setName($this->request['params']['name']);
160
                if (isset($this->request['params']['method'])) $this->request['params']['method'] = is_array($this->request['params']['method']) ? $this->request['params']['method'] : [$this->request['params']['method']];
161
            }
162
        }
163
        $this->router->route->setDetail($this->request);
164
    }
165
166
    /**
167
     * @return bool
168
     */
169
    public function validMethod()
0 ignored issues
show
Coding Style introduced by
validMethod uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
170
    {
171
        if(is_callable($this->request['params']))return true;
172
        if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest')
173
            return (isset($this->request['params']['ajax']) && $this->request['params']['ajax'] === true) ? true : false;
174
        $method = (isset($this->router->route->getDetail()['params']['method'])) ? $this->router->route->getDetail()['params']['method'] : ['GET'];
175
        return (in_array($this->router->route->getMethod(), $method)) ? true : false;
176
    }
177
178
179
    /**
180
     * @param $callback
181
     * @return bool
182
     */
183
    public function matchClosure($callback)
184
    {
185
        if (is_callable($callback)) {
186
            $this->router->route->setTarget([
187
                'dispatcher' => $this->dispatcher['matchClosure'],
188
                'closure' => $callback
189
            ]);
190
            return true;
191
        }
192
        return false;
193
    }
194
195
    /**
196
     * @param $callback
197
     * @throws \Exception
198
     * @return bool
199
     */
200
    public function matchController($callback)
201
    {
202
        if (is_string($callback) && strpos($callback, '@') !== false) {
203
            $routes = explode('@', $callback);
204
            if (!isset($routes[1])) $routes[1] = 'index';
205
            $index = isset($this->request['collection_index']) ? $this->request['collection_index'] : 0;
206
            $class = (class_exists($routes[0]))
207
                ? $routes[0]
208
                : $this->router->collection->getRoutes()['ctrl_namespace_'.$index].$routes[0];
209
            if (!class_exists($class))
210
                throw new \Exception('Class "' . $class . '." is not found');
211
            if (method_exists($class, $routes[1])) {
212
                $this->router->route->setTarget([
213
                    'dispatcher' => $this->dispatcher['matchController'],
214
                    'di' => $this->router->getConfig()['di'],
215
                    'controller' => $class,
216
                    'action' => $routes[1]
217
                ]);
218
                return true;
219
            }
220
            throw new \Exception('The required method "' . $routes[1] . '" is not found in "' . $class . '"');
221
        }
222
        return false;
223
    }
224
225
    /**
226
     * @param $callback
227
     * @throws \Exception
228
     * @return bool
229
     */
230
    public function matchTemplate($callback)
231
    {
232
        if(is_string($callback)) {
233
            $path = trim($callback, '/');
234
            $extension = substr(strrchr($path, "."), 1);
235
            $index = isset($this->request['collection_index']) ? $this->request['collection_index'] : 0;
236
            $viewDir = $this->router->collection->getRoutes('view_dir_' . $index);
237
            $target = null;
238
            if (in_array('.' . $extension, $this->router->getConfig()['templateExtension']) && (is_file($fullPath = $viewDir . $path) || is_file($fullPath = $path)))
239
                $target = $fullPath;
240
            else {
241
                foreach ($this->router->getConfig()['templateExtension'] as $ext) {
242
                    if (is_file($fullPath = $viewDir . $path . $ext) || is_file($fullPath = $path . $ext)) {
243
                        $target = $fullPath;
244
                        $extension = substr(strrchr($ext, "."), 1);
245
                        break;
246
                    }
247
                }
248
            }
249
            if(is_null($target))
250
                throw new \Exception('Template file "' . $path . '" is not found in "' . $viewDir . '"');
251
            $this->router->route->setTarget([
252
                'dispatcher' => $this->dispatcher['matchTemplate'],
253
                'template'   => $target,
254
                'extension'  => $extension,
255
                'callback'   => $this->router->getConfig()['templateCallback']
256
            ]);
257
            return true;
258
        }
259
        return false;
260
    }
261
}
262