Passed
Branchfeature/useWidgetsNamespaces (54f503)
by Robin
04:17
created

AppController::accessDenied()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
c 0
b 0
f 0
dl 0
loc 5
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
// -------------------------------------------------------------------------
4
// OVIDENTIA http://www.ovidentia.org
5
// Ovidentia is free software; you can redistribute it and/or modify
6
// it under the terms of the GNU General Public License as published by
7
// the Free Software Foundation; either version 2, or (at your option)
8
// any later version.
9
//
10
// This program is distributed in the hope that it will be useful, but
11
// WITHOUT ANY WARRANTY; without even the implied warranty of
12
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
// See the GNU General Public License for more details.
14
//
15
// You should have received a copy of the GNU General Public License
16
// along with this program; if not, write to the Free Software
17
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
18
// USA.
19
// -------------------------------------------------------------------------
20
/**
21
 * @license http://opensource.org/licenses/gpl-license.php GNU General Public License (GPL)
22
 * @copyright Copyright (c) 2022 by SI4YOU ({@link https://www.siforyou.com})
23
 */
24
namespace Capwelton\LibApp\Ctrl;
25
26
use Capwelton\Widgets\Widgets\Helpers\WidgetAction;
0 ignored issues
show
Bug introduced by
The type Capwelton\Widgets\Widgets\Helpers\WidgetAction was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
27
use Capwelton\Widgets\Widgets\Interfaces\WidgetDisplayableInterface;
0 ignored issues
show
Bug introduced by
The type Capwelton\Widgets\Widget...getDisplayableInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
28
use Capwelton\Widgets\Widgets\Layout\WidgetFlexLayout;
0 ignored issues
show
Bug introduced by
The type Capwelton\Widgets\Widgets\Layout\WidgetFlexLayout was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
29
use Capwelton\Widgets\Widgets\Page\WidgetBabPage;
0 ignored issues
show
Bug introduced by
The type Capwelton\Widgets\Widgets\Page\WidgetBabPage was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
30
use Capwelton\Widgets\Widgets\Page\WidgetPage;
0 ignored issues
show
Bug introduced by
The type Capwelton\Widgets\Widgets\Page\WidgetPage was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
31
use Capwelton\LibApp\AppObjectInterface;
32
use Capwelton\LibApp\Exceptions\AppUnknownActionException;
33
use Capwelton\LibApp\Exceptions\AppException;
34
use Capwelton\LibApp\AppObject;
35
use Capwelton\LibApp\Exceptions\AppAccessException;
36
use Capwelton\LibApp\Exceptions\AppSaveException;
37
use Capwelton\LibApp\Exceptions\AppDeletedRecordException;
38
use Capwelton\LibApp\Exceptions\AppNotFoundException;
39
use Capwelton\LibApp\Func_App;
40
use Capwelton\LibApp\AppComponent;
41
use Capwelton\LibOrm\Exceptions\ORMException;
0 ignored issues
show
Bug introduced by
The type Capwelton\LibOrm\Exceptions\ORMException was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
42
require_once $GLOBALS['babInstallPath'] . 'utilit/controller.class.php';
43
require_once $GLOBALS['babInstallPath'] . 'utilit/json.php';
44
45
require_once dirname(__FILE__) . '/../functions.php';
46
47
/**
48
 * @method self proxy()
49
 */
50
class AppController extends \bab_Controller implements AppObjectInterface
51
{
52
    
53
    /**
54
     * @var Func_App
55
     */
56
    protected $app = null;
57
    
58
    /**
59
     * @var string[]
60
     */
61
    protected $reloadSelectors = array();
62
    
63
    protected $toasts = array();
64
    
65
    protected $keepDialogOpened = false;
66
    
67
    private $SSERecordSet;
68
    
69
    /**
70
     * @param string $reloadSelector
71
     * @param boolean $withSSE
72
     *            If true, the reloadSelector will be added in the SSE payload
73
     * @param mixed $for
74
     *            The user id or a list of users id. If null, current user will be used
75
     */
76
    public function addReloadSelector($reloadSelector, $withSSE = false, $for = null)
77
    {
78
        $this->reloadSelectors[$reloadSelector] = $reloadSelector;
79
        if($withSSE){
80
            $sseRecordSet = $this->getSSERecordSet();
81
            $sseRecordSet->newReloadSelector($reloadSelector, $for);
82
        }
83
        return $this;
84
    }
85
    
86
    /**
87
     * @return string[]
88
     */
89
    public function getReloadSelectors()
90
    {
91
        return $this->reloadSelectors;
92
    }
93
    
94
    public function getSSERecordSet()
95
    {
96
        if(isset($this->SSERecordSet)){
97
            return $this->SSERecordSet;
98
        }
99
        
100
        $App = $this->App();
101
        $this->SSERecordSet = $App->SSESet();
102
        return $this->SSERecordSet;
103
    }
104
    
105
    public function keepDialogOpened($keepDialogOpened = true)
106
    {
107
        $this->keepDialogOpened = $keepDialogOpened;
108
        return $this;
109
    }
110
    
111
    /**
112
     * Can be used in a controller to check if the current request was made by ajax.
113
     *
114
     * @var bool
115
     */
116
    protected $isAjaxRequest = null;
117
    
118
    /**
119
     * Name of method to use to create action
120
     *
121
     * @var string
122
     */
123
    public $createActionMethod = 'createActionForTg';
124
    
125
    /**
126
     * @param Func_App $app
127
     */
128
    public function __construct(Func_App $app = null)
129
    {
130
        $this->setApp($app);
131
    }
132
    
133
    /**
134
     * @param string $name
135
     * @param mixed $arguments
136
     * @return mixed
137
     */
138
    public function __call($name, $arguments = array())
139
    {
140
        $component = $this->App()->getComponentByName($name);
141
        if($component){
142
            return call_user_func_array(array(
143
                $component,
144
                'controller'
145
            ), $arguments);
146
        }
147
        throw new AppException(sprintf($this->App()->translate('Unknown action %s'), $name));
148
    }
149
    
150
    /**
151
     * {@inheritdoc}
152
     * @see AppObject::setApp()
153
     */
154
    public function setApp(Func_App $app = null)
155
    {
156
        $this->app = $app;
157
        return $this;
158
    }
159
    
160
    /**
161
     * {@inheritdoc}
162
     * @see AppObject::App()
163
     */
164
    public function App()
165
    {
166
        return $this->app;
167
    }
168
    
169
    /**
170
     * @return string
171
     */
172
    protected function getControllerTg()
173
    {
174
        return $this->App()->controllerTg;
175
    }
176
    
177
    /**
178
     * Can be used in a controller to check if the current request was made by ajax.
179
     *
180
     * @return bool
181
     */
182
    public function isAjaxRequest()
183
    {
184
        if(! isset($this->isAjaxRequest)){
185
            $this->isAjaxRequest = (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest');
186
        }
187
        return $this->isAjaxRequest;
188
    }
189
    
190
    /**
191
     * Ensures that the user is logged in.
192
     * Tries to use the appropriate authentication type depending on the situation.
193
     */
194
    public function requireCredential($message = null)
195
    {
196
        if($this->isAjaxRequest()){
197
            $authType = 'Basic';
198
        }
199
        else{
200
            $authType = '';
201
        }
202
        
203
        if(! isset($message)){
204
            $message = $this->App()->translate('You must be logged in to access this page.');
205
        }
206
        
207
        bab_requireCredential($message, $authType);
208
    }
209
    
210
    /**
211
     * Returns an instance of the specific controller class.
212
     * If $proxy is true, a proxy to this controller is returned instead.
213
     *
214
     * @deprecated use $App->ControllerProxy() instead
215
     * @param string $classname
216
     * @param bool $proxy
217
     * @return AppController
218
     */
219
    public static function getInstance($classname, $proxy = true)
220
    {
221
        
222
        // If the app object was not specified (through the setApp() method)
223
        // we try to select one according to the classname prefix.
224
        list ($prefix) = explode('_', __CLASS__);
225
        $functionalityName = ucwords($prefix);
226
        /** @var Func_App */
227
        $App = @\bab_functionality::get('App/' . $functionalityName);
228
        
229
        if(!$App){
0 ignored issues
show
introduced by
$App is of type bab_functionality, thus it always evaluated to true.
Loading history...
230
            throw new AppException('Faild to autodetect functionality App/' . $functionalityName . ', the getInstance method is deprecated, use $App->ControllerProxy() instead');
231
        }
232
        
233
        $controller = $App->ControllerProxy($classname, $proxy);
0 ignored issues
show
Bug introduced by
The method ControllerProxy() does not exist on bab_functionality. It seems like you code against a sub-type of bab_functionality such as Capwelton\LibApp\Func_App. ( Ignorable by Annotation )

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

233
        /** @scrutinizer ignore-call */ 
234
        $controller = $App->ControllerProxy($classname, $proxy);
Loading history...
234
        
235
        return $controller;
236
    }
237
    
238
    /**
239
     * Dynamically creates a proxy class for this controller with all public, non-final and non-static functions
240
     * overriden so that they return an action (WidgetAction) corresponding to each of them.
241
     *
242
     * @param string $classname
243
     * @return AppController
244
     */
245
    static function getProxyInstance(Func_App $App, $classname)
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
246
    {
247
        $class = new \ReflectionClass($classname);
248
        $proxyClassname = $class->getShortName() . self::PROXY_CLASS_SUFFIX;
249
        $finalProxyClassname = $class->getNamespaceName()."\\".$proxyClassname;
250
        if(! class_exists($finalProxyClassname)){
251
            $classStr = "";
252
            if($class->getNamespaceName() != ""){
253
                $classStr .= " namespace ".$class->getNamespaceName()."; ";
254
            }
255
            $classStr .= 'class ' . $proxyClassname . ' extends ' . $class->getShortName() . ' {' . "\n";
256
            $methods = $class->getMethods();
257
            
258
            $classStr .= '	public function __construct($App) {
259
                $this->setApp($App);
260
            }' . "\n";
261
            
262
            foreach ($methods as $method){
263
                if($method->name === '__construct' || ! $method->isPublic() || $method->isStatic() || $method->isFinal() || $method->name === 'setApp' || $method->name === 'App' || $method->name === 'setCrm' || $method->name === 'Crm'){
264
                    continue;
265
                }
266
                
267
                $classStr .= '	public function ' . $method->name . '(';
268
                $parameters = $method->getParameters();
269
                $parametersStr = array();
270
                foreach ($parameters as $parameter){
271
                    
272
                    if($parameter->isDefaultValueAvailable()){
273
                        $parametersStr[] = '$' . $parameter->name . ' = ' . var_export($parameter->getDefaultValue(), true);
274
                    }
275
                    else{
276
                        $parametersStr[] = '$' . $parameter->name;
277
                    }
278
                }
279
                $classStr .= implode(', ', $parametersStr);
280
                $classStr .= ') {' . "\n";
281
                $classStr .= '		$args = func_get_args();' . "\n";
282
                $classStr .= '		return $this->getMethodAction(__FUNCTION__, $args);' . "\n";
283
                $classStr .= '	}' . "\n";
284
            }
285
            $classStr .= '}' . "\n";
286
            // We define the proxy class
287
            eval($classStr);
0 ignored issues
show
introduced by
The use of eval() is discouraged.
Loading history...
288
        }
289
        
290
        $proxy = new $finalProxyClassname($App);
291
        
292
        // $proxy = bab_getInstance($proxyClassname);
293
        return $proxy;
294
    }
295
    
296
    /**
297
     * @return self
298
     */
299
    public function proxy()
300
    {
301
        return self::getProxyInstance($this->App(), get_class($this));
302
    }
303
    
304
    /**
305
     * Get proxy class with action from the new addon controller
306
     *
307
     * @return self
308
     */
309
    protected function quickProxy()
310
    {
311
        $proxy = $this->proxy();
312
        $proxy->createActionMethod = 'createActionForAddon';
313
        return $proxy;
314
    }
315
    
316
    /**
317
     * {@inheritdoc}
318
     * @see \bab_Controller::getObjectName()
319
     */
320
    protected function getObjectName($classname)
321
    {
322
        list ($objectname) = explode('Controller', $classname);
323
        if($this->App()->getComponentByName($objectname)){
324
            return strtolower($objectname);
325
        }
326
        list (, $objectname) = explode('Ctrl', $classname);
327
        return strtolower($objectname);
328
    }
329
    
330
    /**
331
     * Returns the action object corresponding to the current object method $methodName
332
     * with the parameters $args.
333
     *
334
     * @param string $methodName
335
     * @param array $args
336
     * @return WidgetAction Or null on error.
337
     */
338
    protected function getMethodAction($methodName, $args)
339
    {
340
        $fullClassName = substr(get_class($this), 0, - strlen(self::PROXY_CLASS_SUFFIX));
341
        $className = join('', array_slice(explode('\\', $fullClassName), - 1));
342
        
343
        $reflector = new \ReflectionClass(get_class($this));
344
        $parent = $reflector->getParentClass();
345
        if($parent){
0 ignored issues
show
introduced by
$parent is of type ReflectionClass, thus it always evaluated to true.
Loading history...
346
            $parentMethod = $parent->getMethod('__construct');
347
            $docComment = $parentMethod->getDocComment();
348
            if(strpos($docComment, '@isComponentController') !== false){
349
                $fullClassName = $parent->getName();
350
            }
351
        }
352
        
353
        $rc = new \ReflectionClass($fullClassName);
354
        
355
        if(! $rc->hasMethod($methodName)){
356
            throw new \bab_InvalidActionException($fullClassName . '::' . $methodName);
357
        }
358
        $method = new \ReflectionMethod($fullClassName, $methodName);
359
        
360
        $objectName = $this->getObjectName($className);
361
        
362
        $parameters = $method->getParameters();
363
        $actionParams = array();
364
        $argNumber = 0;
365
        foreach ($parameters as $parameter){
366
            $parameterName = $parameter->getName();
367
            if(isset($args[$argNumber])){
368
                $actionParams[$parameterName] = $args[$argNumber];
369
            }
370
            elseif($parameter->isDefaultValueAvailable()){
371
                $actionParams[$parameterName] = $parameter->getDefaultValue();
372
            }
373
            else{
374
                $actionParams[$parameterName] = null;
375
            }
376
            $argNumber ++;
377
        }
378
        
379
        $action = new WidgetAction();
380
        
381
        $action->setMethod($this->getControllerTg(), $objectName . '.' . $methodName, $actionParams);
382
        
383
        $docComment = $method->getDocComment();
384
        if(strpos($docComment, '@ajax') !== false){
385
            $action->setAjax(true);
386
        }
387
        if(strpos($docComment, '@requireSaveMethod') !== false && method_exists($action, 'setRequireSaveMethod')){
388
            $action->setRequireSaveMethod(true);
389
        }
390
        if(strpos($docComment, '@requireDeleteMethod') !== false && method_exists($action, 'setRequireDeleteMethod')){
391
            $action->setRequireDeleteMethod(true);
392
        }
393
        
394
        return $action;
395
    }
396
    
397
    /**
398
     * @return WidgetAction
399
     */
400
    protected function createActionForTg($idx, $actionParams)
401
    {
402
        $action = new WidgetAction();
403
        
404
        $action->setMethod($this->App()->controllerTg, $idx, $actionParams);
405
        
406
        return $action;
407
    }
408
    
409
    /**
410
     * @return WidgetAction
411
     */
412
    protected function createActionForAddon($idx, $actionParams)
413
    {
414
        $App = $this->App();
415
        $action = new WidgetAction();
416
        
417
        $action->setParameters($actionParams);
418
        
419
        list (, , $file) = explode('/', $App->controllerTg);
420
        
421
        $action->setParameter('addon', $App->getAddonName() . '.' . $file);
422
        $action->setParameter('idx', $idx);
423
        
424
        return $action;
425
    }
426
    
427
    /**
428
     * Tries to dispatch the action to the correct sub-controller.
429
     *
430
     * @param WidgetAction $action
431
     * @return mixed
432
     */
433
    final public function execute(WidgetAction $action)
434
    {
435
        $this->app->setCurrentComponent(null);
436
        
437
        $method = $action->getMethod();
438
        
439
        if(! isset($method) || '' === $method){
440
            return false;
441
        }
442
        
443
        list ($objectName,) = explode('.', $method);
444
        
445
        if(! method_exists($this, $objectName)){
446
            /* @var $component AppComponent */
447
            $component = $this->app->getComponentByName($objectName);
448
            if($component){
0 ignored issues
show
introduced by
$component is of type Capwelton\LibApp\AppComponent, thus it always evaluated to true.
Loading history...
449
                $this->app->setCurrentComponent($component);
450
                $objectController = $component->controller(false);
451
            }
452
            else{
453
                header('HTTP/1.0 400 Bad Request');
454
                throw new AppUnknownActionException($action);
455
            }
456
        }
457
        
458
        if(! isset($component)){
459
            $objectController = $this->{$objectName}(false);
460
            if(! ($objectController instanceof AppController)){
461
                return false;
462
            }
463
        }
464
        
465
        try{
466
            $returnedValue = $objectController->execAction($action);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $objectController does not seem to be defined for all execution paths leading up to this point.
Loading history...
467
        }
468
        catch (AppAccessException $e){
469
            
470
            if(! bab_isUserLogged() && $e->requireCredential){
471
                bab_requireCredential($e->getMessage());
472
            }
473
            else{
474
                if($this->isAjaxRequest()){
475
                    
476
                    header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden', true, 403);
477
                    
478
                    die(bab_json_encode(array(
479
                        'exception' => 'app_AccessException',
480
                        'message' => bab_convertStringFromDatabase($e->getMessage(), 'UTF-8'),
481
                        'errorMessage' => bab_convertStringFromDatabase($e->getMessage(), 'UTF-8')
482
                    )));
483
                }
484
                $this->accessPage($e);
485
            }
486
        }
487
        catch (AppSaveException $e){
488
            
489
            if($this->isAjaxRequest()){
490
                header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden', true, 403);
491
                header('Cache-Control: no-cache, must-revalidate');
492
                header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
493
                header('Content-type: application/json');
494
                
495
                die(bab_json_encode(array(
496
                    'exception' => 'app_SaveException',
497
                    'message' => bab_convertStringFromDatabase($e->getMessage(), 'UTF-8'),
498
                    'errorMessage' => bab_convertStringFromDatabase($e->getMessage(), 'UTF-8')
499
                )));
500
            }
501
        }
502
        catch (AppDeletedRecordException $e){
503
            $this->deletedItemPage($action, $e);
504
        }
505
        catch (AppNotFoundException $e){
506
            $this->notFoundPage($action, $e);
507
        }
508
        catch (ORMException $e){
509
            $this->errorPage($e);
510
        }
511
        catch (\Exception $e){
512
            $this->unexpectedErrorPage($e);
513
        }
514
        
515
        $W = bab_Widgets();
516
        
517
        if($returnedValue instanceof WidgetDisplayableInterface){
518
            
519
            if($returnedValue instanceof WidgetBabPage && ! $this->isAjaxRequest()){
520
                
521
                // If the action returned a page, we display it.
522
                $returnedValue->displayHtml();
523
            }
524
            else{
525
                
526
                $htmlCanvas = $W->HtmlCanvas();
527
                if(self::$acceptJson){
528
                    $itemId = $returnedValue->getId();
529
                    $returnArray = array(
530
                        $itemId => $returnedValue->display($htmlCanvas)
531
                    );
532
                    header('Cache-Control: no-cache, must-revalidate');
533
                    header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
534
                    header('Content-type: application/json');
535
                    die(bab_json_encode($returnArray));
536
                }
537
                else{
538
                    header('Cache-Control: no-cache, must-revalidate');
539
                    header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
540
                    header('Content-type: text/html');
541
                    if($returnedValue instanceof WidgetPage && method_exists($returnedValue, 'getPageTitle')){
542
                        $pageTitle = $returnedValue->getPageTitle();
543
                        
544
                        if(method_exists($htmlCanvas, 'sendPageTitle')){
545
                            $htmlCanvas->sendPageTitle($pageTitle);
546
                        }
547
                        else{
548
                            header('X-Cto-PageTitle: ' . $pageTitle);
549
                        }
550
                    }
551
                    $html = $returnedValue->display($htmlCanvas);
552
                    die($html);
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...
553
                }
554
            }
555
        }
556
        elseif(is_array($returnedValue)){
557
            
558
            $htmlCanvas = $W->HtmlCanvas();
559
            $returnedArray = array();
560
            foreach ($returnedValue as $key => &$item){
561
                if($item instanceof WidgetDisplayableInterface){
562
                    $returnedArray[$item->getId()] = $item->display($htmlCanvas);
563
                }
564
                else{
565
                    $returnedArray[$key] = $item;
566
                }
567
            }
568
            header('Cache-Control: no-cache, must-revalidate');
569
            header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
570
            header('Content-type: application/json');
571
            die(bab_convertStringFromDatabase(bab_json_encode($returnedArray), \bab_charset::UTF_8));
572
        }
573
        elseif(true === $returnedValue || is_string($returnedValue)){
574
            
575
            if($this->isAjaxRequest()){
576
                $body = bab_getBody();
577
                $json = array();
578
                $json['messages'] = array();
579
                $toasts = isset($body->messages['toasts']) ? $body->messages['toasts'] : array();
580
                unset($body->messages['toasts']);
581
                $messages = $body->messages;
582
                $errors = $body->errors;
583
                foreach ($messages as $message){
584
                    $json['messages'][] = array(
585
                        'level' => 'info',
586
                        'content' => $message,
587
                        'time' => 4000
588
                    );
589
                }
590
                foreach ($errors as $message){
591
                    $json['messages'][] = array(
592
                        'level' => 'danger',
593
                        'content' => $message
594
                    );
595
                }
596
                $json['toasts'] = $toasts;
597
                if($objectController->getReloadSelectors()){
598
                    $json['reloadSelector'] = implode(',', $objectController->getReloadSelectors());
599
                }
600
                if($objectController->keepDialogOpened){
601
                    $json['keepDialogOpened'] = true;
602
                }
603
                echo bab_json_encode($json);
604
                die();
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...
605
            }
606
        }
607
        
608
        return $returnedValue;
609
    }
610
    
611
    protected function deletedItemPage(WidgetAction $action, AppDeletedRecordException $e)
612
    {
613
        if($this->isAjaxRequest()){
614
            header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden', true, 403);
615
            header('Cache-Control: no-cache, must-revalidate');
616
            header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
617
            header('Content-type: application/json');
618
            
619
            die(app_json_encode(
0 ignored issues
show
Deprecated Code introduced by
The function app_json_encode() has been deprecated: Use bab_json_encode() ( Ignorable by Annotation )

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

619
            die(/** @scrutinizer ignore-deprecated */ app_json_encode(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
620
            array(
621
                'exception' => 'app_SaveException',
622
                'message' => bab_convertStringFromDatabase($e->getMessage(), 'UTF-8'),
623
                'errorMessage' => bab_convertStringFromDatabase($e->getMessage(), 'UTF-8')
624
            )));
625
        }
626
        header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found', true, 404);
627
        
628
        $App = app_App();
629
        $W = bab_Widgets();
630
        
631
        $page = $App->Ui()->ErrorPage();
632
        $page->addClass(\Func_Icons::ICON_LEFT_16);
633
        
634
        $page->addItem($content = $W->FlexItems()
0 ignored issues
show
Bug introduced by
The method FlexItems() does not exist on Func_Widgets. ( Ignorable by Annotation )

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

634
        $page->addItem($content = $W->/** @scrutinizer ignore-call */ FlexItems()

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
635
            ->setSizePolicy('app-error-page-content')
636
            ->setJustifyContent(WidgetFlexLayout::FLEX_JUSTIFY_CONTENT_SPACE_AROUND)
637
            ->setAlignItems(WidgetFlexLayout::FLEX_ALIGN_ITEMS_CENTER));
638
        
639
        // TRANSLATORS: %s can be task, contact, organization ...
640
        $content->addItem($W->FlexItems($W->Label('')
641
            ->setIcon(\Func_Icons::PLACES_USER_TRASH)
642
            ->setIconFormat(48, 'left'), $section = $W->FlexItems()
643
            ->setDirection(WidgetFlexLayout::FLEX_DIRECTION_COL))
644
            ->addClass('widget-50pc alert alert-warning')
645
            ->setAlignItems(WidgetFlexLayout::FLEX_ALIGN_ITEMS_CENTER));
646
        $section->addItems($W->Title($App->translate('Error'), 1), $W->Title(sprintf($App->translate('This %s has been deleted'), $e->getObjectTitle())));
647
        
648
        if($e instanceof AppDeletedRecordException){
0 ignored issues
show
introduced by
$e is always a sub-type of Capwelton\LibApp\Excepti...pDeletedRecordException.
Loading history...
649
            $section->addItems($e->getDeletedBy(), $e->getDeletedOn());
650
        }
651
        
652
        $page->displayHtml();
653
    }
654
    
655
    protected function notFoundPage(WidgetAction $action, AppNotFoundException $e)
656
    {
657
        if($this->isAjaxRequest()){
658
            $message = sprintf(app_translate('This %s does not exists'), $e->getObjectTitle() . ' (' . $e->getId() . ')');
659
            $json = array(
660
                'messages' => array(
661
                    array(
662
                        'level' => 'danger',
663
                        'content' => $message
664
                    )
665
                )
666
            );
667
            echo bab_json_encode($json);
668
            die();
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...
669
        }
670
        header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found', true, 404);
671
        header('Cache-Control: no-cache, must-revalidate');
672
        header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
673
        
674
        $App = app_App();
675
        $W = bab_Widgets();
676
        
677
        $page = $App->Ui()->ErrorPage();
678
        $page->addClass(\Func_Icons::ICON_LEFT_16);
679
        
680
        $page->addItem($content = $W->FlexItems()
681
            ->setSizePolicy('app-error-page-content')
682
            ->setJustifyContent(WidgetFlexLayout::FLEX_JUSTIFY_CONTENT_SPACE_AROUND)
683
            ->setAlignItems(WidgetFlexLayout::FLEX_ALIGN_ITEMS_CENTER));
684
        
685
        // TRANSLATORS: %s can be task, contact, organization ...
686
        $content->addItem($W->FlexItems($W->Label('')
687
            ->setIcon(\Func_Icons::STATUS_DIALOG_QUESTION)
688
            ->setIconFormat(48, 'left'), $section = $W->FlexItems()
689
            ->setDirection(WidgetFlexLayout::FLEX_DIRECTION_COL))
690
            ->addClass('widget-50pc alert alert-warning')
691
            ->setAlignItems(WidgetFlexLayout::FLEX_ALIGN_ITEMS_CENTER));
692
        $section->addItems($W->Title($App->translate('Error'), 1), $W->Title(sprintf($App->translate('This %s does not exists'), $e->getObjectTitle())));
693
        
694
        $page->displayHtml();
695
    }
696
    
697
    protected function unexpectedErrorPage(\Exception $e)
698
    {
699
        if($this->isAjaxRequest()){
700
            $message = sprintf(app_translate('An unexpected error occured') . ':' . '%s', $e->getMessage());
701
            $json = array(
702
                'messages' => array(
703
                    array(
704
                        'level' => 'danger',
705
                        'content' => $message
706
                    )
707
                )
708
            );
709
            echo bab_json_encode($json);
710
            die();
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...
711
        }
712
        header($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal server error', true, 500);
713
        header('Cache-Control: no-cache, must-revalidate');
714
        header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
715
        
716
        $App = app_App();
717
        $W = bab_Widgets();
718
        
719
        $page = $App->Ui()->ErrorPage();
720
        $page->addClass(\Func_Icons::ICON_LEFT_16);
721
        
722
        $page->addItem($content = $W->FlexItems()
723
            ->setSizePolicy('app-error-page-content')
724
            ->setJustifyContent(WidgetFlexLayout::FLEX_JUSTIFY_CONTENT_SPACE_AROUND)
725
            ->setAlignItems(WidgetFlexLayout::FLEX_ALIGN_ITEMS_CENTER));
726
        
727
        // TRANSLATORS: %s can be task, contact, organization ...
728
        $content->addItem($contentBox = $W->FlexItems($W->FlexItems($W->Label('')
729
            ->setIcon(\Func_Icons::STATUS_DIALOG_WARNING)
730
            ->setIconFormat(48, 'left'), $section = $W->FlexItems()
731
            ->setDirection(WidgetFlexLayout::FLEX_DIRECTION_COL))
732
            ->setAlignItems(WidgetFlexLayout::FLEX_ALIGN_ITEMS_CENTER))
733
            ->addClass('widget-50pc alert alert-danger')
734
            ->setDirection(WidgetFlexLayout::FLEX_DIRECTION_COL));
735
        
736
        $logCode = '#' . hrtime(true);
0 ignored issues
show
Bug introduced by
Are you sure hrtime(true) of type array|double|integer 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

736
        $logCode = '#' . /** @scrutinizer ignore-type */ hrtime(true);
Loading history...
737
        $message = addcslashes($e->getMessage(), "\000..\037\177..\377\\");
738
        $trace = addcslashes($e->getTraceAsString(), "\000..\037\177..\377\\");
739
        
740
        error_log(sprintf('Error %s : %s', $logCode, $message) . PHP_EOL . $trace);
741
        
742
        $section->addItems($W->Title($App->translate('Error'), 1), $W->Title($App->translate('An unexpected error occured')), $W->Label(sprintf($App->translate('It has been logged with the following error code : %s'), $logCode)));
743
        
744
        if(bab_isUserAdministrator()){
745
            $contentBox->addItem($W->Section('Stack trace', $stackTraceBox = $W->FlexItems($W->Label($message)
746
                ->addClass('widget-description'))
747
                ->setDirection(WidgetFlexLayout::FLEX_DIRECTION_COL))
748
                ->setFoldable(true, true));
749
            $traces = explode("\n", $e->getTraceAsString());
750
            foreach ($traces as $trace){
751
                $stackTraceBox->addItem($W->Label($trace));
752
            }
753
        }
754
        else{
755
            $section->addItem($W->Label($App->translate('Please contact the administrator')));
756
        }
757
        
758
        $page->displayHtml();
759
    }
760
    
761
    protected function errorPage(\Exception $e)
762
    {
763
        if($this->isAjaxRequest()){
764
            $message = sprintf(app_translate('An unexpected error occured') . ':' . '%s', $e->getMessage());
765
            $json = array(
766
                'messages' => array(
767
                    array(
768
                        'level' => 'danger',
769
                        'content' => $message
770
                    )
771
                )
772
            );
773
            echo bab_json_encode($json);
774
            die();
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...
775
        }
776
        header($_SERVER['SERVER_PROTOCOL'] . ' 500 Internal server error', true, 500);
777
        header('Cache-Control: no-cache, must-revalidate');
778
        header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
779
        
780
        $App = app_App();
781
        $W = bab_Widgets();
782
        
783
        $page = $App->Ui()->ErrorPage();
784
        $page->addClass(\Func_Icons::ICON_LEFT_16);
785
        
786
        $page->addItem($content = $W->FlexItems()
787
            ->setSizePolicy('app-error-page-content')
788
            ->setJustifyContent(WidgetFlexLayout::FLEX_JUSTIFY_CONTENT_SPACE_AROUND)
789
            ->setAlignItems(WidgetFlexLayout::FLEX_ALIGN_ITEMS_CENTER));
790
        
791
        // TRANSLATORS: %s can be task, contact, organization ...
792
        $content->addItem($contentBox = $W->FlexItems($W->FlexItems($W->Label('')
793
            ->setIcon(\Func_Icons::STATUS_DIALOG_WARNING)
794
            ->setIconFormat(48, 'left'), $section = $W->FlexItems()
795
            ->setDirection(WidgetFlexLayout::FLEX_DIRECTION_COL))
796
            ->setAlignItems(WidgetFlexLayout::FLEX_ALIGN_ITEMS_CENTER))
797
            ->addClass('widget-50pc alert alert-danger')
798
            ->setDirection(WidgetFlexLayout::FLEX_DIRECTION_COL));
799
        
800
        $logCode = '#' . hrtime(true);
0 ignored issues
show
Bug introduced by
Are you sure hrtime(true) of type array|double|integer 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

800
        $logCode = '#' . /** @scrutinizer ignore-type */ hrtime(true);
Loading history...
801
        $message = addcslashes($e->getMessage(), "\000..\037\177..\377\\");
802
        $trace = addcslashes($e->getTraceAsString(), "\000..\037\177..\377\\");
803
        
804
        error_log(sprintf('Error %s : %s', $logCode, $message) . PHP_EOL . $trace);
805
        
806
        $section->addItems($W->Title($App->translate('Error'), 1), $W->Title($App->translate('An unexpected error occured')), $W->Label(sprintf($App->translate('It has been logged with the following error code : %s'), $logCode)));
807
        
808
        if(bab_isUserAdministrator()){
809
            $contentBox->addItem($W->Section('Stack trace', $stackTraceBox = $W->FlexItems($W->Label($message)
810
                ->addClass('widget-description'))
811
                ->setDirection(WidgetFlexLayout::FLEX_DIRECTION_COL))
812
                ->setFoldable(true, true));
813
            $traces = explode("\n", $e->getTraceAsString());
814
            foreach ($traces as $trace){
815
                $stackTraceBox->addItem($W->Label($trace));
816
            }
817
        }
818
        else{
819
            $section->addItem($W->Label($App->translate('Please contact the administrator')));
820
        }
821
        
822
        $page->displayHtml();
823
    }
824
    
825
    protected function accessPage(\Exception $e)
826
    {
827
        if($this->isAjaxRequest()){
828
            $message = $e->getMessage();
829
            $json = array(
830
                'messages' => array(
831
                    array(
832
                        'level' => 'danger',
833
                        'content' => $message
834
                    )
835
                )
836
            );
837
            echo bab_json_encode($json);
838
            die();
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...
839
        }
840
        header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden', true, 403);
841
        header('Cache-Control: no-cache, must-revalidate');
842
        header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
843
        
844
        $App = app_App();
845
        $W = bab_Widgets();
846
        
847
        $page = $App->Ui()->ErrorPage();
848
        $page->addClass(\Func_Icons::ICON_LEFT_16);
849
        
850
        $page->addItem($content = $W->FlexItems()
851
            ->setSizePolicy('app-error-page-content')
852
            ->setJustifyContent(WidgetFlexLayout::FLEX_JUSTIFY_CONTENT_SPACE_AROUND)
853
            ->setAlignItems(WidgetFlexLayout::FLEX_ALIGN_ITEMS_CENTER));
854
        
855
        // TRANSLATORS: %s can be task, contact, organization ...
856
        $content->addItem($W->FlexItems($W->FlexItems($W->Label('')
857
            ->setIcon(\Func_Icons_Awesome::WEBAPP_UNLOCK_ALT)
0 ignored issues
show
Bug introduced by
The type Func_Icons_Awesome was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
858
            ->setIconFormat(48, 'left'), $section = $W->FlexItems()
859
            ->setDirection(WidgetFlexLayout::FLEX_DIRECTION_COL))
860
            ->setAlignItems(WidgetFlexLayout::FLEX_ALIGN_ITEMS_CENTER))
861
            ->addClass('widget-50pc alert alert-danger')
862
            ->setDirection(WidgetFlexLayout::FLEX_DIRECTION_COL));
863
        
864
        $section->addItems($W->Title($App->translate('Error'), 1), $W->Label($e->getMessage()));
865
        
866
        $page->displayHtml();
867
    }
868
    
869
    /**
870
     * Method to call before saving
871
     *
872
     * @since 1.0.22
873
     * @return self
874
     */
875
    public function requireSaveMethod()
876
    {
877
        if('GET' === $_SERVER['REQUEST_METHOD']){
878
            throw new AppException('Method not allowed');
879
        }
880
        
881
        return $this;
882
    }
883
    
884
    /**
885
     * Method to call before deleting
886
     *
887
     * @since 1.0.22
888
     * @return self
889
     */
890
    public function requireDeleteMethod()
891
    {
892
        if('GET' === $_SERVER['REQUEST_METHOD']){
893
            throw new AppException('Method not allowed');
894
        }
895
        
896
        return $this;
897
    }
898
    
899
    /**
900
     * Similar to the addMessage method, addToast allows for more customization
901
     *
902
     * @param string $message
903
     *            The message displayed in the toast. Can be HTML or string
904
     * @param string $title
905
     *            The title of the toast.
906
     * @param string $type
907
     *            Choose between 'text', 'log', 'success', 'warn', 'error', 'info'. Other values will result in a 'info' type
908
     * @param string $position
909
     *            The position on the screen of the toast. Can be 'tl', 'tm', 'tr', 'ml', 'mm', 'mr', 'bl', 'bm' or 'br' (first letter is for 'Top', 'Middle', or 'Bottom', second one is for 'Left', 'Middle', 'Right')
910
     * @param int $duration
911
     *            The duration in milliseconds the toast will be shown
912
     * @return self
913
     */
914
    public function addToast($message, $title = '', $type = 'success', $position = 'tr', $duration = 8000)
915
    {
916
        $toast = array(
917
            'title' => $title,
918
            'message' => $message,
919
            'type' => $type,
920
            'duration' => $duration,
921
            'position' => $position
922
        );
923
        $babBody = bab_getBody();
924
        if(! isset($babBody->messages['toasts'])){
925
            $babBody->messages['toasts'] = array();
926
        }
927
        $babBody->messages['toasts'][] = $toast;
928
        return $this;
929
    }
930
    
931
    public function getToasts()
932
    {
933
        return $this->toasts;
934
    }
935
    
936
    /**
937
     * Custom fields
938
     *
939
     * @return AppCtrlCustomField
940
     */
941
    public function CustomField($proxy = true)
942
    {
943
        return $this->App()->ControllerProxy('Capwelton\LibApp\Ctrl\AppCtrlCustomField', $proxy);
944
    }
945
    
946
    /**
947
     * Custom sections
948
     *
949
     * @return AppCtrlCustomSection
950
     */
951
    public function CustomSection($proxy = true)
952
    {
953
        return $this->App()->ControllerProxy('Capwelton\LibApp\Ctrl\AppCtrlCustomSection', $proxy);
954
    }
955
    
956
    /**
957
     * Custom containers
958
     *
959
     * @return AppCtrlCustomContainer
960
     */
961
    public function CustomContainer($proxy = true)
962
    {
963
        return $this->App()->ControllerProxy('Capwelton\LibApp\Ctrl\AppCtrlCustomContainer', $proxy);
964
    }
965
    
966
    /**
967
     * Notification
968
     *
969
     * @return AppCtrlNotification
970
     */
971
    public function Notification($proxy = true)
972
    {
973
        return $this->App()->ControllerProxy('Capwelton\LibApp\Ctrl\AppCtrlNotification', $proxy);
974
    }
975
    
976
    /**
977
     * SSE
978
     *
979
     * @return AppCtrlSSE
980
     */
981
    public function SSE($proxy = true)
982
    {
983
        return $this->App()->ControllerProxy('Capwelton\LibApp\Ctrl\AppCtrlSSE', $proxy);
984
    }
985
    
986
    /**
987
     * Addon configuration
988
     *
989
     * @return AppCtrlAddonConfiguration
990
     */
991
    public function AddonConfiguration($proxy = true)
992
    {
993
        return $this->App()->ControllerProxy('Capwelton\LibApp\Ctrl\AppCtrlAddonConfiguration', $proxy);
994
    }
995
    
996
    /**
997
     * Addon configuration
998
     *
999
     * @return AppCtrlConfiguration
1000
     */
1001
    public function Configuration($proxy = true)
1002
    {
1003
        return $this->App()->ControllerProxy('Capwelton\LibApp\Ctrl\AppCtrlConfiguration', $proxy);
1004
    }
1005
    
1006
    public function accessDenied()
1007
    {
1008
        $App = $this->App();
1009
        $page = $this->accessPage(new AppAccessException($App->translate('Access denied')));
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $page is correct as $this->accessPage(new Ca...late('Access denied'))) targeting Capwelton\LibApp\Ctrl\AppController::accessPage() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
1010
        return $page;
1011
    }
1012
}
1013