Completed
Push — master ( ebff66...d47983 )
by Markus
06:38 queued 02:43
created

CDispatcherBasic::isCallableOrException()   C

Complexity

Conditions 8
Paths 22

Size

Total Lines 42
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 8
eloc 25
c 1
b 0
f 1
nc 22
nop 0
dl 0
loc 42
rs 5.3846
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
    public function prepareName($name)
34
    {
35
        $name = empty($name) ? 'index' : $name;
36
        $name = strtolower($name);
37
        $name = str_replace(['-', '_'], ' ', $name);
38
        $name = ucwords($name);
39
        $name = str_replace(' ', '', $name);
40
        
41
        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
    public function setControllerName($name = 'index')
54
    {
55
        $name = $this->prepareName($name) . 'Controller';
56
57
        $this->controllerName = $name;
58
59
        $this->controller = $this->di->has($name)
60
            ? $this->di->get($name)
61
            : null;
62
    }
63
64
65
66
    /**
67
     * Check if a controller exists with this name.
68
     *
69
     * @return void
70
     */
71
    public function isValidController()
72
    {
73
        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
    public function setActionName($name = 'index')
86
    {
87
        $this->action = lcfirst($this->prepareName($name)) . 'Action';
88
    }
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
    public function isCallableOrException()
135
    {
136
        $validController = $this->isValidController();
137
138
        $isMethod   = null;
139
        $isCallable = null;
140
141
        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 = is_callable($handler);
0 ignored issues
show
Unused Code Comprehensibility introduced by
56% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

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