Completed
Push — master ( c6aea9...538fb8 )
by Flo
05:04 queued 02:10
created

Dispatcher::saveIntoCache()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 14
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 8
nc 2
nop 2
1
<?php
2
/**
3
 * Class Dispatcher
4
 *
5
 * @package Faulancer\Controller
6
 * @author Florian Knapp <[email protected]>
7
 */
8
namespace Faulancer\Controller;
9
10
use Faulancer\Exception\ClassNotFoundException;
11
use Faulancer\Exception\DispatchFailureException;
12
use Faulancer\Form\AbstractFormHandler;
13
use Faulancer\Helper\Reflection\AnnotationParser;
14
use Faulancer\Http\Request;
15
use Faulancer\Http\Response;
16
use Faulancer\Helper\DirectoryIterator;
17
use Faulancer\Exception\MethodNotFoundException;
18
use Faulancer\Service\Config;
19
use Faulancer\Session\SessionManager;
20
21
/**
22
 * Class Dispatcher
23
 */
24
class Dispatcher
25
{
26
27
    /**
28
     * The current request object
29
     * @var Request
30
     */
31
    protected $request;
32
33
    /**
34
     * Dispatcher constructor.
35
     *
36
     * @param Request $request
37
     * @param Config  $config
38
     * @param boolean $routeCacheEnabled
39
     */
40
    public function __construct(Request $request, Config $config, $routeCacheEnabled = true)
41
    {
42
        $this->request           = $request;
43
        $this->routeCacheEnabled = $routeCacheEnabled;
0 ignored issues
show
Bug introduced by
The property routeCacheEnabled does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
44
        $this->config            = $config;
0 ignored issues
show
Bug introduced by
The property config does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
45
    }
46
47
    /**
48
     * Bootstrap for every route call
49
     *
50
     * @return Response|mixed
51
     * @throws MethodNotFoundException
52
     * @throws ClassNotFoundException
53
     * @throws DispatchFailureException
54
     */
55
    public function run()
56
    {
57
        if ($formRequest = $this->handleFormRequest()) {
58
            return $formRequest;
59
        }
60
61
        $response = new Response();
62
63
        try {
64
65
            $target = $this->getRoute($this->request->getUri());
66
            $class  = $target['class'];
67
            $action = $target['action'] . 'Action';
68
69
            $class = new $class();
70
71
            if (isset($target['var'])) {
72
                $response->setContent(call_user_func_array([$class, $action], $target['var']));
73
            } else {
74
                $response->setContent($class->$action());
75
            }
76
77
        } catch (MethodNotFoundException $e) {
78
79
            throw new DispatchFailureException();
80
81
        }
82
83
        return $response;
84
    }
85
86
    /**
87
     * Get data for specific route path
88
     *
89
     * @param string $path
90
     *
91
     * @return array
92
     * @throws MethodNotFoundException
93
     */
94
    private function getRoute($path)
95
    {
96
        $routes = require $this->config->get('routeFile');
97
98
        foreach ($routes as $name => $data) {
99
100
            if ($target = $this->getDirectMatch($path, $data)) {
101
                return $target;
102
            } else if ($target = $this->getVariableMatch($path, $data)) {
103
                return $target;
104
            }
105
106
        }
107
108
        throw new MethodNotFoundException();
109
    }
110
111
    /**
112
     * Determines if we have a direct/static route match
113
     *
114
     * @param string $uri  The request uri
115
     * @param array  $data The result from ClassParser
116
     *
117
     * @return array
118
     * @throws MethodNotFoundException
119
     */
120
    private function getDirectMatch(string $uri, array $data)
121
    {
122
        if ($uri === $data['path']) {
123
124
            if (strcasecmp($data['method'], $this->request->getMethod()) === 0) {
125
126
                return [
127
                    'class'  => $data['controller'],
128
                    'action' => $data['action']
129
                ];
130
131
            }
132
133
            throw new MethodNotFoundException('Non valid request method available.');
134
135
        }
136
137
        return [];
138
    }
139
140
    /**
141
     * Determines if we have a variable route match
142
     *
143
     * @param string $uri
144
     * @param array  $data
145
     *
146
     * @return array
147
     * @throws MethodNotFoundException
148
     */
149
    private function getVariableMatch(string $uri, array $data)
150
    {
151
        $var = [];
152
153
        if ($data['path'] === '/') {
154
            return [];
155
        }
156
157
        $regex = str_replace(
158
            ['/', '___'],
159
            ['\/', '+'],
160
            $data['path']
161
        );
162
163
        if (preg_match('|^' . $regex . '$|', $uri, $var)) {
164
165
            array_splice($var, 0, 1);
166
167
            return [
168
                'class'  => $data['controller'],
169
                'action' => $data['action'],
170
                'var'    => $var
171
            ];
172
173
        }
174
175
        return [];
176
    }
177
178
    /**
179
     * Detect a form request
180
     *
181
     * @return boolean
182
     */
183
    private function handleFormRequest()
184
    {
185
        if (strpos($this->request->getUri(), '/formrequest/') !== 0 && $this->request->isPost()) {
186
            return false;
187
        }
188
189
        $handlerName  = ucfirst(str_replace('/formrequest/', '', $this->request->getUri()));
190
        $handlerClass = '\\' . $this->config->get('namespacePrefix') . '\\Form\\' . $handlerName . 'Handler';
191
192
        if (class_exists($handlerClass)) {
193
194
            /** @var AbstractFormHandler $handler */
195
            $handler = new $handlerClass($this->request, SessionManager::instance());
196
            return $handler->run();
197
198
        }
199
200
        return false;
201
    }
202
203
}