Test Setup Failed
Push — master ( 5f1ff1...213bb6 )
by Php Easy Api
03:56
created

ErrorProvider::getEnvironmentStatus()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Resta\Exception;
4
5
use Resta\Support\Str;
6
use Resta\Support\Utils;
7
use Resta\Support\Dependencies;
8
use Resta\Support\ClosureDispatcher;
9
use Resta\Foundation\ApplicationProvider;
10
use Resta\Foundation\PathManager\StaticPathModel;
11
12
class ErrorProvider extends ApplicationProvider
13
{
14
    /**
15
     * @var null|string
16
     */
17
    public $lang;
18
19
    /**
20
     * @var string
21
     */
22
    protected $exception;
23
24
    /**
25
     * @var array
26
     */
27
    protected $data = array();
28
29
    /**
30
     * @var array
31
     */
32
    protected $result = [];
33
34
    /**
35
     * @return mixed|string
36
     */
37
    private function getEnvironmentStatus()
38
    {
39
        // application key, but if it has a null value
40
        // then we move the environment value to the production environment.
41
        return $this->app->environment();
42
    }
43
44
    /**
45
     * @return void|mixed
46
     */
47
    private function getStatusFromContext()
48
    {
49
        $exception = $this->exception;
50
51
        if(isset(core()->exceptiontrace))
52
        {
53
            $this->data['status'] = (int)core()->exceptiontrace['callNamespace']->getCode();
54
        }
55
        else {
56
57
            $this->data['status']=(int)$exception::exceptionTypeCodes($this->data['errType']);
58
        }
59
60
        $this->app->terminate('responseSuccess');
61
        $this->app->terminate('responseStatus');
62
        $this->app->register('responseSuccess',(bool)false);
63
        $this->app->register('responseStatus',$this->data['status']);
64
65
66
        $optionalException = str_replace("\\","\\\\",$this->app->namespace()->exception());
67
68
        if(preg_match('@'.$optionalException.'@is',$this->data['errType'])){
69
70
            //linux test
71
            $trace = $this->data['errContext']['trace'];
72
            if(preg_match('@Stack trace:\n#0(.*)\n#1@is',$trace,$traceArray)){
73
74
                $traceFile = str_replace(root,'',$traceArray[1]);
75
76
                if(preg_match('@(.*)\((\d+)\)@is',$traceFile,$traceResolve)){
77
                    $this->data['errFile']=$traceResolve[1];
78
                    $this->data['errLine']=(int)$traceResolve[2];
79
                }
80
            }
81
82
83
            $this->data['errType'] = class_basename($this->data['errType']);
84
        }
85
86
        if(is_array($meta = config('response.meta'))){
87
88
            //set as the success object is false
89
            $this->data['appExceptionSuccess'] = [];
90
        }
91
        else{
92
93
            //set as the success object is false
94
            $this->data['appExceptionSuccess'] = ['success'=>(bool)false,'status'=>$this->data['status']];
95
        }
96
    }
97
98
    /**
99
     * error provider handle
100
     *
101
     * @return void
102
     */
103
    public function handle()
104
    {
105
        //sets which php errors are reported
106
        error_reporting(0);
107
108
        // in general we will use the exception class
109
        // in the store/config directory to make it possible
110
        // to change the user-based exceptions.
111
        $this->exception = StaticPathModel::$store.'\Config\Exception';
112
113
        //This function can be used for defining your own way of handling errors during runtime,
114
        //for example in applications in which you need to do cleanup of data/files when a critical error happens,
115
        //or when you need to trigger an error under certain conditions (using trigger_error()).
116
        set_error_handler([$this,'setErrorHandler']);
117
118
        //Registers a callback to be executed after script execution finishes or exit() is called.
119
        //Multiple calls to register_shutdown_function() can be made, and each will be called in the same order as
120
        //they were registered. If you call exit() within one registered shutdown function,
121
        //processing will stop completely and no other registered shutdown functions will be called.
122
        register_shutdown_function([$this,'fatalErrorShutdownHandler']);
123
    }
124
125
    /**
126
     * set error handler
127
     *
128
     * @param null|string $errNo
129
     * @param null|string $errStr
130
     * @param null|string $errFile
131
     * @param null|string $errLine
132
     * @param null|string $errContext
133
     */
134
    public function setErrorHandler($errNo=null, $errStr=null, $errFile=null, $errLine=null, $errContext=null)
135
    {
136
        // in case of a deficiency,
137
        // we need to boot our general needs to be needed for the exception.
138
        Dependencies::loadBootstrapperNeedsForException();
139
140
        // in general we will use the exception class
141
        // in the store/config directory to make it possible
142
        // to change the user-based exceptions.
143
        $this->data['exception']            = $this->exception;
144
        $this->data['errType']              = 'Undefined';
145
        $this->data['errStrReal']           = $errStr;
146
        $this->data['errorClassNamespace']  = null;
147
        $this->data['errFile']              = $errFile;
148
        $this->data['errLine']              = $errLine;
149
        $this->data['errNo']                = $errNo;
150
151
        // catch exception via preg match
152
        // and then clear the Uncaught statement from inside.
153
        $this->getUncaughtProcess();
154
155
        //get status from context
156
        $this->getStatusFromContext();
157
158
        //get lang message for exception
159
        $this->getLangMessageForException();
160
161
        if(property_exists(core(),'exceptiontrace')){
162
163
            $customExceptionTrace   = core()->exceptiontrace;
164
            $this->data['errFile']  = $customExceptionTrace['file'];
165
            $this->data['errLine']  = $customExceptionTrace['line'];
166
        }
167
168
        $environment = $this->getEnvironmentStatus();
169
170
        $vendorDirectory = str_replace(root.''.DIRECTORY_SEPARATOR.'','',$this->data['errFile']);
171
172
        if(Str::startsWith($vendorDirectory,'vendor')
173
            && Str::startsWith($vendorDirectory,'vendor/php-resta')===false)
174
        {
175
            $externalMessage = ($environment==="production") ?
176
                'An unexpected external error has occurred' :
177
                $this->data['errStrReal'];
178
179
            $this->result = $this->getAppException($environment,$externalMessage);
180
181
182
            //Get or Set the HTTP response code
183
            http_response_code(500);
184
            $this->app->terminate('responseStatus');
185
            $this->app->register('responseStatus',500);
186
187
188
        }
189
        else{
190
191
            $this->result = $this->getAppException($environment,$this->data['errStrReal']);
192
193
            //Get or Set the HTTP response code
194
            http_response_code($this->data['status']);
195
        }
196
197
198
        if($environment==="production"){
199
200
            $productionLogMessage = $this->getAppException('local',$this->data['errStrReal']);
201
            $this->app->register('productionLogMessage',core()->out->outputFormatter($productionLogMessage));
202
        }
203
204
        // exception extender The exception information
205
        // that is presented as an extra to the exception result set.
206
        $this->result = $this->getExceptionExtender();
207
208
209
        //set json app exception
210
        core()->routerResult = $this->result;
211
212
        $restaOutHandle = null;
213
214
        if(!defined('responseApp')){
215
            $restaOutHandle=core()->out->handle();
216
        }
217
218
        if($restaOutHandle===null){
219
220
            //header set and symfony response call
221
            header('Content-type:application/json;charset=utf-8');
222
223
            echo json_encode(core()->out->outputFormatter($this->result));
224
            exit();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
225
        }
226
        else{
227
            echo $restaOutHandle;
228
            exit();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
229
        }
230
    }
231
232
    /**
233
     * @param $environment
234
     * @return mixed
235
     */
236
    private function getAppException($environment,$message)
237
    {
238
        return $this->data['appExceptionSuccess']+$this->data['exception']::$environment(
239
                $this->data['errNo'],
240
                $message,
241
                $this->data['errFile'],
242
                $this->data['errLine'],
243
                $this->data['errType'],
244
                $this->data['lang']
245
            );
246
    }
247
248
    /**
249
     * get exception extender object
250
     *
251
     * @return mixed
252
     */
253
    private function getExceptionExtender()
254
    {
255
        return $this->app->resolve(ExceptionExtender::class,
256
            ['result'=>$this->result])->getResult();
257
    }
258
259
    /**
260
     * fatal error shutdown handler
261
     *
262
     * @return mixed
263
     */
264
    public function fatalErrorShutdownHandler()
265
    {
266
        //get fatal error
267
        $last_error = error_get_last();
268
269
        $this->inStackTrace($last_error);
270
271
        if(!is_null($last_error)){
0 ignored issues
show
introduced by
The condition is_null($last_error) is always false.
Loading history...
272
273
            if(!defined('methodName')){
274
                define('methodName',null);
275
            }
276
277
            if(isset(core()->exceptionFile)){
278
                $last_error['file'] = core()->exceptionFile;
279
                $last_error['line'] = core()->exceptionLine;
280
            }
281
282
            $this->setErrorHandler(
283
                E_ERROR,
284
                $last_error['message'],
285
                $last_error['file'],
286
                $last_error['line'],
287
                []
0 ignored issues
show
Bug introduced by
array() of type array is incompatible with the type null|string expected by parameter $errContext of Resta\Exception\ErrorProvider::setErrorHandler(). ( Ignorable by Annotation )

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

287
                /** @scrutinizer ignore-type */ []
Loading history...
288
            );
289
        }
290
    }
291
292
    /**
293
     * @param $error
294
     */
295
    public function inStackTrace($error)
296
    {
297
        if(isset(core()->urlComponent)){
298
            if(!preg_match('@'.core()->urlComponent['project'].'@',$error['file']) && !isset(core()->exceptionFile)){
299
                if(preg_match('@ in\s(.*?)\n@is',$error['message'],$result)){
300
                    $errorMessage = explode(":",$result[1]);
301
                    $this->app->register('exceptionFile',$errorMessage[0]);
302
                    $this->app->register('exceptionLine',$errorMessage[1]);
303
                }
304
            }
305
        }
306
    }
307
308
    /**
309
     * @return void|mixed
310
     */
311
    private function getLangMessageForException()
312
    {
313
        $clone = clone $this;
314
315
        if(property_exists(core(),'exceptionTranslate')){
316
317
            $langMessage=trans('exception.'.core()->exceptionTranslate);
318
319
            if(!is_null($langMessage) && property_exists(core(),'exceptionTranslateParams')){
320
321
                if(count(core()->exceptionTranslateParams[core()->exceptionTranslate])){
322
                    foreach (core()->exceptionTranslateParams[core()->exceptionTranslate] as $key=>$value){
323
                        $langMessage=preg_replace('@\('.$key.'\)@is',$value,$langMessage);
324
                    }
325
                }
326
            }
327
328
            if($langMessage!==null){
329
                $this->data['errStrReal']=$langMessage;
330
            }
331
        }
332
333
        if(class_exists($this->data['errorClassNamespace'])
334
            &&
335
            (Str::startsWith($this->data['errorClassNamespace'],'App')
336
                || Str::startsWith($this->data['errorClassNamespace'],__NAMESPACE__))){
337
338
            ClosureDispatcher::bind($this->data['errorClassNamespace'])->call(function() use ($clone) {
339
                if(property_exists($this,'lang')){
340
                    $clone->lang=$this->lang;
341
                }
342
            });
343
        }
344
345
        $this->data['lang']=$lang=$clone->lang;
346
347
        if($lang!==null){
348
            $langMessage=trans('exception.'.$lang);
349
        }
350
        else{
351
            $langMessage=null;
352
        }
353
354
355
        if($langMessage!==null){
356
            $this->data['errStrReal']=$langMessage;
357
        }
358
    }
359
360
    /**
361
     * get uncaught process
362
     *
363
     * @return void|mixed
364
     */
365
    private function getUncaughtProcess()
366
    {
367
        // catch exception via preg match
368
        // and then clear the Uncaught statement from inside.
369
        if(preg_match('@(.*?):@is',$this->data['errStrReal'],$errArr)){
370
371
            $this->data['errType']=trim(str_replace('Uncaught','',$errArr[1]));
372
            $this->data['errorClassNamespace']=$this->data['errType'];
373
        }
374
375
        if(preg_match('@Uncaught@is',$this->data['errStrReal'])
376
            && preg_match('@(.*?):(.*?)\sin\s@is',$this->data['errStrReal'],$errStrRealArray)){
377
            $this->data['errStrReal']=trim($errStrRealArray[2]);
378
        }
379
380
        if($this->data['errType']==="Undefined"){
381
            $this->data['errStrReal']=$this->data['errStrReal'];
382
        }
383
        else{
384
            $this->data['errContext']['trace']=$this->data['errStrReal'];
385
        }
386
    }
387
388
    /**
389
     * get result for exception
390
     *
391
     * @return array
392
     */
393
    public function getResult()
394
    {
395
        return $this->result;
396
    }
397
398
}