CDispatcherBasic::isCallableOrException()   B
last analyzed

Complexity

Conditions 8
Paths 22

Size

Total Lines 46

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 10.8584

Importance

Changes 0
Metric Value
cc 8
nc 22
nop 0
dl 0
loc 46
ccs 20
cts 31
cp 0.6452
crap 10.8584
rs 7.9337
c 0
b 0
f 0
1
<?php
2
3
namespace Anax\MVC;
4
5
/**
6
 * Dispatching to controllers.
7
 *
8
 */
9
class CDispatcherBasic implements \Anax\DI\IInjectionAware
10
{
11
    use \Anax\DI\TInjectionAware;
12
13
14
15
    /**
16
     * Properties
17
     *
18
     */
19
    private $controllerName;    // Name of controller
20
    private $controller;        // Actual controller
21
    private $action;            // Name of action
22
    private $params;            // Params
23
24
25
26
    /**
27
     * Prepare the name.
28
     *
29
     * @param string $name to prepare.
30
     *
31
     * @return string as the prepared name.
32
     */
33 1
    public function prepareName($name)
34
    {
35 1
        $name = empty($name) ? 'index' : $name;
36 1
        $name = strtolower($name);
37 1
        $name = str_replace(['-', '_'], ' ', $name);
38 1
        $name = ucwords($name);
39 1
        $name = str_replace(' ', '', $name);
40
        
41 1
        return $name;
42
    }
43
44
45
46
    /**
47
     * Set the name of the controller.
48
     *
49
     * @param string $name of the controller, defaults to 'index'.
50
     *
51
     * @return void
52
     */
53 1
    public function setControllerName($name = 'index')
54
    {
55 1
        $name = $this->prepareName($name) . 'Controller';
56
57 1
        $this->controllerName = $name;
58
59 1
        $this->controller = $this->di->has($name)
60 1
            ? $this->di->get($name)
61 1
            : null;
62 1
    }
63
64
65
66
    /**
67
     * Check if a controller exists with this name.
68
     *
69
     * @return void
70
     */
71 2
    public function isValidController()
72
    {
73 2
        return is_object($this->controller);
74
    }
75
76
77
78
    /**
79
     * Set the name of the action.
80
     *
81
     * @param string $name of the action, defaults to 'index'.
82
     *
83
     * @return void
84
     */
85 1
    public function setActionName($name = 'index')
86
    {
87 1
        $this->action = lcfirst($this->prepareName($name)) . 'Action';
88 1
    }
89
90
91
92
    /**
93
     * Set the params.
94
     *
95
     * @param array $params all parameters, defaults to empty.
96
     *
97
     * @return void
98
     */
99
    public function setParams($params = [])
100
    {
101
        $this->params = $params;
102
    }
103
104
105
106
    /**
107
     * Dispatch to a controller, action with parameters.
108
     *
109
     * @return bool
110
     */
111
    public function isCallable()
112
    {
113
        $handler = [$this->controller, $this->action];
0 ignored issues
show
Unused Code introduced by
$handler is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
114
115
        if (!method_exists($this->controller, $this->action)) {
116
            return false;
117
        }
118
119
        $reflection = new \ReflectionMethod($this->controller, $this->action);
120
        if (!$reflection->isPublic()) {
121
            return false;
122
        }
123
124
        return true;
125
    }
126
127
128
129
    /**
130
     * Inspect if callable and throw exception if parts is not callable.
131
     *
132
     * @return void.
0 ignored issues
show
Documentation introduced by
The doc-type void. could not be parsed: Unknown type name "void." at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
133
     */
134 2
    public function isCallableOrException()
135
    {
136 2
        $validController = $this->isValidController();
137
138 2
        $isMethod   = null;
139 2
        $isCallable = null;
140
141 2
        if ($validController) {
142
            $handler = [$this->controller, $this->action];
0 ignored issues
show
Unused Code introduced by
$handler is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
143
            $isMethod   = method_exists($this->controller, $this->action);
144
            $isCallable = $this->isCallable();
145
        }
146
147 2
        if (!($isMethod && $isCallable)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $isMethod of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
Bug Best Practice introduced by
The expression $isCallable of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
148
            $msg =
149
                "Trying to dispatch/forward to a non callable item. Controllername = '"
150 2
                . $this->controllerName
151 2
                . "', Action = '"
152 2
                . $this->action
153 2
                . "'."
154 2
            ;
155
156 2
            $not = $validController ? "" : "NOT";
157
            $msg .=
158 2
                " The controller named '$this->controllerName' does $not exist as part of of the
159
                service-container \$di.
160 2
                ";
161
162 2
            $services = $this->di->getServices();
163 2
            natcasesort($services);
164 2
            $services = implode("\n", $services);
165 2
            $msg .= " Loaded services are: <pre>$services</pre>\n";
166
167 2
            if ($validController) {
168
                $not = $isMethod ? "" : "NOT";
169
                $msg .= " The method '$this->action' does $not exist in the class '$this->controllerName'.";
170
171
                $not = $isCallable ? "" : "NOT";
172
                $msg .=
173
                    " The method '$this->action' is $not callable in the class '$this->controllerName'
174
                    (taking magic methods into consideration).";
175
            }
176
177 2
            throw new \Exception($msg);
178
        }
179
    }
180
181
182
183
    /**
184
     * Dispatch to a controller, action with parameters.
185
     *
186
     * @return mixed result from dispatched controller action.
187
     */
188 2
    public function dispatch()
189
    {
190 2
        $handler = [$this->controller, 'initialize'];
191 2
        if (method_exists($this->controller, 'initialize') && is_callable($handler)) {
192
            call_user_func($handler);
193
        }
194
195 2
        $this->isCallableOrException();
196
197
        return call_user_func_array([$this->controller, $this->action], $this->params);
198
    }
199
200
201
    /**
202
     * Forward to a controller, action with parameters.
203
     *
204
     * @param array $forward with details for controller, action, parameters.
205
     *
206
     * @return mixed result from dispatched controller action.
207
     */
208
    public function forward($forward = [])
209
    {
210
        $controller = isset($forward['controller'])
211
            ? $forward['controller']
212
            : null;
213
214
        $action = isset($forward['action'])
215
            ? $forward['action']
216
            : null;
217
        
218
        $params = isset($forward['params'])
219
            ? $forward['params']
220
            : [];
221
222
        $this->setControllerName($controller);
223
        $this->setActionName($action);
224
        $this->setParams($params);
225
226
        $this->isCallableOrException();
227
        return $this->dispatch();
228
    }
229
}
230