Completed
Push — develop ( b8de44...c0835d )
by John
03:40
created

ActiveRecordController::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 10
rs 9.4285
cc 1
eloc 5
nc 1
nop 1
1
<?php
2
3
namespace Alpha\Controller;
4
5
use Alpha\Controller\Front\FrontController;
6
use Alpha\Util\Logging\Logger;
7
use Alpha\Util\Config\ConfigProvider;
8
use Alpha\Util\Http\Request;
9
use Alpha\Util\Http\Response;
10
use Alpha\Util\Helper\Validator;
11
use Alpha\View\View;
12
use Alpha\View\ViewState;
13
use Alpha\Exception\IllegalArguementException;
14
use Alpha\Exception\ResourceNotFoundException;
15
use Alpha\Exception\ResourceNotAllowedException;
16
use Alpha\Exception\SecurityException;
17
use Alpha\Exception\AlphaException;
18
use Alpha\Exception\RecordNotFoundException;
19
use Alpha\Exception\ValidationException;
20
use Alpha\Model\ActiveRecord;
21
22
/**
23
 * The main active record CRUD controller for the framework.
24
 *
25
 * @since 2.0
26
 *
27
 * @author John Collins <[email protected]>
28
 * @license http://www.opensource.org/licenses/bsd-license.php The BSD License
29
 * @copyright Copyright (c) 2017, John Collins (founder of Alpha Framework).
30
 * All rights reserved.
31
 *
32
 * <pre>
33
 * Redistribution and use in source and binary forms, with or
34
 * without modification, are permitted provided that the
35
 * following conditions are met:
36
 *
37
 * * Redistributions of source code must retain the above
38
 *   copyright notice, this list of conditions and the
39
 *   following disclaimer.
40
 * * Redistributions in binary form must reproduce the above
41
 *   copyright notice, this list of conditions and the
42
 *   following disclaimer in the documentation and/or other
43
 *   materials provided with the distribution.
44
 * * Neither the name of the Alpha Framework nor the names
45
 *   of its contributors may be used to endorse or promote
46
 *   products derived from this software without specific
47
 *   prior written permission.
48
 *
49
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
50
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
51
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
52
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
53
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
54
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
55
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
56
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
57
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
59
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
60
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
61
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
62
 * </pre>
63
 */
64
class ActiveRecordController extends Controller implements ControllerInterface
65
{
66
    /**
67
     * The start number for list pageination.
68
     *
69
     * @var int
70
     *
71
     * @since 2.0
72
     */
73
    protected $start = 0;
74
75
    /**
76
     * The amount of records to return during pageination.
77
     *
78
     * @var int
79
     *
80
     * @since 2.0
81
     */
82
    protected $limit;
83
84
    /**
85
     * The count of the records of this type in the database (used during pagination).
86
     *
87
     * @var int
88
     *
89
     * @since 2.0
90
     */
91
    protected $recordCount = 0;
92
93
    /**
94
     * The field name to sort the list by (optional, default is OID).
95
     *
96
     * @var string
97
     *
98
     * @since 2.0
99
     */
100
    protected $sort;
101
102
    /**
103
     * The order to sort the list by (optional, should be ASC or DESC, default is ASC).
104
     *
105
     * @var string
106
     *
107
     * @since 2.0
108
     */
109
    protected $order;
110
111
    /**
112
     * The name of the BO field to filter the list by (optional).
113
     *
114
     * @var string
115
     *
116
     * @since 2.0
117
     */
118
    protected $filterField;
119
120
    /**
121
     * The value of the filterField to filter by (optional).
122
     *
123
     * @var string
124
     *
125
     * @since 2.0
126
     */
127
    protected $filterValue;
128
129
    /**
130
     * Trace logger.
131
     *
132
     * @var \Alpha\Util\Logging\Logger
133
     *
134
     * @since 2.0
135
     */
136
    private static $logger = null;
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
137
138
    /**
139
     * Constructor to set up the object.
140
     *
141
     * @param string $visibility The name of the rights group that can access this controller.
142
     *
143
     * @since 1.0
144
     */
145
    public function __construct($visibility = 'Admin')
146
    {
147
        self::$logger = new Logger('ActiveRecordController');
148
        self::$logger->debug('>>__construct()');
149
150
        // ensure that the super class constructor is called, indicating the rights group
151
        parent::__construct($visibility);
152
153
        self::$logger->debug('<<__construct');
154
    }
155
156
    /**
157
     * Handle GET requests.
158
     *
159
     * @param \Alpha\Util\Http\Request $request
160
     *
161
     * @throws \Alpha\Exception\ResourceNotFoundException
162
     * @throws \Alpha\Exception\IllegalArguementException
163
     *
164
     * @return \Alpha\Util\Http\Response
165
     *
166
     * @since 2.0
167
     */
168
    public function doGET($request)
169
    {
170
        self::$logger->debug('>>doGET(request=['.var_export($request, true).'])');
171
172
        $params = $request->getParams();
173
        $accept = $request->getAccept();
174
175
        $body = '';
176
177
        try {
178
            // get a single record
179
            if (isset($params['ActiveRecordType']) && isset($params['ActiveRecordOID'])) {
180 View Code Duplication
                if (!Validator::isInteger($params['ActiveRecordOID'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
181
                    throw new IllegalArguementException('Invalid oid ['.$params['ActiveRecordOID'].'] provided on the request!');
182
                }
183
184
                $ActiveRecordType = urldecode($params['ActiveRecordType']);
185
186
                if (class_exists($ActiveRecordType)) {
187
                    $record = new $ActiveRecordType();
188
                } else {
189
                    throw new IllegalArguementException('No ActiveRecord available to view!');
190
                }
191
192
                // set up the title and meta details
193
                if (isset($params['view']) && $params['view'] == 'edit') {
194
                    if (!isset($this->title)) {
195
                        $this->setTitle('Editing a '.$record->getFriendlyClassName());
196
                    }
197
                    if (!isset($this->description)) {
198
                        $this->setDescription('Page to edit a '.$record->getFriendlyClassName().'.');
199
                    }
200
                    if (!isset($this->keywords)) {
201
                        $this->setKeywords('edit,'.$record->getFriendlyClassName());
202
                    }
203
                } else {
204
                    if (!isset($this->title)) {
205
                        $this->setTitle('Viewing a '.$record->getFriendlyClassName());
206
                    }
207
                    if (!isset($this->description)) {
208
                        $this->setDescription('Page to view a '.$record->getFriendlyClassName().'.');
209
                    }
210
                    if (!isset($this->keywords)) {
211
                        $this->setKeywords('view,'.$record->getFriendlyClassName());
212
                    }
213
                }
214
215
                $record->load($params['ActiveRecordOID']);
216
                ActiveRecord::disconnect();
217
218
                $view = View::getInstance($record, false, $accept);
219
220
                $body .= View::displayPageHead($this);
221
222
                $message = $this->getStatusMessage();
223
                if (!empty($message)) {
224
                    $body .= $message;
225
                }
226
227
                $body .= View::renderDeleteForm($request->getURI());
228
229
                if (isset($params['view']) && $params['view'] == 'edit') {
230
                    $fields = array('formAction' => $this->request->getURI());
231
                    $body .= $view->editView($fields);
232
                } else {
233
                    $body .= $view->detailedView();
234
                }
235
            } elseif (isset($params['ActiveRecordType']) && isset($params['start'])) {
236
                // list all records of this type
237
                $ActiveRecordType = urldecode($params['ActiveRecordType']);
238
239
                if (class_exists($ActiveRecordType)) {
240
                    $record = new $ActiveRecordType();
241
                } else {
242
                    throw new IllegalArguementException('No ActiveRecord available to view!');
243
                }
244
245
                // set up the title and meta details
246
                if (!isset($this->title)) {
247
                    $this->setTitle('Listing all '.$record->getFriendlyClassName());
248
                }
249
                if (!isset($this->description)) {
250
                    $this->setDescription('Listing all '.$record->getFriendlyClassName());
251
                }
252
                if (!isset($this->keywords)) {
253
                    $this->setKeywords('list,all,'.$record->getFriendlyClassName());
254
                }
255
256
                if (isset($this->filterField) && isset($this->filterValue)) {
257
                    if (isset($this->sort) && isset($this->order)) {
258
                        $records = $record->loadAllByAttribute($this->filterField, $this->filterValue, $params['start'], $params['limit'],
259
                            $this->sort, $this->order);
260
                    } else {
261
                        $records = $record->loadAllByAttribute($this->filterField, $this->filterValue, $params['start'], $params['limit']);
262
                    }
263
264
                    $this->recordCount = $record->getCount(array($this->filterField), array($this->filterValue));
265
                } else {
266
                    if (isset($this->sort) && isset($this->order)) {
267
                        $records = $record->loadAll($params['start'], $params['limit'], $this->sort, $this->order);
268
                    } else {
269
                        $records = $record->loadAll($params['start'], $params['limit']);
270
                    }
271
272
                    $this->recordCount = $record->getCount();
273
                }
274
275
                ActiveRecord::disconnect();
276
277
                $view = View::getInstance($record, false, $accept);
278
279
                $body .= View::displayPageHead($this);
280
281
                $message = $this->getStatusMessage();
282
                if (!empty($message)) {
283
                    $body .= $message;
284
                }
285
286
                $body .= View::renderDeleteForm($this->request->getURI());
287
288 View Code Duplication
                foreach ($records as $record) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
289
                    $view = View::getInstance($record, false, $accept);
290
                    $fields = array('formAction' => $this->request->getURI());
291
                    $body .= $view->listView($fields);
292
                }
293
294
                if ($accept == 'application/json') {
295
                    $body = rtrim($body, ',');
296
                }
297
            } elseif (isset($params['ActiveRecordType'])) {
298
                // create a new record of this type
299
                $ActiveRecordType = urldecode($params['ActiveRecordType']);
300
301
                if (class_exists($ActiveRecordType)) {
302
                    $record = new $ActiveRecordType();
303
                } else {
304
                    throw new IllegalArguementException('No ActiveRecord available to create!');
305
                }
306
307
                // set up the title and meta details
308
                if (!isset($this->title)) {
309
                    $this->setTitle('Create a new '.$record->getFriendlyClassName());
310
                }
311
                if (!isset($this->description)) {
312
                    $this->setDescription('Create a new '.$record->getFriendlyClassName().'.');
313
                }
314
                if (!isset($this->keywords)) {
315
                    $this->setKeywords('create,new,'.$record->getFriendlyClassName());
316
                }
317
318
                $view = View::getInstance($record, false, $accept);
319
320
                $body .= View::displayPageHead($this);
321
                $fields = array('formAction' => $this->request->getURI());
322
                $body .= $view->createView($fields);
323
            } else {
324
                throw new IllegalArguementException('No ActiveRecord available to display!');
325
            }
326
        } catch (IllegalArguementException $e) {
327
            self::$logger->warn($e->getMessage());
328
            throw new ResourceNotFoundException('The record that you have requested cannot be found!');
329
        } catch (RecordNotFoundException $e) {
330
            self::$logger->warn($e->getMessage());
331
            throw new ResourceNotFoundException('The record that you have requested cannot be found!');
332
        }
333
334
        $body .= View::displayPageFoot($this);
335
336
        self::$logger->debug('<<doGET');
337
338
        return new Response(200, $body, array('Content-Type' => ($accept == 'application/json' ? 'application/json' : 'text/html')));
339
    }
340
341
    /**
342
     * Method to handle POST requests.
343
     *
344
     * @param \Alpha\Util\Http\Request $request
345
     *
346
     * @throws \Alpha\Exception\IllegalArguementException
347
     * @throws \Alpha\Exception\SecurityException
348
     *
349
     * @return \Alpha\Util\Http\Response
350
     *
351
     * @since 2.0
352
     */
353
    public function doPOST($request)
354
    {
355
        self::$logger->debug('>>doDPOST(request=['.var_export($request, true).'])');
356
357
        $config = ConfigProvider::getInstance();
358
359
        $params = $request->getParams();
360
        $accept = $request->getAccept();
361
362
        try {
363 View Code Duplication
            if (isset($params['ActiveRecordType'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
364
                $ActiveRecordType = urldecode($params['ActiveRecordType']);
365
            } else {
366
                throw new IllegalArguementException('No ActiveRecord available to create!');
367
            }
368
369 View Code Duplication
            if (class_exists($ActiveRecordType)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
370
                $record = new $ActiveRecordType();
371
            } else {
372
                throw new IllegalArguementException('No ActiveRecord ['.$ActiveRecordType.'] available to create!');
373
            }
374
375
            // check the hidden security fields before accepting the form POST data
376
            if (!$this->checkSecurityFields()) {
377
                throw new SecurityException('This page cannot accept post data from remote servers!');
378
            }
379
380
            $record->populateFromArray($params);
381
            $record->save();
382
383
            self::$logger->action('Created new '.$ActiveRecordType.' instance with OID '.$record->getOID());
384
385 View Code Duplication
            if (isset($params['statusMessage'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
386
                $this->setStatusMessage(View::displayUpdateMessage($params['statusMessage']));
387
            } else {
388
                $this->setStatusMessage(View::displayUpdateMessage('Created'));
389
            }
390
391
            ActiveRecord::disconnect();
392
        } catch (SecurityException $e) {
393
            self::$logger->warn($e->getMessage());
394
            throw new ResourceNotAllowedException($e->getMessage());
395
        } catch (IllegalArguementException $e) {
396
            self::$logger->warn($e->getMessage());
397
            throw new ResourceNotFoundException('The record that you have requested cannot be found!');
398
        } catch (ValidationException $e) {
399
            self::$logger->warn($e->getMessage());
400
            $this->setStatusMessage(View::displayErrorMessage($e->getMessage()));
401
        }
402
403
        if ($accept == 'application/json') {
404
            $view = View::getInstance($record, false, $accept);
0 ignored issues
show
Bug introduced by
The variable $record does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
405
            $body = $view->detailedView();
406
            $response = new Response(201);
407
            $response->setHeader('Content-Type', 'application/json');
408
            $response->setHeader('Location', $config->get('app.url').'/record/'.$params['ActiveRecordType'].'/'.$record->getOID());
409
            $response->setBody($body);
410
        } else {
411
            $response = new Response(301);
412
413
            if ($this->getNextJob() != '') {
414
                $response->redirect($this->getNextJob());
415
            } else {
416
                if ($this->request->isSecureURI()) {
417
                    $response->redirect(FrontController::generateSecureURL('act=Alpha\\Controller\\ActiveRecordController&ActiveRecordType='.$ActiveRecordType.'&ActiveRecordOID='.$record->getOID()));
0 ignored issues
show
Bug introduced by
The variable $ActiveRecordType does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
418
                } else {
419
                    $response->redirect($config->get('app.url').'/record/'.$params['ActiveRecordType'].'/'.$record->getOID());
420
                }
421
            }
422
        }
423
424
        self::$logger->debug('<<doPOST');
425
426
        return $response;
427
    }
428
429
    /**
430
     * Method to handle PUT requests.
431
     *
432
     * @param \Alpha\Util\Http\Request $request
433
     *
434
     * @throws \Alpha\Exception\IllegalArguementException
435
     * @throws \Alpha\Exception\SecurityException
436
     *
437
     * @return \Alpha\Util\Http\Response
438
     *
439
     * @since 2.0
440
     */
441
    public function doPUT($request)
442
    {
443
        self::$logger->debug('>>doPUT(request=['.var_export($request, true).'])');
444
445
        $config = ConfigProvider::getInstance();
446
447
        $params = $request->getParams();
448
        $accept = $request->getAccept();
449
450
        try {
451 View Code Duplication
            if (isset($params['ActiveRecordType'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
452
                $ActiveRecordType = urldecode($params['ActiveRecordType']);
453
            } else {
454
                throw new IllegalArguementException('No ActiveRecord available to edit!');
455
            }
456
457 View Code Duplication
            if (class_exists($ActiveRecordType)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
458
                $record = new $ActiveRecordType();
459
            } else {
460
                throw new IllegalArguementException('No ActiveRecord ['.$ActiveRecordType.'] available to edit!');
461
            }
462
463
            // check the hidden security fields before accepting the form POST data
464
            if (!$this->checkSecurityFields()) {
465
                throw new SecurityException('This page cannot accept post data from remote servers!');
466
            }
467
468
            $record->load($params['ActiveRecordOID']);
469
            $record->populateFromArray($params);
470
            $record->save();
471
472
            self::$logger->action('Saved '.$ActiveRecordType.' instance with OID '.$record->getOID());
473
474 View Code Duplication
            if (isset($params['statusMessage'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
475
                $this->setStatusMessage(View::displayUpdateMessage($params['statusMessage']));
476
            } else {
477
                $this->setStatusMessage(View::displayUpdateMessage('Saved'));
478
            }
479
480
            ActiveRecord::disconnect();
481
        } catch (SecurityException $e) {
482
            self::$logger->warn($e->getMessage());
483
            throw new ResourceNotAllowedException($e->getMessage());
484
        } catch (IllegalArguementException $e) {
485
            self::$logger->warn($e->getMessage());
486
            throw new ResourceNotFoundException('The record that you have requested cannot be found!');
487
        } catch (RecordNotFoundException $e) {
488
            self::$logger->warn($e->getMessage());
489
            throw new ResourceNotFoundException('The record that you have requested cannot be found!');
490
        } catch (ValidationException $e) {
491
            self::$logger->warn($e->getMessage());
492
            $this->setStatusMessage(View::displayErrorMessage($e->getMessage()));
493
        }
494
495
        if ($accept == 'application/json') {
496
            $view = View::getInstance($record, false, $accept);
0 ignored issues
show
Bug introduced by
The variable $record does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
497
            $body = $view->detailedView();
498
            $response = new Response(200);
499
            $response->setHeader('Content-Type', 'application/json');
500
            $response->setHeader('Location', $config->get('app.url').'/record/'.$params['ActiveRecordType'].'/'.$record->getOID());
501
            $response->setBody($body);
502
        } else {
503
            $response = new Response(301);
504
505
            if ($this->getNextJob() != '') {
506
                $response->redirect($this->getNextJob());
507
            } else {
508
                if ($this->request->isSecureURI()) {
509
                    $response->redirect(FrontController::generateSecureURL('act=Alpha\\Controller\\ActiveRecordController&ActiveRecordType='.urldecode($params['ActiveRecordType']).'&ActiveRecordOID='.$record->getOID().'&view=edit'));
510
                } else {
511
                    $response->redirect($config->get('app.url').'/record/'.$params['ActiveRecordType'].'/'.$record->getOID().'/edit');
512
                }
513
            }
514
        }
515
516
        self::$logger->debug('<<doPUT');
517
518
        return $response;
519
    }
520
521
    /**
522
     * Method to handle DELETE requests.
523
     *
524
     * @param \Alpha\Util\Http\Request $request
525
     *
526
     * @throws \Alpha\Exception\IllegalArguementException
527
     * @throws \Alpha\Exception\SecurityException
528
     * @throws \Alpha\Exception\ResourceNotAllowedException
529
     *
530
     * @return \Alpha\Util\Http\Response
531
     *
532
     * @since 2.0
533
     */
534
    public function doDELETE($request)
535
    {
536
        self::$logger->debug('>>doDELETE(request=['.var_export($request, true).'])');
537
538
        $config = ConfigProvider::getInstance();
539
540
        $params = $request->getParams();
541
        $accept = $request->getAccept();
542
543
        try {
544
            // check the hidden security fields before accepting the form data
545
            if (!$this->checkSecurityFields()) {
546
                throw new SecurityException('This page cannot accept data from remote servers!');
547
            }
548
549 View Code Duplication
            if (isset($params['ActiveRecordType'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
550
                $ActiveRecordType = urldecode($params['ActiveRecordType']);
551
            } else {
552
                throw new IllegalArguementException('No ActiveRecord available to edit!');
553
            }
554
555 View Code Duplication
            if (class_exists($ActiveRecordType)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
556
                $record = new $ActiveRecordType();
557
            } else {
558
                throw new IllegalArguementException('No ActiveRecord ['.$ActiveRecordType.'] available to edit!');
559
            }
560
561
            // check the hidden security fields before accepting the form POST data
562
            if (!$this->checkSecurityFields()) {
563
                throw new SecurityException('This page cannot accept post data from remote servers!');
564
            }
565
566
            $record->load($params['ActiveRecordOID']);
567
568
            ActiveRecord::begin();
569
            $record->delete();
570
            ActiveRecord::commit();
571
            ActiveRecord::disconnect();
572
573
            self::$logger->action('Deleted '.$ActiveRecordType.' instance with OID '.$params['ActiveRecordOID']);
574
575
            if ($accept == 'application/json') {
576
                $response = new Response(200);
577
                $response->setHeader('Content-Type', 'application/json');
578
                $response->setBody(json_encode(array('message' => 'deleted')));
579
            } else {
580
                $response = new Response(301);
581
582 View Code Duplication
                if (isset($params['statusMessage'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
583
                    $this->setStatusMessage(View::displayUpdateMessage($params['statusMessage']));
584
                } else {
585
                    $this->setStatusMessage(View::displayUpdateMessage('Deleted'));
586
                }
587
588
                if ($this->getNextJob() != '') {
589
                    $response->redirect($this->getNextJob());
590
                } else {
591
                    if ($this->request->isSecureURI()) {
592
                        $response->redirect(FrontController::generateSecureURL('act=Alpha\\Controller\\ActiveRecordController&ActiveRecordType='.$ActiveRecordType.'&start=0&limit='.$config->get('app.list.page.amount')));
593
                    } else {
594
                        $response->redirect($config->get('app.url').'/records/'.$params['ActiveRecordType']);
595
                    }
596
                }
597
            }
598
599
            self::$logger->debug('<<doDELETE');
600
601
            return $response;
602
        } catch (SecurityException $e) {
603
            self::$logger->warn($e->getMessage());
604
            throw new ResourceNotAllowedException($e->getMessage());
605
        } catch (RecordNotFoundException $e) {
606
            self::$logger->warn($e->getMessage());
607
            throw new ResourceNotFoundException('The item that you have requested cannot be found!');
608
        } catch (AlphaException $e) {
609
            self::$logger->error($e->getMessage());
610
            ActiveRecord::rollback();
611
            throw new ResourceNotAllowedException($e->getMessage());
612
        }
613
    }
614
615
    /**
616
     * Sets up the pagination start point and limit.
617
     *
618
     * @since 2.0
619
     */
620
    public function after_displayPageHead_callback()
621
    {
622
        $body = parent::after_displayPageHead_callback();
623
624
        // set the start point for the list pagination
625
        if ($this->request->getParam('start') != null) {
626
            $this->start = $this->request->getParam('start');
627
628
            $viewState = ViewState::getInstance();
629
            $viewState->set('selectedStart', $this->start);
630
631
            if ($this->request->getParam('limit') != null) {
632
                $this->limit = $this->request->getParam('limit');
633
            } else {
634
                $config = ConfigProvider::getInstance();
635
                $this->limit = $config->get('app.list.page.amount');
0 ignored issues
show
Documentation Bug introduced by
The property $limit was declared of type integer, but $config->get('app.list.page.amount') is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
636
            }
637
638
            $accept = $this->request->getAccept();
639
640
            if ($accept == 'application/json') {
641
                $body .= '[';
642
            }
643
        }
644
645
        return $body;
646
    }
647
648
    /**
649
     * Method to display the page footer with pageination links.
650
     *
651
     * @return string
652
     *
653
     * @since 2.0
654
     */
655
    public function before_displayPageFoot_callback()
656
    {
657
        $body = '';
658
659
        if ($this->request->getParam('start') != null) {
660
            $accept = $this->request->getAccept();
661
662
            if ($accept == 'application/json') {
663
                $body .= ']';
664
            } else {
665
                $body .= $this->renderPageLinks();
666
                $body .= '<br>';
667
            }
668
        }
669
670
        return $body;
671
    }
672
673
    /**
674
     * Method for rendering the pagination links.
675
     *
676
     * @return string
677
     *
678
     * @since 2.0
679
     */
680
    protected function renderPageLinks()
681
    {
682
        $config = ConfigProvider::getInstance();
683
684
        $body = '';
685
686
        // the index of the last record displayed on this page
687
        $last = $this->start + $config->get('app.list.page.amount');
688
689
        // ensure that the last index never overruns the total record count
690
        if ($last > $this->recordCount) {
691
            $last = $this->recordCount;
692
        }
693
694
        // render a message for an empty list
695
        if ($this->recordCount > 0) {
696
            $body .= '<ul class="pagination">';
697
        } else {
698
            $body .= '<p align="center">The list is empty.&nbsp;&nbsp;</p>';
699
700
            return $body;
701
        }
702
703
        // render "Previous" link
704
        if ($this->start > 0) {
705
            // handle secure URLs
706 View Code Duplication
            if ($this->request->getParam('token', null) != null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
707
                $body .= '<li><a href="'.FrontController::generateSecureURL('act=Alpha\Controller\ActiveRecordController&ActiveRecordType='.$this->request->getParam('ActiveRecordType').'&start='.($this->start - $this->limit).'&limit='.$this->limit).'">&lt;&lt;-Previous</a></li>';
708
            } else {
709
                $body .= '<li><a href="/records/'.urlencode($this->request->getParam('ActiveRecordType')).'/'.($this->start - $this->limit).'/'.$this->limit.'">&lt;&lt;-Previous</a></li>';
710
            }
711
        } elseif ($this->recordCount > $this->limit) {
712
            $body .= '<li class="disabled"><a href="#">&lt;&lt;-Previous</a></li>';
713
        }
714
715
        // render the page index links
716
        if ($this->recordCount > $this->limit) {
717
            $page = 1;
718
719
            for ($i = 0; $i < $this->recordCount; $i += $this->limit) {
720
                if ($i != $this->start) {
721
                    // handle secure URLs
722
                    if ($this->request->getParam('token', null) != null) {
723
                        $body .= '<li><a href="'.FrontController::generateSecureURL('act=Alpha\Controller\ActiveRecordController&ActiveRecordType='.$this->request->getParam('ActiveRecordType').'&start='.$i.'&limit='.$this->limit).'">'.$page.'</a></li>';
724
                    } else {
725
                        $body .= '<li><a href="/records/'.urlencode($this->request->getParam('ActiveRecordType')).'/'.$i.'/'.$this->limit.'">'.$page.'</a></li>';
726
                    }
727
                } elseif ($this->recordCount > $this->limit) { // render an anchor for the current page
728
                    $body .= '<li class="active"><a href="#">'.$page.'</a></li>';
729
                }
730
731
                ++$page;
732
            }
733
        }
734
735
        // render "Next" link
736
        if ($this->recordCount > $last) {
737
            // handle secure URLs
738 View Code Duplication
            if ($this->request->getParam('token', null) != null) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
739
                $body .= '<li><a href="'.FrontController::generateSecureURL('act=Alpha\Controller\ActiveRecordController&ActiveRecordType='.$this->request->getParam('ActiveRecordType').'&start='.($this->start + $this->limit).'&limit='.$this->limit).'">Next-&gt;&gt;</a></li>';
740
            } else {
741
                $body .= '<li><a href="/records/'.urlencode($this->request->getParam('ActiveRecordType')).'/'.($this->start + $this->limit.'/'.$this->limit).
742
                    '">Next-&gt;&gt;</a></li>';
743
            }
744
        } elseif ($this->recordCount > $this->limit) {
745
            $body .= '<li class="disabled"><a href="#">Next-&gt;&gt;</a></li>';
746
        }
747
748
        $body .= '</ul>';
749
750
        return $body;
751
    }
752
}
753