Passed
Push — master ( 1c0893...f7ffcc )
by Fran
03:22
created

Dispatcher::run()   B

Complexity

Conditions 7
Paths 19

Size

Total Lines 21
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 7.3229

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 16
nc 19
nop 0
dl 0
loc 21
ccs 13
cts 16
cp 0.8125
crap 7.3229
rs 7.551
c 1
b 0
f 0
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 23 and the first side effect is on line 17.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * @author Fran López <[email protected]>
4
 * @version 1.0
5
 */
6
7
namespace PSFS;
8
9
use PSFS\base\config\Config;
10
use PSFS\base\exception\ConfigException;
11
use PSFS\base\exception\RouterException;
12
use PSFS\base\exception\SecurityException;
13
use PSFS\base\Logger;
14
use PSFS\base\Singleton;
15
use PSFS\controller\ConfigController;
16
17 1
require_once __DIR__ . DIRECTORY_SEPARATOR . "bootstrap.php";
18
19
/**
20
 * Class Dispatcher
21
 * @package PSFS
22
 */
23
class Dispatcher extends Singleton
24
{
25
    /**
26
     * @Inyectable
27
     * @var \PSFS\base\Security $security
28
     */
29
    protected $security;
30
    /**
31
     * @Inyectable
32
     * @var \PSFS\base\Router $router
33
     */
34
    protected $router;
35
    /**
36
     * @Inyectable
37
     * @var \PSFS\base\Request $parser
38
     */
39
    protected $parser;
40
    /**
41
     * @Inyectable
42
     * @var \PSFS\base\Logger $log
43
     */
44
    protected $log;
45
    /**
46
     * @Inyectable
47
     * @var \PSFS\base\config\Config $config
48
     */
49
    protected $config;
50
51
    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...
52
    protected $mem;
53
    protected $locale = "es_ES";
54
55
    private $actualUri;
56
57
    /**
58
     * Initializer method
59
     */
60 1
    public function init()
61
    {
62 1
        Logger::log('Dispatcher init');
63 1
        parent::init();
64 1
        $this->initiateStats();
65 1
        $this->setLocale();
66 1
        $this->bindWarningAsExceptions();
67 1
        $this->actualUri = $this->parser->getServer("REQUEST_URI");
68 1
        Logger::log('End dispatcher init');
69 1
    }
70
71
    /**
72
     * Method that assign the locale to the request
73
     * @return $this
74
     */
75 1
    private function setLocale()
76
    {
77 1
        $this->locale = $this->config->get("default_language");
78 1
        Logger::log('Set locale to project [' . $this->locale . ']');
79
        // Load translations
80 1
        putenv("LC_ALL=" . $this->locale);
81 1
        setlocale(LC_ALL, $this->locale);
82
        // Load the locale path
83 1
        $locale_path = BASE_DIR . DIRECTORY_SEPARATOR . 'locale';
84 1
        Logger::log('Set locale dir ' . $locale_path);
85 1
        Config::createDir($locale_path);
86 1
        bindtextdomain('translations', $locale_path);
87 1
        textdomain('translations');
88 1
        bind_textdomain_codeset('translations', 'UTF-8');
89
90 1
        return $this;
91
    }
92
93
    /**
94
     * Run method
95
     * @return string HTML
96
     */
97 5
    public function run()
98
    {
99 5
        Logger::log('Begin runner');
100
        try {
101 5
            if ($this->config->isConfigured()) {
102 4
                if (!$this->parser->isFile()) {
103 4
                    return $this->router->execute($this->actualUri);
104
                }
105
            } else {
106 1
                return ConfigController::getInstance()->config();
107
            }
108 4
        } catch (ConfigException $c) {
109
            return $this->dumpException($c);
110 4
        } catch (SecurityException $s) {
111 1
            return $this->security->notAuthorized($this->actualUri);
112 4
        } catch (RouterException $r) {
113 1
            return $this->router->httpNotFound($r);
114 2
        } catch (\Exception $e) {
115 2
            return $this->dumpException($e);
116
        }
117
    }
118
119
    /**
120
     * Method that convert an exception to html
121
     *
122
     * @param \Exception $e
123
     *
124
     * @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...
125
     */
126 2
    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...
127
    {
128 2
        Logger::log('Starting dump exception');
129 2
        $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...
130
        $error = array(
131 2
            "error" => $ex->getMessage(),
132 2
            "file" => $ex->getFile(),
133 2
            "line" => $ex->getLine(),
134 2
        );
135 2
        Logger::log('Throwing exception', LOG_ERR, $error);
136 2
        unset($error);
137
138 2
        return $this->router->httpNotFound($ex);
139
    }
140
141
    /**
142
     * Method that returns the memory used at this specific moment
143
     *
144
     * @param $unit string
145
     *
146
     * @return int
147
     */
148 1
    public function getMem($unit = "Bytes")
149
    {
150 1
        $use = memory_get_usage() - $this->mem;
151
        switch ($unit) {
152 1
            case "KBytes":
153 1
                $use /= 1024;
154 1
                break;
155 1
            case "MBytes":
156 1
                $use /= (1024 * 1024);
157 1
                break;
158 1
            case "Bytes":
159 1
            default:
160 1
        }
161
162 1
        return $use;
163
    }
164
165
    /**
166
     * Method that returns the seconds spent with the script
167
     * @return double
168
     */
169 2
    public function getTs()
170
    {
171 2
        return microtime(TRUE) - $this->ts;
172
    }
173
174
    /**
175
     * Debug function to catch warnings as exceptions
176
     */
177 1
    protected function bindWarningAsExceptions()
178
    {
179 1
        if ($this->config->getDebugMode()) {
180
            Logger::log('Added handlers for errors');
181
            //Warning & Notice handler
182
            set_error_handler(function ($errno, $errstr, $errfile, $errline) {
183
                Logger::log($errstr, LOG_CRIT, ['file' => $errfile, 'line' => $errline]);
184
                throw new \Exception($errstr, 500);
185
            });
186
        }
187 1
    }
188
189
    /**
190
     * Stats initializer
191
     */
192 1
    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...
193
    {
194 1
        Logger::log('Initialicing stats (mem + ts)');
195 1
        if (null !== $_SERVER && array_key_exists('REQUEST_TIME_FLOAT', $_SERVER)) {
196 1
            $this->ts = (float)$_SERVER['REQUEST_TIME_FLOAT'];
197 1
        } else {
198
            $this->ts = $this->parser->getTs();
199
        }
200 1
        $this->mem = memory_get_usage();
201 1
    }
202
203
}
204