Passed
Push — master ( 34a83f...053766 )
by kill
03:49
created

Route   A

Complexity

Total Complexity 23

Size/Duplication

Total Lines 139
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 2

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
dl 0
loc 139
rs 10
c 0
b 0
f 0
ccs 0
cts 64
cp 0
wmc 23
lcom 2
cbo 2

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A __call() 0 3 1
B addRoute() 0 30 6
A error() 0 3 1
A haltOnMatch() 0 3 1
A foundRoute() 0 21 4
B foundRegexRoute() 0 14 5
A dispatch() 0 20 4
1
<?php
2
/**
3
 * Created by rozbo at 2017/3/19 下午5:30
4
 */
5
6
namespace puck;
7
8
class Route {
9
    private $request;
10
11
    public function __construct(Request $request) {
12
        $this->request = $request;
13
        $this->errorCallback=function (){
14
            die("404");
0 ignored issues
show
Coding Style Compatibility introduced by
The method __construct() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
15
        };
16
    }
17
18
    public static $halts = false;
19
    private $routes = array();
20
    private $regexRoutes = [];
21
    public static $methods = array();
22
    public static $callbacks = array();
23
    private $patterns = array(
24
        ':any' => '[^/]+',
25
        ':num' => '[0-9]+',
26
        ':all' => '.*'
27
    );
28
    public $errorCallback;
29
30
    /**
31
     * Defines a route w/ callback and method
32
     */
33
    public function __call($method, $params) {
34
        $this->addRoute($method, $params[0], $params[1]);
35
    }
36
37
    /**
38
     * 添加一个路由
39
     * @param string $method
40
     * @param string $uri
41
     * @param mixed $callBack
42
     */
43
    public function addRoute($method, $uri, $callBack) {
44
        $method = strtoupper($method);
45
        //预定义正则路由
46
        if (strpos($uri, ':') !== false) {
47
            $searches = array_keys($this->patterns);
48
            $replaces = array_values($this->patterns);
49
            $uri = str_replace($searches, $replaces, $uri);
50
            $this->regexRoutes[] = [
51
                'method' => $method,
52
                'regex' => '#^' . $uri . '$#',
53
                'callback' => $callBack
54
            ];
55
        } //自定义正则路由
56
        elseif ($uri[0] == '#'
57
            || (strlen($uri) > 2 && tools\Str::endsWith($uri, '/') && tools\Str::startsWith($uri, '/'))
58
        ) {
59
            $this->regexRoutes[] = [
60
                'method' => $method,
61
                'regex' => $uri,
62
                'callback' => $callBack
63
            ];
64
        } //直接定义的路由
65
        else {
66
            $this->routes[$method . $uri] = [
67
                'method' => $method,
68
                'uri' => $uri,
69
                'callback' => $callBack
70
            ];
71
        }
72
    }
73
74
    /**
75
     * Defines callback if route is not found
76
     */
77
    public function error($callback) {
78
        $this->errorCallback = $callback;
79
    }
80
81
    public static function haltOnMatch($flag = true) {
82
        self::$halts = $flag;
83
    }
84
85
86
    private function foundRoute($route, $param = []) {
87
        try {
88
            if ($route['callback'] instanceof \Closure) {
89
                app()->invokeFunction($route['callback'],$param);
90
            } else {
91
                // Grab all parts based on a / separator
92
                $parts = explode('/', $route['callback']);
93
                // Collect the last index of the array
94
                $last = end($parts);
95
                // Grab the controller name and method call
96
                $segments = explode('@', $last);
97
                app()->invokeMethod($segments, $param);
98
            }
99
        } catch (\ReflectionException $e) {
100
            return false;
101
        }
102
        catch (\InvalidArgumentException $e) {
103
            return false;
104
        }
105
        return true;
106
    }
107
108
    public function foundRegexRoute($current) {
109
        foreach ($this->regexRoutes as $regexRoute) {
110
            if (preg_match($regexRoute['regex'], $current['uri'], $matched)) {
111
                if ($regexRoute['method'] == $current['method']
112
                    || $regexRoute['method'] == 'ANY'
113
                ) {
114
                    //将第一个成员,即是全部字符串剔除
115
                    array_shift($matched);
116
                    return $this->foundRoute($regexRoute, $matched);
117
                }
118
            }
119
        }
120
        return false;
121
    }
122
123
    /**
124
     * Runs the callback for the given request
125
     */
126
    public function dispatch() {
127
128
        $current['uri'] = $this->request->path();
0 ignored issues
show
Coding Style Comprehensibility introduced by
$current was never initialized. Although not strictly required by PHP, it is generally a good practice to add $current = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
129
        $current['method'] = $this->request->method();
130
        # 第一种情况,直接命中
131
        if (isset($this->routes[$current['method'] . $current['uri']])) {
132
            $this->foundRoute($this->routes[$current['method'] . $current['uri']]);
133
        } # 第二种情况,any命中
134
        else if (isset($this->routes['ANY' . $current['uri']])) {
135
            $this->foundRoute($this->routes['ANY' . $current['method']]);
136
        } # 第三种情况,正则命中
137
        else {
138
            if ($this->foundRegexRoute($current)) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
139
140
            } else {
141
                $route['callback'] = $this->errorCallback;
0 ignored issues
show
Coding Style Comprehensibility introduced by
$route was never initialized. Although not strictly required by PHP, it is generally a good practice to add $route = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
142
                $this->foundRoute($route);
143
            }
144
        }
145
    }
146
}