Completed
Push — master ( f9a3f2...2eb481 )
by Sinnarasa
02:45
created

Router::setMatcher()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 5
rs 9.4285
cc 2
eloc 4
nc 2
nop 1
1
<?php
2
3
namespace JetFire\Routing;
4
5
/**
6
 * Class Router
7
 * @package JetFire\Routing
8
 */
9
class Router
10
{
11
12
    /**
13
     * @var Route
14
     */
15
    public $route;
16
    /**
17
     * @var RouteCollection
18
     */
19
    public $collection;
20
    /**
21
     * @var ResponseInterface
22
     */
23
    public $response;
24
    /**
25
     * @var
26
     */
27
    public $middleware;
28
    /**
29
     * @var array
30
     */
31
    public $matcher = [];
32
    /**
33
     * @var
34
     */
35
    public $dispatcher;
36
    /**
37
     * @var array
38
     */
39
    private $config = [
40
        'templateExtension'      => ['.html', '.php', '.json', '.xml'],
41
        'templateCallback'       => [],
42
        'di'                 => '',
43
        'generateRoutesPath' => false,
44
    ];
45
46
    /**
47
     * @param RouteCollection $collection
48
     * @param ResponseInterface $response
49
     * @param Route $route
50
     */
51
    public function __construct(RouteCollection $collection,ResponseInterface $response = null,Route $route = null)
52
    {
53
        $this->collection = $collection;
54
        $this->response = is_null($response)? new Response() : $response;
55
        $this->response->setStatusCode(404);
56
        $this->route = is_null($route)? new Route() : $route;
57
        $this->config['di'] = function($class){
58
            return new $class;
59
        };
60
    }
61
62
    /**
63
     * @param array $config
64
     */
65
    public function setConfig($config)
66
    {
67
        $this->config = array_merge($this->config, $config);
68
    }
69
70
    /**
71
     * @return array
72
     */
73
    public function getConfig()
74
    {
75
        return $this->config;
76
    }
77
78
    /**
79
     * @param object|array $matcher
80
     */
81
    public function setMatcher($matcher){
82
        if(is_object($matcher))
83
            $matcher = [$matcher];
84
        $this->matcher = $matcher;
85
    }
86
87
    /**
88
     * @param string $matcher
89
     */
90
    public function addMatcher($matcher){
91
        $this->matcher[] = $matcher;
92
    }
93
94
    /**
95
     * @description main function
96
     */
97
    public function run()
98
    {
99
        $this->setUrl();
100
        if ($this->config['generateRoutesPath']) $this->collection->generateRoutesPath();
101
        if ($this->match()) {
102
            $this->handle();
103
            $this->callTarget();
104
        }
105
        $this->callResponse();
106
    }
107
108
    /**
109
     * @param null $url
110
     */
111
    public function setUrl($url = null)
0 ignored issues
show
Coding Style introduced by
setUrl uses the super-global variable $_GET 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...
Coding Style introduced by
setUrl 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...
112
    {
113
        if (is_null($url))
114
            $url = (isset($_GET['url'])) ? $_GET['url'] : substr(str_replace(str_replace('/index.php', '', $_SERVER['SCRIPT_NAME']), '', $_SERVER['REQUEST_URI']), 1);
115
        $this->route->setUrl('/' . trim(explode('?', $url)[0], '/'));
116
    }
117
118
    /**
119
     * @return bool
120
     */
121
    public function match()
122
    {
123
        foreach ($this->matcher as $key => $matcher) {
124
            if (call_user_func([$this->matcher[$key], 'match']))
125
                return true;
126
        }
127
        return false;
128
    }
129
130
    /**
131
     *
132
     */
133
    public function callTarget()
134
    {
135
        $target = is_array($this->route->getTarget('dispatcher'))?$this->route->getTarget('dispatcher'):[$this->route->getTarget('dispatcher')];
136
        if(!empty($target)) {
137
            foreach($target as $call) {
138
                $this->dispatcher = new $call($this->route, $this->response);
139
                call_user_func([$this->dispatcher, 'call']);
140
            }
141
        }
142
    }
143
144
    /**
145
     * @description handle middleware
146
     */
147
    private function handle()
148
    {
149
        $this->middleware = new Middleware($this);
150
        $this->middleware->globalMiddleware();
151
        $this->middleware->blockMiddleware();
152
        $this->middleware->classMiddleware();
153
        $this->middleware->routeMiddleware();
154
    }
155
156
    /**
157
     * @param array $responses
158
     */
159
    public function setResponses($responses = [])
160
    {
161
        $this->route->addDetail('response_templates', $responses);
162
    }
163
164
    /**
165
     * @description set response code
166
     */
167
    public function callResponse()
168
    {
169
        if (isset($this->route->getDetail()['response_templates']) && isset($this->route->getDetail()['response_templates'][$code = $this->response->getStatusCode()])) {
170
            $this->route->setCallback($this->route->getDetail()['response_templates'][$code]);
171
            foreach($this->matcher as $key => $instance) {
172
                foreach (call_user_func([$instance, 'getResolver']) as $match)
173
                    if (is_array($target = call_user_func_array([$instance, $match], [$this->route->getCallback()]))){
174
                        call_user_func_array([$instance, 'setTarget'],[$target]);
175
                        $this->callTarget();
176
                        break;
177
                    }
178
            }
179
            $this->response->setStatusCode($code);
180
        }
181
        $this->response->send();
182
    }
183
}
184