Completed
Push — master ( 1798cf...75b2e6 )
by Bohuslav
01:48
created

DispatcherClosure::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
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 9
nc 2
nop 3
1
<?php
2
namespace Kambo\Router\Dispatchers;
3
4
// \Spl
5
use InvalidArgumentException;
6
7
// \Kambo\Router
8
use Kambo\Router\Dispatchers\Interfaces\DispatcherInterface;
9
use Kambo\Router\Route\Route;
10
11
/**
12
 * Dispatcher with closure support
13
 *
14
 * @author  Bohuslav Simek <[email protected]>
15
 * @license Apache-2.0
16
 * @package Kambo\Router\Dispatchers
17
 */
18
class DispatcherClosure implements DispatcherInterface
19
{
20
    /**
21
     * Not found handler will be called if nothing has been found.
22
     *
23
     * @var \Closure
24
     */
25
    private $notFoundHandler;
26
27
    /**
28
     * Dispatch found route with given parameters
29
     *
30
     * @param Route $route      found route
31
     * @param mixed $parameters parameters for route
32
     *
33
     * @return mixed
34
     */
35
    public function dispatchRoute(Route $route, array $parameters)
36
    {
37
        $handler = $route->getHandler();
38
        if ($this->isClosure($handler)) {
39
            $paramMap  = $this->getFunctionArgumentsNames($handler);
40
            $arguments = $this->getFunctionArguments(
41
                $paramMap,
42
                $parameters,
43
                $route->getParameters()
44
            );
45
46
            return call_user_func_array($handler, $arguments);
47
        } else {
48
            return $this->dispatchNotFound();
49
        }
50
    }
51
52
    /**
53
     * Called if nothing was not found.
54
     * Can call a a defined handler or simply do nothing if the handler is
55
     * not specified.
56
     *
57
     * @return mixed|null
58
     */
59
    public function dispatchNotFound()
60
    {
61
        if (isset($this->notFoundHandler)) {
62
            return call_user_func($this->notFoundHandler);
63
        }
64
65
        return null;
66
    }
67
68
    /**
69
     * Set not found handler
70
     *
71
     * @return self for fluent interface
72
     *
73
     * @throws InvalidArgumentException if the provided value is not closure
74
     */
75
    public function setNotFoundHandler($handler)
76
    {
77
        if (!$this->isClosure($handler)) {
78
            throw new InvalidArgumentException(
79
                'Handler must be closure'
80
            );
81
        }
82
83
        $this->notFoundHandler = $handler;
84
85
        return $this;
86
    }
87
88
    // ------------ PRIVATE METHODS
89
90
    /**
91
     * Check if variable is closure
92
     *
93
     * @param mixed $type variable to check
94
     *
95
     * @return boolean return true if is
96
     */
97
    private function isClosure($type)
98
    {
99
        return is_object($type) && ($type instanceof \Closure);
100
    }
101
102
    /**
103
     * Get arguments for closure function in proper order
104
     * from provided parameters
105
     *
106
     * @param mixed $paramMap   parameter map for getting proper order
107
     * @param mixed $matches    parameters from request
108
     * @param mixed $parameters expected parameters from route
109
     *
110
     * @return array Parameters in right order, if there are not any
111
     *         parametrs an empty array is returned.
112
     */
113
    private function getFunctionArguments($paramMap, $matches, $parameters)
114
    {
115
        $output  = [];
116
        $matches = array_values($matches);
117
        if (isset($parameters)) {
118 View Code Duplication
            foreach ($parameters as $key => $valueName) {
119
                foreach ($paramMap as $possition => $value) {
120
                    if ($value == $valueName[1][0]) {
121
                        $output[] = $matches[$possition];
122
                    }
123
                }
124
            }
125
        }
126
127
        return $output;
128
    }
129
130
    /**
131
     * Get name of parameters for provided closure
132
     *
133
     * @param \Closure $closure
134
     *
135
     * @return array
136
     */
137
    private function getFunctionArgumentsNames($closure)
138
    {
139
        $closureReflection = new \ReflectionFunction($closure);
140
        $result            = [];
141
        foreach ($closureReflection->getParameters() as $param) {
142
            $result[] = $param->name;
143
        }
144
145
        return $result;
146
    }
147
}
148