Test Failed
Branch develop (ab83c3)
by Bohuslav
02:47
created

ClosureAutoBind::getFunctionArguments()   B

Complexity

Conditions 5
Paths 2

Size

Total Lines 16
Code Lines 9

Duplication

Lines 7
Ratio 43.75 %

Importance

Changes 0
Metric Value
dl 7
loc 16
c 0
b 0
f 0
rs 8.8571
cc 5
eloc 9
nc 2
nop 3
1
<?php
2
namespace Kambo\Router\Dispatcher;
3
4
// \Spl
5
use Closure;
6
use InvalidArgumentException;
7
use ReflectionFunction;
8
9
// \Kambo\Router
10
use Kambo\Router\Dispatcher;
11
use Kambo\Router\Route\Route\Parsed;
12
13
/**
14
 * Dispatcher with closure support
15
 *
16
 * @package Kambo\Router\Dispatcher
17
 * @author  Bohuslav Simek <[email protected]>
18
 * @license MIT
19
 */
20
class ClosureAutoBind implements Dispatcher
21
{
22
    /**
23
     * Not found handler will be called if nothing has been found.
24
     *
25
     * @var \Closure
26
     */
27
    private $notFoundHandler;
28
29
    /**
30
     * Dispatch found route with given parameters
31
     *
32
     * @param \Kambo\Router\Route\Route\Parsed $route      Instance of found and parsed route.
33
     * @param array                            $parameters Additional parameters which will be passed into
34
     *                                                     the dispatcher.
35
     *
36
     * @return mixed
37
     */
38
    public function dispatchRoute(Parsed $route, array $parameters)
39
    {
40
        $handler = $route->getHandler();
41
        if ($this->isClosure($handler)) {
42
            $paramMap  = $this->getFunctionArgumentsNames($handler);
43
            $arguments = $this->getFunctionArguments(
44
                $paramMap,
45
                $route->getParameters(),
46
                $route->getPlaceholders()
47
            );
48
49
            return call_user_func_array($handler, $arguments);
50
        } else {
51
            return $this->dispatchNotFound();
52
        }
53
    }
54
55
    /**
56
     * Called if any of route did not match the request.
57
     * Call the defined handler or simply do nothing if the handler is not
58
     * specified.
59
     *
60
     * @return mixed|null
61
     */
62
    public function dispatchNotFound()
63
    {
64
        if (isset($this->notFoundHandler)) {
65
            return call_user_func($this->notFoundHandler);
66
        }
67
68
        return null;
69
    }
70
71
    /**
72
     * Sets not found handler
73
     *
74
     * @param string $handler handler that will be excuted if nothing has been
75
     *                        found
76
     *
77
     * @return self for fluent interface
78
     *
79
     * @throws InvalidArgumentException if the provided value is not closure
80
     */
81
    public function setNotFoundHandler($handler)
82
    {
83
        if (!$this->isClosure($handler)) {
84
            throw new InvalidArgumentException(
85
                'Handler must be closure'
86
            );
87
        }
88
89
        $this->notFoundHandler = $handler;
0 ignored issues
show
Documentation Bug introduced by
It seems like $handler of type string is incompatible with the declared type object<Closure> of property $notFoundHandler.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
90
91
        return $this;
92
    }
93
94
    // ------------ PRIVATE METHODS
95
96
    /**
97
     * Check if variable is closure
98
     *
99
     * @param mixed $type variable to check
100
     *
101
     * @return boolean return true if is
102
     */
103
    private function isClosure($type)
104
    {
105
        return is_object($type) && ($type instanceof Closure);
106
    }
107
108
    /**
109
     * Get arguments for closure function in proper order
110
     * from provided parameters
111
     *
112
     * @param mixed $paramMap   parameter map for getting proper order
113
     * @param mixed $matches    parameters from request
114
     * @param mixed $parameters expected parameters from route
115
     *
116
     * @return array Parameters in right order, if there are not any
117
     *         parametrs an empty array is returned.
118
     */
119
    private function getFunctionArguments($paramMap, $matches, $parameters)
120
    {
121
        $output  = [];
122
        $matches = array_values($matches);
123
        if (isset($parameters)) {
124 View Code Duplication
            foreach ($parameters as $valueName) {
125
                foreach ($paramMap as $possition => $value) {
126
                    if ($value == $valueName[1][0]) {
127
                        $output[] = $matches[$possition];
128
                    }
129
                }
130
            }
131
        }
132
133
        return $output;
134
    }
135
136
    /**
137
     * Get name of parameters for provided closure
138
     *
139
     * @param \Closure $closure
140
     *
141
     * @return array
142
     */
143
    private function getFunctionArgumentsNames($closure)
144
    {
145
        $closureReflection = new ReflectionFunction($closure);
146
        $result            = [];
147
        foreach ($closureReflection->getParameters() as $param) {
148
            $result[] = $param->name;
149
        }
150
151
        return $result;
152
    }
153
}
154