Test Failed
Push — master ( d54ee5...17804e )
by Fran
06:18
created

Dispatcher::run()   C

Complexity

Conditions 8
Paths 23

Size

Total Lines 23
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 18
nc 23
nop 0
dl 0
loc 23
rs 6.1403
c 0
b 0
f 0
1
<?php
2
/**
3
 * @author Fran López <[email protected]>
4
 * @version 1.0
5
 */
6
7
namespace PSFS;
8
9
use PSFS\base\exception\AdminCredentialsException;
10
use PSFS\base\exception\ConfigException;
11
use PSFS\base\exception\RouterException;
12
use PSFS\base\exception\SecurityException;
13
use PSFS\base\exception\UserAuthException;
14
use PSFS\base\Logger;
15
use PSFS\base\Request;
16
use PSFS\base\Singleton;
17
use PSFS\base\types\helpers\GeneratorHelper;
18
use PSFS\controller\ConfigController;
19
use PSFS\controller\UserController;
20
21
/**
22
 * Class Dispatcher
23
 * @package PSFS
24
 */
25
class Dispatcher extends Singleton
26
{
27
    /**
28
     * @Inyectable
29
     * @var \PSFS\base\Security $security
30
     */
31
    protected $security;
32
    /**
33
     * @Inyectable
34
     * @var \PSFS\base\Router $router
35
     */
36
    protected $router;
37
    /**
38
     * @Inyectable
39
     * @var \PSFS\base\Request $parser
40
     */
41
    protected $parser;
42
    /**
43
     * @Inyectable
44
     * @var \PSFS\base\Logger $log
45
     */
46
    protected $log;
47
    /**
48
     * @Inyectable
49
     * @var \PSFS\base\config\Config $config
50
     */
51
    protected $config;
52
53
    protected $ts;
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $ts. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
54
    protected $mem;
55
    protected $locale = "es_ES";
56
57
    private $actualUri;
58
59
    /**
60
     * Initializer method
61
     */
62
    public function init()
63
    {
64
        Logger::log('Dispatcher init');
65
        parent::init();
66
        $this->initiateStats();
67
        $this->setLocale();
68
        $this->bindWarningAsExceptions();
69
        $this->actualUri = $this->parser->getServer("REQUEST_URI");
70
        Logger::log('End dispatcher init');
71
    }
72
73
    /**
74
     * Method that assign the locale to the request
75
     * @return $this
76
     */
77
    private function setLocale()
78
    {
79
        $this->locale = $this->config->get("default_language");
80
        Logger::log('Set locale to project [' . $this->locale . ']');
81
        // Load translations
82
        putenv("LC_ALL=" . $this->locale);
83
        setlocale(LC_ALL, $this->locale);
84
        // Load the locale path
85
        $locale_path = BASE_DIR . DIRECTORY_SEPARATOR . 'locale';
86
        Logger::log('Set locale dir ' . $locale_path);
87
        GeneratorHelper::createDir($locale_path);
88
        bindtextdomain('translations', $locale_path);
89
        textdomain('translations');
90
        bind_textdomain_codeset('translations', 'UTF-8');
91
92
        return $this;
93
    }
94
95
    /**
96
     * Run method
97
     * @return string HTML
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
98
     */
99
    public function run()
100
    {
101
        Logger::log('Begin runner');
102
        try {
103
            if ($this->config->isConfigured()) {
104
                if (!$this->parser->isFile()) {
105
                    return $this->router->execute($this->actualUri);
106
                }
107
            } else {
108
                return ConfigController::getInstance()->config();
109
            }
110
        } catch (AdminCredentialsException $a) {
111
            return UserController::showAdminManager();
112
        } catch (ConfigException $c) {
113
            return $this->dumpException($c);
114
        } catch (SecurityException $s) {
115
            return $this->security->notAuthorized($this->actualUri);
116
        } catch (RouterException $r) {
117
            return $this->router->httpNotFound($r);
118
        } catch (\Exception $e) {
119
            return $this->dumpException($e);
120
        }
121
    }
122
123
    private function redirectToHome()
124
    {
125
        Request::getInstance()->redirect($this->router->getRoute($this->config->get('home_action')));
126
    }
127
128
    /**
129
     * Method that convert an exception to html
130
     *
131
     * @param \Exception $e
132
     *
133
     * @return string HTML
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
134
     */
135
    protected function dumpException(\Exception $e)
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $e. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
136
    {
137
        Logger::log('Starting dump exception');
138
        $ex = (NULL !== $e->getPrevious()) ? $e->getPrevious() : $e;
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $ex. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
139
        $error = array(
140
            "error" => $ex->getMessage(),
141
            "file" => $ex->getFile(),
142
            "line" => $ex->getLine(),
143
        );
144
        Logger::log('Throwing exception', LOG_ERR, $error);
145
        unset($error);
146
147
        return $this->router->httpNotFound($ex);
148
    }
149
150
    /**
151
     * Method that returns the memory used at this specific moment
152
     *
153
     * @param $unit string
154
     *
155
     * @return int
156
     */
157
    public function getMem($unit = "Bytes")
158
    {
159
        $use = memory_get_usage() - $this->mem;
160
        switch ($unit) {
161
            case "KBytes":
162
                $use /= 1024;
163
                break;
164
            case "MBytes":
165
                $use /= (1024 * 1024);
166
                break;
167
            case "Bytes":
168
            default:
169
        }
170
171
        return $use;
172
    }
173
174
    /**
175
     * Method that returns the seconds spent with the script
176
     * @return double
177
     */
178
    public function getTs()
179
    {
180
        return microtime(TRUE) - $this->ts;
181
    }
182
183
    /**
184
     * Debug function to catch warnings as exceptions
185
     */
186
    protected function bindWarningAsExceptions()
187
    {
188
        if ($this->config->getDebugMode() && $this->config->get('errors.strict', false)) {
189
            Logger::log('Added handlers for errors');
190
            //Warning & Notice handler
191
            set_error_handler(function ($errno, $errstr, $errfile, $errline) {
192
                Logger::log($errstr, LOG_CRIT, ['file' => $errfile, 'line' => $errline]);
193
                throw new \Exception($errstr, 500);
194
            });
195
        }
196
    }
197
198
    /**
199
     * Stats initializer
200
     */
201
    private function initiateStats()
0 ignored issues
show
Coding Style introduced by
initiateStats uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
202
    {
203
        Logger::log('Initializing stats (mem + ts)');
204
        if (null !== $_SERVER && array_key_exists('REQUEST_TIME_FLOAT', $_SERVER)) {
205
            $this->ts = (float)$_SERVER['REQUEST_TIME_FLOAT'];
206
        } else {
207
            $this->ts = $this->parser->getTs();
208
        }
209
        $this->mem = memory_get_usage();
210
    }
211
212
}
213