Errors   A
last analyzed

Complexity

Total Complexity 19

Size/Duplication

Total Lines 318
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 113
dl 0
loc 318
rs 10
c 0
b 0
f 0
wmc 19

11 Methods

Rating   Name   Duplication   Size   Complexity  
A errorHandler() 0 30 1
A __construct() 0 7 1
A obtainExceptionRender() 0 9 1
A obtainErrorType() 0 29 2
A callRender() 0 36 2
A defineExceptionHandler() 0 16 2
A obtainErrorRender() 0 9 1
A defineErrorHandler() 0 16 2
A exceptionHandler() 0 24 1
A saveIntoPhpLog() 0 9 1
A defineRenderToUse() 0 18 5
1
<?php
2
3
namespace BFW\Core;
4
5
/**
6
 * Class used to have a personnal message/page for errors and exceptions
7
 */
8
class Errors
9
{
10
    /**
11
     * Constructeur
12
     */
13
    public function __construct()
14
    {
15
        //Find and create the handler for errors
16
        $this->defineErrorHandler();
17
        
18
        //Find and create the handler for exceptions
19
        $this->defineExceptionHandler();
20
    }
21
    
22
    /**
23
     * Find and create the handler for errors
24
     * 
25
     * @return void
26
     */
27
    protected function defineErrorHandler()
28
    {
29
        $errorRender = $this->obtainErrorRender();
30
        
31
        //If not render to use
32
        if ($errorRender === false) {
33
            return;
34
        }
35
36
        //add the handler for errors
37
        set_error_handler([$this, 'errorHandler']);
38
        
39
        \BFW\Application::getInstance()
40
            ->getMonolog()
41
            ->getLogger()
42
            ->debug('New error handler defined.')
43
        ;
44
    }
45
    
46
    /**
47
     * Find and create the handler for exceptions
48
     * 
49
     * @return void
50
     */
51
    protected function defineExceptionHandler()
52
    {
53
        $exceptionRender = $this->obtainExceptionRender();
54
        
55
        //If not render to use
56
        if ($exceptionRender === false) {
57
            return;
58
        }
59
        
60
        //add the handler for exceptions
61
        set_exception_handler([$this, 'exceptionHandler']);
62
        
63
        \BFW\Application::getInstance()
64
            ->getMonolog()
65
            ->getLogger()
66
            ->debug('New exception handler defined.')
67
        ;
68
    }
69
    
70
    /**
71
     * Get the error render from config for cli or default
72
     * 
73
     * @return boolean|array Render infos
74
     *  Boolean : false if no render to use
75
     *  Array   : Infos from config
76
     */
77
    protected function obtainErrorRender()
78
    {
79
        $app        = \BFW\Application::getInstance();
80
        $renderFcts = $app->getConfig()->getValue(
81
            'errorRenderFct',
82
            'errors.php'
83
        );
84
        
85
        return $this->defineRenderToUse($renderFcts);
86
    }
87
    
88
    /**
89
     * Get the exception render from config for cli or default
90
     * 
91
     * @return boolean|array Render infos
92
     *  Boolean : false if no render to use
93
     *  Array   : Infos from config
94
     */
95
    protected function obtainExceptionRender()
96
    {
97
        $app        = \BFW\Application::getInstance();
98
        $renderFcts = $app->getConfig()->getValue(
99
            'exceptionRenderFct',
100
            'errors.php'
101
        );
102
        
103
        return $this->defineRenderToUse($renderFcts);
104
    }
105
    
106
    /**
107
     * Find the render to use with the config
108
     * If cli render is not define, it's use the default render.
109
     * 
110
     * @param array $renderConfig : Render infos from config
111
     * 
112
     * @return boolean|array : Render to use
113
     *  Boolean : false if is no enabled or if no render is defined
114
     *  Array : The render to use
115
     */
116
    protected function defineRenderToUse(array $renderConfig)
117
    {
118
        //Check enabled
119
        if ($renderConfig['enabled'] === false) {
120
            return false;
121
        }
122
        
123
        //The cli render if cli mode
124
        if (PHP_SAPI === 'cli' && isset($renderConfig['cli'])) {
125
            return $renderConfig['cli'];
126
        }
127
        
128
        //The default render or cli if cli mode and no cli render configured
129
        if (isset($renderConfig['default'])) {
130
            return $renderConfig['default'];
131
        }
132
        
133
        return false;
134
    }
135
    
136
    /**
137
     * The default exception handler included in BFW
138
     * 
139
     * @param \Throwable $exception : Exception informations
140
     * 
141
     * @return void
142
     */
143
    public function exceptionHandler(\Throwable $exception)
144
    {
145
        \BFW\Application::getInstance()
146
            ->getMonolog()
147
            ->getLogger()
148
            ->debug(
149
                'New exception catched.',
150
                [
151
                    'msg'  => $exception->getMessage(),
152
                    'file' => $exception->getFile(),
153
                    'line' => $exception->getLine()
154
                ]
155
            );
156
        
157
        $errorRender = $this->obtainExceptionRender();
158
        
159
        $this->callRender(
160
            $errorRender,
0 ignored issues
show
Bug introduced by
It seems like $errorRender can also be of type boolean; however, parameter $renderInfos of BFW\Core\Errors::callRender() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

160
            /** @scrutinizer ignore-type */ $errorRender,
Loading history...
161
            'Exception Uncaught', 
162
            $exception->getMessage(), 
163
            $exception->getFile(), 
164
            $exception->getLine(), 
165
            $exception->getTrace(),
166
            $exception->getCode()
167
        );
168
    }
169
    
170
    /**
171
     * The default error handler included in BFW
172
     * 
173
     * @param integer $errSeverity : Error severity
174
     * @param string  $errMsg : Error message
175
     * @param string  $errFile : File where the error is triggered
176
     * @param integer $errLine : Line where the error is triggered
177
     * 
178
     * @return void
179
     */
180
    public function errorHandler(
181
        int $errSeverity,
182
        string $errMsg,
183
        string $errFile,
184
        int $errLine
185
    ) {
186
        $errType     = $this->obtainErrorType($errSeverity);
187
        $errorRender = $this->obtainErrorRender();
188
        
189
        \BFW\Application::getInstance()
190
            ->getMonolog()
191
            ->getLogger()
192
            ->debug(
193
                'New error catched.',
194
                [
195
                    'type' => $errType,
196
                    'msg'  => $errMsg,
197
                    'file' => $errFile,
198
                    'line' => $errLine
199
                ]
200
            );
201
        
202
        //Call the "callRender" method for this class (or child class)
203
        $this->callRender(
204
            $errorRender,
0 ignored issues
show
Bug introduced by
It seems like $errorRender can also be of type boolean; however, parameter $renderInfos of BFW\Core\Errors::callRender() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

204
            /** @scrutinizer ignore-type */ $errorRender,
Loading history...
205
            $errType,
206
            $errMsg,
207
            $errFile,
208
            $errLine,
209
            debug_backtrace()
210
        );
211
    }
212
    
213
    /**
214
     * Call the personnal class-method or function declared on config when
215
     * an exception or an error is triggered.
216
     * 
217
     * @param array    $renderInfos : Infos from config
218
     * @param string   $errType : Human readable error severity
219
     * @param string   $errMsg : Error/exception message
220
     * @param string   $errFile : File where the error/exception is triggered
221
     * @param integer  $errLine : Line where the error/exception is triggered
222
     * @param array    $backtrace : Error/exception backtrace
223
     * @param int|null $exceptionCode : (default null) Exception code
224
     * 
225
     * @return void
226
     */
227
    protected function callRender(
228
        array $renderInfos,
229
        string $errType,
230
        string $errMsg,
231
        string $errFile,
232
        int $errLine,
233
        array $backtrace,
234
        $exceptionCode = null
235
    ) {
236
        $this->saveIntoPhpLog($errType, $errMsg, $errFile, $errLine);
237
        
238
        $class  = $renderInfos['class'];
239
        $method = $renderInfos['method'];
240
        
241
        //If is a class, call "$class::$method" (compatibility 5.x)
242
        if (!empty($class)) {
243
            $class::$method(
244
                $errType,
245
                $errMsg,
246
                $errFile,
247
                $errLine,
248
                $backtrace,
249
                $exceptionCode
250
            );
251
            
252
            return;
253
        }
254
        
255
        //If is not a class, it's a function.
256
        $method(
257
            $errType,
258
            $errMsg,
259
            $errFile,
260
            $errLine,
261
            $backtrace,
262
            $exceptionCode
263
        );
264
    }
265
    
266
    /**
267
     * Save the error into the PHP log
268
     * 
269
     * @param string  $errType : Human readable error severity
270
     * @param string  $errMsg : Error/exception message
271
     * @param string  $errFile : File where the error/exception is triggered
272
     * @param integer $errLine : Line where the error/exception is triggered
273
     * 
274
     * @return void
275
     */
276
    protected function saveIntoPhpLog(
277
        string $errType,
278
        string $errMsg,
279
        string $errFile,
280
        int $errLine
281
    ) {
282
        error_log(
283
            'Error detected : '.$errType.' '.$errMsg
284
            .' at '.$errFile.':'.$errLine
285
        );
286
    }
287
    
288
    /**
289
     * Map array to have a human readable severity.
290
     * 
291
     * @see http://fr2.php.net/manual/fr/function.set-error-handler.php#113567
292
     * 
293
     * @param int $errSeverity : The error severity with PHP constant
294
     * 
295
     * @return string
296
     */
297
    protected function obtainErrorType(int $errSeverity): string
298
    {
299
        $errorMap = [
300
            E_ERROR             => 'Fatal',
301
            E_CORE_ERROR        => 'Fatal',
302
            E_USER_ERROR        => 'Fatal',
303
            E_COMPILE_ERROR     => 'Fatal',
304
            E_RECOVERABLE_ERROR => 'Fatal',
305
            E_WARNING           => 'Warning',
306
            E_CORE_WARNING      => 'Warning',
307
            E_USER_WARNING      => 'Warning',
308
            E_COMPILE_WARNING   => 'Warning',
309
            E_PARSE             => 'Parse',
310
            E_NOTICE            => 'Notice',
311
            E_USER_NOTICE       => 'Notice',
312
            E_STRICT            => 'Strict',
313
            E_DEPRECATED        => 'Deprecated',
314
            E_USER_DEPRECATED   => 'Deprecated'
315
        ];
316
317
        //Default value if the error is not found in the map array
318
        $errType = 'Unknown';
319
        
320
        //Search in map array
321
        if (isset($errorMap[$errSeverity])) {
322
            $errType = $errorMap[$errSeverity];
323
        }
324
        
325
        return $errType;
326
    }
327
}
328