Completed
Push — master ( 9a95ba...d1c5d4 )
by Sinnarasa
02:47
created

Router::handle()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

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