Passed
Push — master ( 161efd...324fc7 )
by Alex
02:17
created

Application.php (1 issue)

Labels
Severity
1
<?php
2
namespace Mezon\Application;
3
4
/**
5
 * Class Application
6
 *
7
 * @package Mezon
8
 * @subpackage Application
9
 * @author Dodonov A.A.
10
 * @version v.1.0 (2019/08/13)
11
 * @copyright Copyright (c) 2019, aeon.org
12
 */
13
14
/**
15
 * Base class of the application
16
 */
17
class Application
18
{
19
20
    /**
21
     * Router object
22
     *
23
     * @var \Mezon\Router\Router
24
     */
25
    private $router = null;
26
27
    /**
28
     * Params fetcher
29
     *
30
     * @var \Mezon\Transport\RequestParams
31
     */
32
    private $requestParams = null;
33
34
    /**
35
     * Constructor
36
     */
37
    function __construct()
38
    {
39
        // getting application's actions
40
        $this->router = new \Mezon\Router\Router();
41
42
        $this->router->fetchActions($this);
43
44
        $reflector = new \ReflectionClass(get_class($this));
45
        $classPath = dirname($reflector->getFileName());
46
47
        if (file_exists($classPath.'/conf/routes.php')) {
48
            $this->loadRoutesFromConfig($classPath.'/conf/routes.php');
49
        }
50
51
        if (file_exists($classPath.'/conf/routes.json')) {
52
            $this->loadRoutesFromConfig($classPath.'/conf/routes.json');
53
        }
54
    }
55
56
    /**
57
     * Method returns $this->requestParams and creates this object if necessery
58
     *
59
     * @return \Mezon\Transport\RequestParams
60
     */
61
    public function getRequestParamsFetcher(): \Mezon\Transport\RequestParams
62
    {
63
        if ($this->requestParams === null) {
64
            $this->requestParams = new \Mezon\Transport\HttpRequestParams($this->router);
65
        }
66
67
        return $this->requestParams;
68
    }
69
70
    /**
71
     * Method calls route and returns it's content
72
     */
73
    protected function callRoute()
74
    {
75
        $route = explode('/', trim(@$_GET['r'], '/'));
76
77
        if ($this->router === null) {
78
            throw (new \Exception('this->Router was not set', - 2));
79
        }
80
81
        return $this->router->callRoute($route);
82
    }
83
84
    /**
85
     * Method loads single route
86
     *
87
     * @param array $route
88
     *            Route settings
89
     */
90
    public function loadRoute(array $route): void
91
    {
92
        if (isset($route['route']) === false) {
93
            throw (new \Exception('Field "route" must be set'));
94
        }
95
        if (isset($route['callback']) === false) {
96
            throw (new \Exception('Field "callback" must be set'));
97
        }
98
99
        $callback = $route['callback'];
100
101
        if (is_array($route['callback'])) {
102
            $route['class'] = $route['callback'][0];
103
            $route['callback'] = $route['callback'][1];
104
        } else {
105
            $class = isset($route['class']) ? new $route['class']() : $this;
106
            $callback = [
107
                $class,
108
                $callback
109
            ];
110
        }
111
        $this->router->addRoute($route['route'], $callback, isset($route['method']) ? $route['method'] : 'GET');
112
    }
113
114
    /**
115
     * Method loads routes
116
     *
117
     * @param array $routes
118
     *            List of routes
119
     */
120
    public function loadRoutes(array $routes): void
121
    {
122
        foreach ($routes as $route) {
123
            $this->loadRoute($route);
124
        }
125
    }
126
127
    /**
128
     * Method loads routes from config file in *.php or *.json format
129
     *
130
     * @param string $configPath
131
     *            Path of the config for routes
132
     */
133
    public function loadRoutesFromConfig(string $configPath): void
134
    {
135
        if (file_exists($configPath)) {
136
            if (substr($configPath, - 5) === '.json') {
137
                // load config from json
138
                $routes = json_decode(file_get_contents($configPath), true);
139
            } else {
140
                // loadconfig from php
141
                $routes = (include ($configPath));
142
            }
143
            $this->loadRoutes($routes);
144
        } else {
145
            throw (new \Exception('Route ' . $configPath . ' was not found', 1));
146
        }
147
    }
148
149
    /**
150
     * Method loads list of configs
151
     *
152
     * @param array $configPaths
153
     *            paths to config files
154
     */
155
    public function loadRoutesFromConfigs(array $configPaths): void
156
    {
157
        foreach ($configPaths as $configPath) {
158
            $this->loadRoutesFromConfig($configPath);
159
        }
160
    }
161
162
    /**
163
     * Method loads routes from the directory
164
     *
165
     * @param string $directory
166
     *            path to the directory. Scanninng is recursive.
167
     */
168
    public function loadRoutesFromDirectory(string $directory): void
169
    {
170
        $paths = scandir($directory);
171
172
        foreach ($paths as $path) {
173
            if (is_file($directory . '/' . $path)) {
174
                $this->loadRoutesFromConfig($directory . '/' . $path);
175
            }
176
        }
177
    }
178
179
    /**
180
     * Method processes exception
181
     *
182
     * @param \Exception $e
183
     *            Exception object to be formatted
184
     */
185
    public function handleException(\Exception $e): void
186
    {
187
        print('<pre>' . $e->getMessage().'<br/>'.$this->formatCallStack($e));
0 ignored issues
show
Are you sure $this->formatCallStack($e) of type array can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

187
        print('<pre>' . $e->getMessage().'<br/>'./** @scrutinizer ignore-type */ $this->formatCallStack($e));
Loading history...
188
    }
189
190
    /**
191
     * Running application
192
     */
193
    public function run(): void
194
    {
195
        try {
196
            print($this->callRoute());
197
        } catch (\Exception $e) {
198
            $this->handleException($e);
199
        }
200
    }
201
202
    /**
203
     * Allowing to call methods added on the fly
204
     *
205
     * @param string $method
206
     *            Method to be called
207
     * @param array $args
208
     *            Arguments
209
     * @return mixed Result of the call
210
     */
211
    public function __call(string $method, array $args)
212
    {
213
        if (isset($this->$method)) {
214
            $function = $this->$method;
215
216
            return call_user_func_array($function, $args);
217
        } else {
218
            throw (new \Exception('Method ' . $method . ' was not found in the application ' . get_class($this)));
219
        }
220
    }
221
222
    /**
223
     * Method redirects user to another page
224
     *
225
     * @param string $url
226
     *            New page
227
     */
228
    public function redirectTo($url): void
229
    {
230
        // @codeCoverageIgnoreStart
231
        header('Location: ' . $url);
232
        exit(0);
233
        // @codeCoverageIgnoreEnd
234
    }
235
236
    /**
237
     * Method validates that route exists
238
     *
239
     * @param string $route
240
     *            route
241
     * @return bool true if the route exists
242
     */
243
    public function routeExists(string $route): bool
244
    {
245
        return $this->router->routeExists($route);
246
    }
247
248
    /**
249
     * Method returns router
250
     *
251
     * @return \Mezon\Router\Router router
252
     */
253
    public function getRouter(): \Mezon\Router\Router
254
    {
255
        return $this->router;
256
    }
257
258
    /**
259
     * Formatting call stack
260
     *
261
     * @param mixed $e
262
     *            Exception object
263
     */
264
    protected function formatCallStack($e): array
265
    {
266
        $stack = $e->getTrace();
267
        
268
        foreach ($stack as $i => $call) {
269
            $stack[$i] = (@$call['file'] == '' ? 'lambda : ' : @$call['file'] . ' (' . $call['line'] . ') : ') .
270
            (@$call['class'] == '' ? '' : $call['class'] . '->') . $call['function'];
271
        }
272
        
273
        return $stack;
274
    }
275
}
276