Completed
Push — master ( 3e8504...bdb393 )
by Sinnarasa
02:04
created

Middleware::callHandlers()   B

Complexity

Conditions 5
Paths 6

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 8
rs 8.8571
c 1
b 0
f 0
cc 5
eloc 5
nc 6
nop 2
1
<?php
2
3
namespace JetFire\Routing;
4
5
use ReflectionMethod;
6
7
8
/**
9
 * Class Middleware
10
 * @package JetFire\Routing
11
 */
12
class Middleware implements MiddlewareInterface
13
{
14
15
    /**
16
     * @var Router
17
     */
18
    private $router;
19
    /**
20
     * @var bool
21
     */
22
    private $next = true;
23
24
    /**
25
     * @var array
26
     */
27
    protected $callbacks = [
28
        'globalMiddleware',
29
        'blockMiddleware',
30
        'classMiddleware',
31
        'routeMiddleware',
32
    ];
33
34
    /**
35
     * @var array
36
     */
37
    private $middleware = [];
38
39
    /**
40
     * @param Router $router
41
     */
42
    public function __construct(Router $router)
43
    {
44
        $this->router = $router;
45
    }
46
47
    /**
48
     * @return array
49
     */
50
    public function getMiddleware()
51
    {
52
        return $this->middleware;
53
    }
54
55
    /**
56
     * @param $middleware
57
     * @return mixed|void
58
     */
59
    public function setBeforeCallback($middleware)
60
    {
61
        $this->setMiddleware('before', $middleware);
62
    }
63
64
    /**
65
     * @param $middleware
66
     * @return mixed|void
67
     */
68
    public function setAfterCallback($middleware)
69
    {
70
        $this->setMiddleware('after', $middleware);
71
    }
72
73
    /**
74
     * @param $action
75
     * @param $middleware
76
     */
77
    private function setMiddleware($action, $middleware)
78
    {
79
        if (is_string($middleware)) {
80
            $middleware = rtrim($middleware, '/');
81
        }
82
        if (is_array($middleware)) {
83
            $this->middleware[$action] = $middleware;
84
        } elseif (is_file($middleware) && is_array($mid = include $middleware)) {
85
            $this->middleware[$action] = $mid;
86
        } else {
87
            throw new \InvalidArgumentException('Accepted argument for setMiddleware are array and array file');
88
        }
89
    }
90
91
    /**
92
     * @return Router
93
     */
94
    public function getCallbacks()
95
    {
96
        return $this->callbacks;
97
    }
98
99
    /**
100
     * @description global middleware
101
     * @param $action
102
     */
103
    public function globalMiddleware($action)
104
    {
105
        if (isset($this->middleware[$action]['global_middleware'])) {
106
            $this->callHandlers($this->middleware[$action]['global_middleware']);
107
        }
108
    }
109
110
    /**
111
     * @description block middleware
112
     * @param $action
113
     */
114
    public function blockMiddleware($action)
115
    {
116 View Code Duplication
        if (isset($this->middleware[$action]['block_middleware'])) {
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...
117
            if (isset($this->middleware[$action]['block_middleware'][$this->router->route->getTarget('block')])) {
118
                $blocks = $this->middleware[$action]['block_middleware'][$this->router->route->getTarget('block')];
119
                $this->callHandlers($blocks);
120
            }
121
        }
122
    }
123
124
    /**
125
     * @description controller middleware
126
     * @param $action
127
     */
128
    public function classMiddleware($action)
129
    {
130
        if (isset($this->middleware[$action]['class_middleware'])) {
131
            $ctrl = str_replace('\\', '/', $this->router->route->getTarget('controller'));
132
            if (isset($this->middleware[$action]['class_middleware'][$ctrl]) && class_exists($this->router->route->getTarget('controller'))) {
133
                $classes = $this->middleware[$action]['class_middleware'][$ctrl];
134
                $this->callHandlers($classes);
135
            }
136
        }
137
    }
138
139
    /**
140
     * @description route middleware
141
     * @param $action
142
     */
143
    public function routeMiddleware($action)
144
    {
145
        if (isset($this->middleware[$action]['route_middleware'])) {
146 View Code Duplication
            if (isset($this->router->route->getPath()['middleware']) && class_exists($this->middleware[$action]['route_middleware'][$this->router->route->getPath()['middleware']])) {
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...
147
                $classes = $this->middleware[$action]['route_middleware'][$this->router->route->getPath()['middleware']];
148
                $this->callHandlers($classes);
149
            }
150
        }
151
    }
152
153
    /**
154
     * @param $handlers
155
     * @param array $params
156
     */
157
    private function callHandlers($handlers, $params = []){
158
        $handlers = is_array($handlers) ? $handlers : [$handlers];
159
        foreach ($handlers as $handler) {
160
            if($this->next && $this->handle($handler, $params) !== true){
161
                break;
162
            }
163
        }
164
    }
165
166
    /**
167
     * @param $callback
168
     * @param array $params
169
     * @return mixed
170
     */
171
    private function handle($callback, $params = [])
172
    {
173
        $callback = explode('@', $callback);
174
        $response = true;
175
        $method = isset($callback[1]) ? $callback[1] : 'handle';
176
        if (class_exists($callback[0])) {
177
            $instance = call_user_func($this->router->getConfig()['di'], $callback[0]);
178
            if (method_exists($instance, $method)) {
179
                $reflectionMethod = new ReflectionMethod($instance, $method);
180
                $dependencies = $params;
181
                foreach ($reflectionMethod->getParameters() as $arg) {
182
                    if (!is_null($arg->getClass())) {
183
                        $dependencies[] = $this->getClass($arg->getClass()->name);
184
                    }
185
                }
186
                $dependencies = array_merge($dependencies, [$this->router->route]);
187
                $response = $reflectionMethod->invokeArgs($instance, $dependencies);
188
                if(is_array($response) && isset($response['call'])){
189
                    if(isset($response['response']) && $response['response'] instanceof ResponseInterface){
190
                        $this->router->response = $response['response'];
191
                    }
192
                    $params = isset($response['params']) ? $response['params']: [];
193
                    $this->callHandlers($response['call'], $params);
194
                    $this->next = isset($response['next']) ? (bool)$response['next'] : false;
195
                } else if ($response instanceof ResponseInterface) {
196
                    $this->router->response = $response;
197
                }
198
            }
199
        }
200
        return $response;
201
    }
202
203
    /**
204
     * @param $class
205
     * @return Route|RouteCollection|Router|mixed
206
     */
207
    private function getClass($class)
208
    {
209
        switch ($class) {
210
            case Route::class:
211
                return $this->router->route;
212
            case Router::class:
213
                return $this->router;
214
            case RouteCollection::class:
215
                return $this->router->collection;
216
            case ResponseInterface::class:
217
                return $this->router->response;
218
            default:
219
                return call_user_func_array($this->router->getConfig()['di'], [$class]);
220
        }
221
    }
222
}
223