Completed
Push — 2.0.0 ( 65df5c...50869e )
by John
05:51
created

ArticleController::renderComments()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 34
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 34
rs 8.439
cc 6
eloc 20
nc 4
nop 0
1
<?php
2
3
namespace Alpha\Controller;
4
5
use Alpha\Util\Logging\Logger;
6
use Alpha\Util\Logging\KPI;
7
use Alpha\Util\Config\ConfigProvider;
8
use Alpha\Util\Security\SecurityUtils;
9
use Alpha\Util\Extension\TCPDFFacade;
10
use Alpha\Util\Http\Request;
11
use Alpha\Util\Http\Response;
12
use Alpha\Util\Http\Session\SessionProviderFactory;
13
use Alpha\Util\File\FileUtils;
14
use Alpha\Model\Article;
15
use Alpha\Model\ArticleComment;
16
use Alpha\View\View;
17
use Alpha\View\ViewState;
18
use Alpha\View\Widget\Button;
19
use Alpha\Exception\SecurityException;
20
use Alpha\Exception\AlphaException;
21
use Alpha\Exception\RecordNotFoundException;
22
use Alpha\Exception\IllegalArguementException;
23
use Alpha\Exception\ResourceNotFoundException;
24
use Alpha\Exception\FileNotFoundException;
25
use Alpha\Model\ActiveRecord;
26
use Alpha\Controller\Front\FrontController;
27
28
/**
29
 * Controller used handle Article objects.
30
 *
31
 * @since 1.0
32
 *
33
 * @author John Collins <[email protected]>
34
 * @license http://www.opensource.org/licenses/bsd-license.php The BSD License
35
 * @copyright Copyright (c) 2015, John Collins (founder of Alpha Framework).
36
 * All rights reserved.
37
 *
38
 * <pre>
39
 * Redistribution and use in source and binary forms, with or
40
 * without modification, are permitted provided that the
41
 * following conditions are met:
42
 *
43
 * * Redistributions of source code must retain the above
44
 *   copyright notice, this list of conditions and the
45
 *   following disclaimer.
46
 * * Redistributions in binary form must reproduce the above
47
 *   copyright notice, this list of conditions and the
48
 *   following disclaimer in the documentation and/or other
49
 *   materials provided with the distribution.
50
 * * Neither the name of the Alpha Framework nor the names
51
 *   of its contributors may be used to endorse or promote
52
 *   products derived from this software without specific
53
 *   prior written permission.
54
 *
55
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
56
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
57
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
58
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
59
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
60
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
61
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
62
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
63
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
64
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
65
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
66
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
67
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
68
 * </pre>
69
 */
70
class ArticleController extends ActiveRecordController implements ControllerInterface
71
{
72
    /**
73
     * Trace logger.
74
     *
75
     * @var Alpha\Util\Logging\Logger
76
     *
77
     * @since 1.0
78
     */
79
    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...
80
81
    /**
82
     * constructor to set up the object.
83
     *
84
     * @since 1.0
85
     */
86 View Code Duplication
    public function __construct()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
87
    {
88
        self::$logger = new Logger('ArticleController');
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Alpha\Util\Logging\...er('ArticleController') of type object<Alpha\Util\Logging\Logger> is incompatible with the declared type object<Alpha\Controller\...ha\Util\Logging\Logger> of property $logger.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
89
        self::$logger->debug('>>__construct()');
90
91
        // ensure that the super class constructor is called, indicating the rights group
92
        parent::__construct('Public');
93
94
        self::$logger->debug('<<__construct');
95
    }
96
97
    /**
98
     * Handle GET requests.
99
     *
100
     * @param Alpha\Util\Http\Request
101
     *
102
     * @return Alpha\Util\Http\Response
103
     *
104
     * @throws Alpha\Exception\ResourceNotFoundException
105
     *
106
     * @since 1.0
107
     */
108
    public function doGET($request)
109
    {
110
        self::$logger->debug('>>doGET($request=['.var_export($request, true).'])');
111
112
        $config = ConfigProvider::getInstance();
113
114
        $params = $request->getParams();
115
116
        $body = '';
117
118
        // handle requests for PDFs
119
        if (isset($params['title']) && (isset($params['pdf']) || $request->getHeader('Accept') == 'application/pdf')) {
120
            try {
121
                $title = str_replace($config->get('cms.url.title.separator'), ' ', $params['title']);
122
123
                $record = new Article();
124
                $record->loadByAttribute('title', $title);
125
                $this->record = $record;
0 ignored issues
show
Documentation Bug introduced by
It seems like $record of type object<Alpha\Model\Article> is incompatible with the declared type object<Alpha\Controller\Alpha\Model\ActiveRecord> of property $record.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
126
127
                ActiveRecord::disconnect();
128
129
                $pdf = new TCPDFFacade($record);
0 ignored issues
show
Documentation introduced by
$record is of type object<Alpha\Model\Article>, but the function expects a object<Alpha\Util\Extens...pha\Model\ActiveRecord>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
130
                $pdfData = $pdf->getPDFData();
131
                $pdfDownloadName = str_replace(' ', '-', $record->get('title').'.pdf');
132
133
                $headers = array(
134
                    'Pragma' => 'public',
135
                    'Expires' => 0,
136
                    'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0',
137
                    'Content-Transfer-Encoding' => 'binary',
138
                    'Content-Type' => 'application/pdf',
139
                    'Content-Length' => strlen($pdfData),
140
                    'Content-Disposition' => 'attachment; filename="'.$pdfDownloadName.'";',
141
                );
142
143
                return new Response(200, $pdfData, $headers);
144
            } catch (IllegalArguementException $e) {
145
                self::$logger->error($e->getMessage());
146
                throw new ResourceNotFoundException($e->getMessage());
147
            } catch (RecordNotFoundException $e) {
148
                self::$logger->error($e->getMessage());
149
                throw new ResourceNotFoundException($e->getMessage());
150
            }
151
        }
152
153
        // view edit article requests
154
        if ((isset($params['view']) && $params['view'] == 'edit') && (isset($params['title']) || isset($params['ActiveRecordOID']))) {
155
            $record = new Article();
156
157
            try {
158
                if (isset($params['title'])) {
159
                    $title = str_replace($config->get('cms.url.title.separator'), ' ', $params['title']);
160
                    $record->loadByAttribute('title', $title);
161
                } else {
162
                    $record->load($params['ActiveRecordOID']);
163
                }
164
            } catch (RecordNotFoundException $e) {
165
                self::$logger->warn($e->getMessage());
166
                $body .= View::renderErrorPage(404, 'Failed to find the requested article!');
167
168
                return new Response(404, $body, array('Content-Type' => 'text/html'));
169
            }
170
171
            ActiveRecord::disconnect();
172
173
            $this->record = $record;
174
            $view = View::getInstance($record);
175
176
            // set up the title and meta details
177
            $this->setTitle($record->get('title').' (editing)');
178
            $this->setDescription('Page to edit '.$record->get('title').'.');
179
            $this->setKeywords('edit,article');
180
181
            $body .= View::displayPageHead($this);
0 ignored issues
show
Documentation introduced by
$this is of type this<Alpha\Controller\ArticleController>, but the function expects a object<Alpha\View\Alpha\Controller\Controller>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
182
183
            $message = $this->getStatusMessage();
184
            if (!empty($message)) {
185
                $body .= $message;
186
            }
187
188
            $body .= $view->editView(array('URI' => $request->getURI()));
189
            $body .= View::renderDeleteForm($request->getURI());
190
191
            $body .= View::displayPageFoot($this);
0 ignored issues
show
Documentation introduced by
$this is of type this<Alpha\Controller\ArticleController>, but the function expects a object<Alpha\View\Alpha\Aonctoller\Controller>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
192
            self::$logger->debug('<<doGET');
193
194
            return new Response(200, $body, array('Content-Type' => 'text/html'));
195
        }
196
197
        // handle requests for viewing articles
198
        if (isset($params['title']) || isset($params['ActiveRecordOID'])) {
199
            $KDP = new KPI('viewarticle');
200
            $record = new Article();
201
202
            try {
203 View Code Duplication
                if (isset($params['title'])) {
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...
204
                    $title = str_replace($config->get('cms.url.title.separator'), ' ', $params['title']);
205
206
                    $record->loadByAttribute('title', $title, false, array('OID', 'version_num', 'created_ts', 'updated_ts', 'title', 'author', 'published', 'content', 'headerContent'));
207
                } else {
208
                    $record->load($params['ActiveRecordOID']);
209
                }
210
211
                if (!$record->get('published')) {
212
                    throw new RecordNotFoundException('Attempted to load an article which is not published yet');
213
                }
214
215
                $record->set('tags', $record->getOID());
216
            } catch (IllegalArguementException $e) {
217
                self::$logger->warn($e->getMessage());
218
                throw new ResourceNotFoundException('The file that you have requested cannot be found!');
219
            } catch (RecordNotFoundException $e) {
220
                self::$logger->warn($e->getMessage());
221
                throw new ResourceNotFoundException('The article that you have requested cannot be found!');
222
            }
223
224
            $this->record = $record;
225
            $this->setTitle($record->get('title'));
226
            $this->setDescription($record->get('description'));
227
228
            $BOView = View::getInstance($record);
229
230
            $body .= View::displayPageHead($this);
0 ignored issues
show
Documentation introduced by
$this is of type this<Alpha\Controller\ArticleController>, but the function expects a object<Alpha\View\Alpha\Controller\Controller>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
231
232
            $message = $this->getStatusMessage();
233
            if (!empty($message)) {
234
                $body .= $message;
235
            }
236
237
            $body .= $BOView->markdownView();
238
239
            $body .= View::displayPageFoot($this);
0 ignored issues
show
Documentation introduced by
$this is of type this<Alpha\Controller\ArticleController>, but the function expects a object<Alpha\View\Alpha\Aonctoller\Controller>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
240
241
            $KDP->log();
242
243
            return new Response(200, $body, array('Content-Type' => 'text/html'));
244
        }
245
246
        // handle requests to view an article stored in a file
247
        if (isset($params['file'])) {
248
            try {
249
                $record = new Article();
250
251
                // just checking to see if the file path is absolute or not
252
                if (mb_substr($params['file'], 0, 1) == '/') {
253
                    $record->loadContentFromFile($params['file']);
254
                } else {
255
                    $record->loadContentFromFile($config->get('app.root').'docs/'.$params['file']);
256
                }
257
            } catch (IllegalArguementException $e) {
258
                self::$logger->error($e->getMessage());
259
                throw new ResourceNotFoundException($e->getMessage());
260
            } catch (FileNotFoundException $e) {
261
                self::$logger->warn($e->getMessage().' File path is ['.$params['file'].']');
262
                throw new ResourceNotFoundException('Failed to load the requested article from the file system!');
263
            }
264
265
            $this->record = $record;
266
            $this->setTitle($record->get('title'));
267
268
            $BOView = View::getInstance($record);
269
270
            $body .= View::displayPageHead($this, false);
0 ignored issues
show
Documentation introduced by
$this is of type this<Alpha\Controller\ArticleController>, but the function expects a object<Alpha\View\Alpha\Controller\Controller>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Unused Code introduced by
The call to View::displayPageHead() has too many arguments starting with false.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
271
272
            $body .= $BOView->markdownView();
273
274
            $body .= View::displayPageFoot($this);
0 ignored issues
show
Documentation introduced by
$this is of type this<Alpha\Controller\ArticleController>, but the function expects a object<Alpha\View\Alpha\Aonctoller\Controller>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
275
276
            return new Response(200, $body, array('Content-Type' => 'text/html'));
277
        }
278
279
        // handle requests to view a list of articles
280
        if (isset($params['start'])) {
281
            return parent::doGET($request);
282
        }
283
284
        // create a new article requests
285
        $record = new Article();
286
        $view = View::getInstance($record);
287
288
        // set up the title and meta details
289
        $this->setTitle('Creating article');
290
        $this->setDescription('Page to create a new article.');
291
        $this->setKeywords('create,article');
292
293
        $body .= View::displayPageHead($this);
0 ignored issues
show
Documentation introduced by
$this is of type this<Alpha\Controller\ArticleController>, but the function expects a object<Alpha\View\Alpha\Controller\Controller>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
294
295
        $message = $this->getStatusMessage();
296
        if (!empty($message)) {
297
            $body .= $message;
298
        }
299
300
        $fields = array('formAction' => $this->request->getURI());
301
        $body .= $view->createView($fields);
302
303
        $body .= View::displayPageFoot($this);
0 ignored issues
show
Documentation introduced by
$this is of type this<Alpha\Controller\ArticleController>, but the function expects a object<Alpha\View\Alpha\Aonctoller\Controller>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
304
        self::$logger->debug('<<doGET');
305
306
        return new Response(200, $body, array('Content-Type' => 'text/html'));
307
    }
308
309
    /**
310
     * Method to handle PUT requests.
311
     *
312
     * @param Alpha\Util\Http\Request
313
     *
314
     * @return Alpha\Util\Http\Response
315
     *
316
     * @since 1.0
317
     */
318
    public function doPUT($request)
319
    {
320
        self::$logger->debug('>>doPUT($request=['.var_export($request, true).'])');
321
322
        $config = ConfigProvider::getInstance();
323
324
        $params = $request->getParams();
325
326
        try {
327
            // check the hidden security fields before accepting the form POST data
328
            if (!$this->checkSecurityFields()) {
329
                throw new SecurityException('This page cannot accept post data from remote servers!');
330
                self::$logger->debug('<<doPUT');
0 ignored issues
show
Unused Code introduced by
self::$logger->debug('<<doPUT'); does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
331
            }
332
333
            if (isset($params['markdownTextBoxRows']) && $params['markdownTextBoxRows'] != '') {
334
                $viewState = ViewState::getInstance();
335
                $viewState->set('markdownTextBoxRows', $params['markdownTextBoxRows']);
336
            }
337
338
            if (isset($params['title']) || isset($params['ActiveRecordOID'])) {
339
                $record = new Article();
340
341 View Code Duplication
                if (isset($params['title'])) {
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...
342
                    $title = str_replace($config->get('cms.url.title.separator'), ' ', $params['title']);
343
344
                    $record->loadByAttribute('title', $title, false, array('OID', 'version_num', 'created_ts', 'updated_ts', 'title', 'author', 'published', 'content', 'headerContent'));
345
                } else {
346
                    $record->load($params['ActiveRecordOID']);
347
                }
348
349
                // uploading an article attachment
350
                if (isset($params['uploadBut'])) {
351
                    $source = $request->getFile('userfile')['tmp_name'];
352
                    $dest = $record->getAttachmentsLocation().'/'.$request->getFile('userfile')['name'];
353
354
                    // upload the file to the attachments directory
355
                    FileUtils::copy($source, $dest);
356
357
                    if (!file_exists($dest)) {
358
                        throw new AlphaException('Could not move the uploaded file ['.$request->getFile('userfile')['name'].']');
359
                    }
360
361
                    // set read/write permissions on the file
362
                    $success = chmod($dest, 0666);
363
364
                    if (!$success) {
365
                        throw new AlphaException('Unable to set read/write permissions on the uploaded file ['.$dest.'].');
366
                    }
367
368
                    if ($success) {
369
                        self::$logger->action('File '.$source.' uploaded to '.$dest);
370
                        $this->setStatusMessage(View::displayUpdateMessage('File '.$source.' uploaded to '.$dest));
371
                    }
372
                } elseif (isset($params['deletefile']) && $params['deletefile'] != '') {
373
                    $success = unlink($record->getAttachmentsLocation().'/'.$params['deletefile']);
374
375
                    if (!$success) {
376
                        throw new AlphaException('Could not delete the file ['.$params['deletefile'].']');
377
                    }
378
379
                    if ($success) {
380
                        self::$logger->action('File '.$record->getAttachmentsLocation().'/'.$params['deletefile'].' deleted');
381
                        $this->setStatusMessage(View::displayUpdateMessage('File '.$record->getAttachmentsLocation().'/'.$params['deletefile'].' deleted'));
382
                    }
383
                } else {
384
                    self::$logger->debug('<<doPUT');
385
386
                    return parent::doPUT($request);
387
                }
388
            } else {
389
                throw new IllegalArguementException('No valid article ID provided!');
390
            }
391
        } catch (SecurityException $e) {
392
            $this->setStatusMessage(View::displayErrorMessage($e->getMessage()));
393
            self::$logger->warn($e->getMessage());
394
        } catch (IllegalArguementException $e) {
395
            $this->setStatusMessage(View::displayErrorMessage($e->getMessage()));
396
            self::$logger->error($e->getMessage());
397
        } catch (RecordNotFoundException $e) {
398
            self::$logger->warn($e->getMessage());
399
            $this->setStatusMessage(View::displayErrorMessage('Failed to load the requested article from the database!'));
400
        } catch (AlphaException $e) {
401
            $this->setStatusMessage(View::displayErrorMessage($e->getMessage()));
402
            self::$logger->error($e->getMessage());
403
        }
404
405
        $response = new Response(301);
406
407
        if ($this->getNextJob() != '') {
408
            $response->redirect($this->getNextJob());
409
        } else {
410
            if ($this->request->isSecureURI()) {
411
                $response->redirect(FrontController::generateSecureURL('act=Alpha\\Controller\\ActiveRecordController&ActiveRecordType=Alpha\Model\Article&ActiveRecordOID='.$record->getOID().'&view=edit'));
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...
412
            } else {
413
                $title = str_replace(' ', $config->get('cms.url.title.separator'), $record->get('title'));
414
                $response->redirect($config->get('app.url').'/a/'.$title.'/edit');
415
            }
416
        }
417
418
        self::$logger->debug('<<doPUT');
419
420
        return $response;
421
    }
422
423
    /**
424
     * Method to handle DELETE requests.
425
     *
426
     * @param Alpha\Util\Http\Request
427
     *
428
     * @return Alpha\Util\Http\Response
429
     *
430
     * @since 2.0
431
     */
432
    public function doDELETE($request)
433
    {
434
        self::$logger->debug('>>doDELETE($request=['.var_export($request, true).'])');
435
436
        $this->setUnitOfWork(array());
437
438
        self::$logger->debug('<<doDELETE');
439
440
        return parent::doDELETE($request);
441
    }
442
443
    /**
444
     * Renders custom HTML header content.
445
     *
446
     * @return string
447
     *
448
     * @since 1.0
449
     */
450
    public function during_displayPageHead_callback()
451
    {
452
        $config = ConfigProvider::getInstance();
453
454
        $params = $this->request->getParams();
455
456
        $html = '';
457
458
        if ($config->get('cms.highlight.provider.name') == 'Alpha\Util\Code\Highlight\HighlightProviderLuminous') {
459
            $html .= '<link rel="StyleSheet" type="text/css" href="'.$config->get('app.url').'/css/luminous.css">';
460
            $html .= '<link rel="StyleSheet" type="text/css" href="'.$config->get('app.url').'/css/luminous_light.css">';
461
        }
462
463
        if ((isset($params['view']) && $params['view'] == 'edit') || (isset($params['ActiveRecordType']) && !isset($params['ActiveRecordOID']))) {
464
465
            $fieldid = ($config->get('security.encrypt.http.fieldnames') ? 'text_field_'.base64_encode(SecurityUtils::encrypt('content')).'_0' : 'text_field_content_0');
466
467
            $html .= '
468
                <script type="text/javascript">
469
                $(document).ready(function() {
470
                    $(\'[id="'.$fieldid.'"]\').pagedownBootstrap({
471
                        \'sanatize\': false
472
                    });
473
                });
474
                </script>';
475
476
        } elseif (isset($params['view']) && $params['view'] == 'print') {
477
            $html .= '<link rel="StyleSheet" type="text/css" href="'.$config->get('app.url').'/css/print.css">';
478
        }
479
480
        return $html;
481
    }
482
483
    /**
484
     * Callback that inserts the CMS level header.
485
     *
486
     * @return string
487
     *
488
     * @since 1.0
489
     */
490
    public function insert_CMSDisplayStandardHeader_callback()
491
    {
492
        if ($this->request->getParam('token') != null) {
493
            return '';
494
        }
495
496
        if (!$this->record instanceof Article) {
497
            return '';
498
        }
499
500
        $config = ConfigProvider::getInstance();
501
502
        $html = '';
503
504
        if ($config->get('cms.display.standard.header')) {
505
            $html .= '<p><a href="'.$config->get('app.url').'">'.$config->get('app.title').'</a> &nbsp; &nbsp;';
506
            $html .= 'Date Added: <em>'.$this->record->getCreateTS()->getDate().'</em> &nbsp; &nbsp;';
507
            $html .= 'Last Updated: <em>'.$this->record->getUpdateTS()->getDate().'</em> &nbsp; &nbsp;';
508
            $html .= 'Revision: <em>'.$this->record->getVersion().'</em></p>';
509
        }
510
511
        $html .= $config->get('cms.header');
512
513
        return $html;
514
    }
515
516
    /**
517
     * Callback used to render footer content, including comments, votes and print/PDF buttons when
518
     * enabled to do so.
519
     *
520
     * @return string
521
     *
522
     * @since 1.0
523
     */
524
    public function before_displayPageFoot_callback()
525
    {
526
        $config = ConfigProvider::getInstance();
527
        $sessionProvider = $config->get('session.provider.name');
528
        $session = SessionProviderFactory::getInstance($sessionProvider);
529
530
        $html = '';
531
        $params = $this->request->getParams();
532
533
        // this will ensure that direct requests to ActiveRecordController will be re-directed here.
534
        if (isset($this->record) && !$this->record->isTransient()) {
535
            $this->setName($config->get('app.url').$this->request->getURI());
536
            $this->setUnitOfWork(array($config->get('app.url').$this->request->getURI(), $config->get('app.url').$this->request->getURI()));
537
        } else {
538
            $this->setUnitOfWork(array());
539
        }
540
541
        if ($this->record != null) {
542
            if (isset($params['view']) && $params['view'] == 'detailed') {
543
                if ($config->get('cms.display.comments')) {
544
                    $html .= $this->renderComments();
545
                }
546
547
                if ($config->get('cms.display.tags')) {
548
                    $tags = $this->record->getPropObject('tags')->getRelatedObjects();
549
550
                    if (count($tags) > 0) {
551
                        $html .= '<p>Tags:';
552
553 View Code Duplication
                        foreach ($tags as $tag) {
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...
554
                            $html .= ' <a href="'.$config->get('app.url').'/search/'.$tag->get('content').'">'.$tag->get('content').'</a>';
555
                        }
556
                        $html .= '</p>';
557
                    }
558
                }
559
560
                if ($config->get('cms.display.votes')) {
561
                    $rating = $this->record->getArticleScore();
562
                    $votes = $this->record->getArticleVotes();
563
                    $html .= '<p>Average Article User Rating: <strong>'.$rating.'</strong> out of 10 (based on <strong>'.count($votes).'</strong> votes)</p>';
564
                }
565
566
                if (!$this->record->checkUserVoted() && $config->get('cms.voting.allowed')) {
567
                    $URL = FrontController::generateSecureURL('act=Alpha\Controller\ActiveRecordController&ActiveRecordType=Alpha\Model\ArticleVote');
568
                    $html .= '<form action="'.$URL.'" method="post" accept-charset="UTF-8">';
569
                    $fieldname = ($config->get('security.encrypt.http.fieldnames') ? base64_encode(SecurityUtils::encrypt('score')) : 'score');
570
                    $html .= '<p>Please rate this article from 1-10 (10 being the best):'.
571
                            '<select name="'.$fieldname.'">'.
572
                            '<option value="1">1'.
573
                            '<option value="2">2'.
574
                            '<option value="3">3'.
575
                            '<option value="4">4'.
576
                            '<option value="5">5'.
577
                            '<option value="6">6'.
578
                            '<option value="7">7'.
579
                            '<option value="8">8'.
580
                            '<option value="9">9'.
581
                            '<option value="10">10'.
582
                            '</select></p>&nbsp;&nbsp;';
583
584
                    $fieldname = ($config->get('security.encrypt.http.fieldnames') ? base64_encode(SecurityUtils::encrypt('articleOID')) : 'articleOID');
585
                    $html .= '<input type="hidden" name="'.$fieldname.'" value="'.$this->record->getOID().'"/>';
586
587
                    $fieldname = ($config->get('security.encrypt.http.fieldnames') ? base64_encode(SecurityUtils::encrypt('personOID')) : 'personOID');
588
                    $html .= '<input type="hidden" name="'.$fieldname.'" value="'.$session->get('currentUser')->getID().'"/>';
589
590
                    $fieldname = ($config->get('security.encrypt.http.fieldnames') ? base64_encode(SecurityUtils::encrypt('statusMessage')) : 'statusMessage');
591
                    $html .= '<input type="hidden" name="'.$fieldname.'" value="Thank you for rating this article!"/>';
592
593
                    $temp = new Button('submit', 'Vote!', 'voteBut');
594
                    $html .= $temp->render();
595
596
                    $html .= View::renderSecurityFields();
597
                    $html .= '<form>';
598
                }
599
600
                ActiveRecord::disconnect();
601
602
                if ($config->get('cms.allow.print.versions')) {
603
                    $html .= '&nbsp;&nbsp;';
604
                    $temp = new Button("window.open('".$this->record->get('printURL')."')", 'Open Printer Version', 'printBut');
605
                    $html .= $temp->render();
606
                }
607
608
                $html .= '&nbsp;&nbsp;';
609 View Code Duplication
                if ($config->get('cms.allow.pdf.versions')) {
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...
610
                    $html .= '&nbsp;&nbsp;';
611
                    $temp = new Button("document.location = '".FrontController::generateSecureURL("act=Alpha\Controller\ArticleController&mode=pdf&title=".$this->record->get('title'))."';", 'Open PDF Version', 'pdfBut');
612
                    $html .= $temp->render();
613
                }
614
615
                // render edit button for admins only
616 View Code Duplication
                if ($session->get('currentUser') instanceof Alpha\Model\Person && $session->get('currentUser')->inGroup('Admin')) {
0 ignored issues
show
Bug introduced by
The class Alpha\Controller\Alpha\Model\Person does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
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...
617
                    $html .= '&nbsp;&nbsp;';
618
                    $button = new Button("document.location = '".FrontController::generateSecureURL('act=Alpha\Controller\ArticleController&mode=edit&ActiveRecordOID='.$this->record->getID())."'", 'Edit', 'editBut');
619
                    $html .= $button->render();
620
                }
621
            }
622
623
            if ($config->get('cms.display.standard.footer')) {
624
                $html .= '<p>Article URL: <a href="'.$this->record->get('URL').'">'.$this->record->get('URL').'</a><br>';
625
                $html .= 'Title: '.$this->record->get('title').'<br>';
626
                $html .= 'Author: '.$this->record->get('author').'</p>';
627
            }
628
        }
629
630
        $html .= $config->get('cms.footer');
631
632
        return $html;
633
    }
634
635
    /**
636
     * Method for displaying the user comments for the article.
637
     *
638
     * @return string
639
     *
640
     * @since 1.0
641
     */
642
    private function renderComments()
643
    {
644
        $config = ConfigProvider::getInstance();
645
        $sessionProvider = $config->get('session.provider.name');
646
        $session = SessionProviderFactory::getInstance($sessionProvider);
647
648
        $html = '';
649
650
        $comments = $this->record->getArticleComments();
651
        $commentsCount = count($comments);
652
653
        $URL = FrontController::generateSecureURL('act=Alpha\Controller\ActiveRecordController&ActiveRecordType=Alpha\Model\ArticleComment');
654
655
        $fields = array('formAction' => $URL);
656
657
        if ($config->get('cms.display.comments') && $commentsCount > 0) {
658
            $html .= '<h2>There are ['.$commentsCount.'] user comments for this article</h2>';
659
660
            for ($i = 0; $i < $commentsCount; ++$i) {
661
                $view = View::getInstance($comments[$i]);
662
                $html .= $view->markdownView($fields);
663
            }
664
        }
665
666
        if ($session->get('currentUser') != null && $config->get('cms.comments.allowed')) {
667
            $comment = new ArticleComment();
668
            $comment->set('articleOID', $this->record->getID());
669
670
            $view = View::getInstance($comment);
671
            $html .= $view->createView($fields);
672
        }
673
674
        return $html;
675
    }
676
}
677