GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Push — integration ( 45cc9f...98bc42 )
by Brendan
05:52
created

contentBlueprintsPages::__viewEdit()   F

Complexity

Conditions 42
Paths > 20000

Size

Total Lines 303
Code Lines 172

Duplication

Lines 30
Ratio 9.9 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 42
eloc 172
c 2
b 0
f 0
nc 429496.7295
nop 0
dl 30
loc 303
rs 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * @package content
5
 */
6
7
/**
8
 * Developers can create new Frontend pages from this class. It provides
9
 * an index view of all the pages in this Symphony install as well as the
10
 * forms for the creation/editing of a Page
11
 */
12
13
class contentBlueprintsPages extends AdministrationPage
14
{
15
    public $_errors = array();
16
    protected $_hilights = array();
17
18
    /**
19
     * The Pages page has /action/id/flag/ context.
20
     * eg. /edit/1/saved/
21
     *
22
     * @param array $context
23
     * @param array $parts
24
     * @return array
25
     */
26 View Code Duplication
    public function parseContext(array &$context, array $parts)
27
    {
28
        // Order is important!
29
        $params = array_fill_keys(array('action', 'id', 'flag'), null);
30
31
        if (isset($parts[2])) {
32
            $extras = preg_split('/\//', $parts[2], -1, PREG_SPLIT_NO_EMPTY);
33
            list($params['action'], $params['id'], $params['flag']) = $extras;
34
            $params['id'] = (int)$params['id'];
35
        }
36
37
        $context = array_filter($params);
38
    }
39
40
    public function insertBreadcrumbsUsingPageIdentifier($page_id, $preserve_last = true)
41
    {
42
        if ($page_id === 0) {
43
            return $this->insertBreadcrumbs(
44
                array(Widget::Anchor(__('Pages'), SYMPHONY_URL . '/blueprints/pages/'))
45
            );
46
        }
47
48
        $pages = PageManager::resolvePage($page_id, 'handle');
49
50
        foreach ($pages as &$page) {
0 ignored issues
show
Bug introduced by
The expression $pages of type array|boolean is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
51
            // If we are viewing the Page Editor, the Breadcrumbs should link
52
            // to the parent's Page Editor.
53
            if ($this->_context['action'] === 'edit') {
54
                $page = Widget::Anchor(
55
                    PageManager::fetchTitleFromHandle($page),
56
                    SYMPHONY_URL . '/blueprints/pages/edit/' . PageManager::fetchIDFromHandle($page) . '/'
57
                );
58
59
                // If the pages index is nested, the Breadcrumb should link to the
60
                // Pages Index filtered by parent
61
            } elseif (Symphony::Configuration()->get('pages_table_nest_children', 'symphony') === 'yes') {
62
                $page = Widget::Anchor(
63
                    PageManager::fetchTitleFromHandle($page),
64
                    SYMPHONY_URL . '/blueprints/pages/?parent=' . PageManager::fetchIDFromHandle($page)
65
                );
66
67
                // If there is no nesting on the Pages Index, the breadcrumb is
68
                // not a link, just plain text
69
            } else {
70
                $page = new XMLElement('span', PageManager::fetchTitleFromHandle($page));
71
            }
72
        }
73
74
        if (!$preserve_last) {
75
            array_pop($pages);
76
        }
77
78
        $this->insertBreadcrumbs(array_merge(
79
            array(Widget::Anchor(__('Pages'), SYMPHONY_URL . '/blueprints/pages/')),
80
            $pages
81
        ));
82
    }
83
84
    public function __viewIndex()
85
    {
86
        $this->setPageType('table');
87
        $this->setTitle(__('%1$s &ndash; %2$s', array(__('Pages'), __('Symphony'))));
88
89
        $nesting = Symphony::Configuration()->get('pages_table_nest_children', 'symphony') === 'yes';
90
91
        if ($nesting && isset($_GET['parent']) && is_numeric($_GET['parent'])) {
92
            $parent = PageManager::fetchPageByID((int)$_GET['parent'], array('title', 'id'));
93
        }
94
95
        $this->appendSubheading(isset($parent) ? $parent['title'] : __('Pages'), Widget::Anchor(
96
            __('Create New'), Administration::instance()->getCurrentPageURL() . 'new/' . ($nesting && isset($parent) ? "?parent={$parent['id']}" : null),
97
            __('Create a new page'), 'create button', null, array('accesskey' => 'c')
98
        ));
99
100
        if (isset($parent)) {
101
            $this->insertBreadcrumbsUsingPageIdentifier($parent['id'], false);
102
        }
103
104
        $aTableHead = array(
105
            array(__('Name'), 'col'),
106
            array(__('Template'), 'col'),
107
            array('<abbr title="' . __('Universal Resource Locator') . '">' . __('URL') . '</abbr>', 'col'),
108
            array(__('Parameters'), 'col'),
109
            array(__('Type'), 'col')
110
        );
111
        $aTableBody = array();
112
113
        if ($nesting) {
114
            $aTableHead[] = array(__('Children'), 'col');
115
            $where = array(
116
                'parent ' . (isset($parent) ? " = {$parent['id']} " : ' IS NULL ')
117
            );
118
        } else {
119
            $where = array();
120
        }
121
122
        $pages = PageManager::fetch(true, array('*'), $where);
123
124
        if (!is_array($pages) || empty($pages)) {
125
            $aTableBody = array(Widget::TableRow(array(
126
                Widget::TableData(__('None found.'), 'inactive', null, count($aTableHead))
127
            ), 'odd'));
128
        } else {
129
            foreach ($pages as $page) {
130
                $class = array();
131
132
                $page_title = ($nesting ? $page['title'] : PageManager::resolvePageTitle($page['id']));
133
                $page_url = URL . '/' . PageManager::resolvePagePath($page['id']) . '/';
134
                $page_edit_url = Administration::instance()->getCurrentPageURL() . 'edit/' . $page['id'] . '/';
135
                $page_template = PageManager::createFilePath($page['path'], $page['handle']);
136
137
                $col_title = Widget::TableData(Widget::Anchor($page_title, $page_edit_url, $page['handle']));
138
                $col_title->appendChild(Widget::Label(__('Select Page %s', array($page_title)), null, 'accessible', null, array(
139
                    'for' => 'page-' . $page['id']
140
                )));
141
                $col_title->appendChild(Widget::Input('items['.$page['id'].']', 'on', 'checkbox', array(
142
                    'id' => 'page-' . $page['id']
143
                )));
144
145
                $col_template = Widget::TableData($page_template . '.xsl');
146
147
                $col_url = Widget::TableData(Widget::Anchor($page_url, $page_url));
148
149 View Code Duplication
                if ($page['params']) {
150
                    $col_params = Widget::TableData(trim($page['params'], '/'));
151
                } else {
152
                    $col_params = Widget::TableData(__('None'), 'inactive');
153
                }
154
155 View Code Duplication
                if (!empty($page['type'])) {
156
                    $col_types = Widget::TableData(implode(', ', $page['type']));
157
                } else {
158
                    $col_types = Widget::TableData(__('None'), 'inactive');
159
                }
160
161
                if (in_array($page['id'], $this->_hilights)) {
162
                    $class[] = 'failed';
163
                }
164
165
                $columns = array($col_title, $col_template, $col_url, $col_params, $col_types);
166
167
                if ($nesting) {
168
                    if (PageManager::hasChildPages($page['id'])) {
169
                        $col_children = Widget::TableData(
170
                            Widget::Anchor(PageManager::getChildPagesCount($page['id']) . ' &rarr;',
171
                            SYMPHONY_URL . '/blueprints/pages/?parent=' . $page['id'])
172
                        );
173
                    } else {
174
                        $col_children = Widget::TableData(__('None'), 'inactive');
175
                    }
176
177
                    $columns[] = $col_children;
178
                }
179
180
                $aTableBody[] = Widget::TableRow(
181
                    $columns,
182
                    implode(' ', $class)
183
                );
184
            }
185
        }
186
187
        $table = Widget::Table(
188
            Widget::TableHead($aTableHead), null,
189
            Widget::TableBody($aTableBody), 'orderable selectable',
190
            null, array('role' => 'directory', 'aria-labelledby' => 'symphony-subheading', 'data-interactive' => 'data-interactive')
191
        );
192
193
        $this->Form->appendChild($table);
194
195
        $version = new XMLElement('p', 'Symphony ' . Symphony::Configuration()->get('version', 'symphony'), array(
196
            'id' => 'version'
197
        ));
198
        $this->Form->appendChild($version);
199
200
        $tableActions = new XMLElement('div');
201
        $tableActions->setAttribute('class', 'actions');
202
203
        $options = array(
204
            array(null, false, __('With Selected...')),
205
            array('delete', false, __('Delete'), 'confirm', null, array(
206
                'data-message' => __('Are you sure you want to delete the selected pages?')
207
            ))
208
        );
209
210
        /**
211
         * Allows an extension to modify the existing options for this page's
212
         * With Selected menu. If the `$options` parameter is an empty array,
213
         * the 'With Selected' menu will not be rendered.
214
         *
215
         * @delegate AddCustomActions
216
         * @since Symphony 2.3.2
217
         * @param string $context
218
         * '/blueprints/pages/'
219
         * @param array $options
220
         *  An array of arrays, where each child array represents an option
221
         *  in the With Selected menu. Options should follow the same format
222
         *  expected by `Widget::__SelectBuildOption`. Passed by reference.
223
         */
224
        Symphony::ExtensionManager()->notifyMembers('AddCustomActions', '/blueprints/pages/', array(
225
            'options' => &$options
226
        ));
227
228
        if (!empty($options)) {
229
            $tableActions->appendChild(Widget::Apply($options));
230
            $this->Form->appendChild($tableActions);
231
        }
232
    }
233
234
    public function __viewNew()
235
    {
236
        $this->__viewEdit();
237
    }
238
239
    public function __viewEdit()
0 ignored issues
show
Coding Style introduced by
__viewEdit uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
240
    {
241
        $this->setPageType('form');
242
        $fields = array("title"=>null, "handle"=>null, "parent"=>null, "params"=>null, "type"=>null, "data_sources"=>null);
243
        $existing = $fields;
244
245
        $nesting = (Symphony::Configuration()->get('pages_table_nest_children', 'symphony') === 'yes');
246
247
        // Verify page exists:
248
        if ($this->_context['action'] === 'edit') {
249
            if (!$page_id = (int)$this->_context['id']) {
250
                redirect(SYMPHONY_URL . '/blueprints/pages/');
251
            }
252
253
            $existing = PageManager::fetchPageByID($page_id);
254
255
            if (!$existing) {
256
                Administration::instance()->errorPageNotFound();
257
            } else {
258
                $existing['type'] = PageManager::fetchPageTypes($page_id);
259
            }
260
        }
261
262
        // Status message:
263
        if (isset($this->_context['flag'])) {
264
            $flag = $this->_context['flag'];
265
            $parent_link_suffix = $message = '';
266
            $time = Widget::Time();
267
268
            if (isset($_REQUEST['parent']) && is_numeric($_REQUEST['parent'])) {
269
                $parent_link_suffix = "?parent=" . $_REQUEST['parent'];
270
            } elseif ($nesting && isset($existing) && !is_null($existing['parent'])) {
271
                $parent_link_suffix = '?parent=' . $existing['parent'];
272
            }
273
274
            switch ($flag) {
275
                case 'saved':
276
                    $message = __('Page updated at %s.', array($time->generate()));
277
                    break;
278
                case 'created':
279
                    $message = __('Page created at %s.', array($time->generate()));
280
            }
281
282
            $this->pageAlert(
283
                $message
284
                . ' <a href="' . SYMPHONY_URL . '/blueprints/pages/new/' . $parent_link_suffix . '" accesskey="c">'
285
                . __('Create another?')
286
                . '</a> <a href="' . SYMPHONY_URL . '/blueprints/pages/" accesskey="a">'
287
                . __('View all Pages')
288
                . '</a>',
289
                Alert::SUCCESS
290
            );
291
        }
292
293
        // Find values:
294
        if (isset($_POST['fields'])) {
295
            $fields = $_POST['fields'];
296
        } elseif ($this->_context['action'] === 'edit') {
297
            $fields = $existing;
298
299
            if (!is_null($fields['type'])) {
300
                $fields['type'] = implode(', ', $fields['type']);
301
            }
302
303
            $fields['data_sources'] = preg_split('/,/i', $fields['data_sources'], -1, PREG_SPLIT_NO_EMPTY);
304
            $fields['events'] = preg_split('/,/i', $fields['events'], -1, PREG_SPLIT_NO_EMPTY);
305 View Code Duplication
        } elseif (isset($_REQUEST['parent']) && is_numeric($_REQUEST['parent'])) {
306
            $fields['parent'] = $_REQUEST['parent'];
307
        }
308
309
        $title = $fields['title'];
310
311
        if (trim($title) === '') {
312
            $title = $existing['title'];
313
        }
314
315
        $this->setTitle(__(
316
            ($title ? '%1$s &ndash; %2$s &ndash; %3$s' : '%2$s &ndash; %3$s'),
317
            array(
318
                $title,
319
                __('Pages'),
320
                __('Symphony')
321
            )
322
        ));
323
324
        $page_id = isset($page_id) ? $page_id : null;
325
326
        if (!empty($title)) {
327
            $page_url = URL . '/' . PageManager::resolvePagePath($page_id) . '/';
328
329
            $this->appendSubheading($title, array(
330
                Widget::Anchor(__('View Page'), $page_url, __('View Page on Frontend'), 'button', null, array('target' => '_blank', 'accesskey' => 'v'))
331
            ));
332
        } else {
333
            $this->appendSubheading(!empty($title) ? $title : __('Untitled'));
334
        }
335
336
        if (isset($page_id)) {
337
            $this->insertBreadcrumbsUsingPageIdentifier($page_id, false);
338
        } else {
339
            $_GET['parent'] = isset($_GET['parent']) ? $_GET['parent'] : null;
340
            $this->insertBreadcrumbsUsingPageIdentifier((int)$_GET['parent'], true);
341
        }
342
343
        // Title --------------------------------------------------------------
344
345
        $fieldset = new XMLElement('fieldset');
346
        $fieldset->setAttribute('class', 'settings');
347
        $fieldset->appendChild(new XMLElement('legend', __('Page Settings')));
348
349
        $label = Widget::Label(__('Name'));
350
        $label->appendChild(Widget::Input(
351
            'fields[title]', General::sanitize($fields['title'])
352
        ));
353
354
        if (isset($this->_errors['title'])) {
355
            $label = Widget::Error($label, $this->_errors['title']);
356
        }
357
358
        $fieldset->appendChild($label);
359
360
        // Handle -------------------------------------------------------------
361
362
        $group = new XMLElement('div');
363
        $group->setAttribute('class', 'two columns');
364
        $column = new XMLElement('div');
365
        $column->setAttribute('class', 'column');
366
367
        $label = Widget::Label(__('Handle'));
368
        $label->appendChild(Widget::Input(
369
            'fields[handle]', $fields['handle']
370
        ));
371
372
        if (isset($this->_errors['handle'])) {
373
            $label = Widget::Error($label, $this->_errors['handle']);
374
        }
375
376
        $column->appendChild($label);
377
378
        // Parent ---------------------------------------------------------
379
380
        $label = Widget::Label(__('Parent Page'));
381
382
        $where = array(
383
            sprintf('id != %d', $page_id)
384
        );
385
        $pages = PageManager::fetch(false, array('id'), $where, 'title ASC');
386
387
        $options = array(
388
            array('', false, '/')
389
        );
390
391
        if (!empty($pages)) {
392
            foreach ($pages as $page) {
393
                $options[] = array(
394
                    $page['id'], $fields['parent'] === $page['id'],
395
                    '/' . PageManager::resolvePagePath($page['id'])
396
                );
397
            }
398
399
            usort($options, array($this, '__compare_pages'));
400
        }
401
402
        $label->appendChild(Widget::Select(
403
            'fields[parent]', $options
404
        ));
405
        $column->appendChild($label);
406
        $group->appendChild($column);
407
408
        // Parameters ---------------------------------------------------------
409
410
        $column = new XMLElement('div');
411
        $column->setAttribute('class', 'column');
412
413
        $label = Widget::Label(__('Parameters'));
414
        $label->appendChild(Widget::Input(
415
            'fields[params]', $fields['params'], 'text', array('placeholder' => 'param1/param2')
416
        ));
417
        $column->appendChild($label);
418
419
        // Type -----------------------------------------------------------
420
421
        $label = Widget::Label(__('Type'));
422
        $label->appendChild(Widget::Input('fields[type]', $fields['type']));
423
424
        if (isset($this->_errors['type'])) {
425
            $label = Widget::Error($label, $this->_errors['type']);
426
        }
427
428
        $column->appendChild($label);
429
430
        $tags = new XMLElement('ul');
431
        $tags->setAttribute('class', 'tags');
432
        $tags->setAttribute('data-interactive', 'data-interactive');
433
434
        $types = PageManager::fetchAvailablePageTypes();
435
436
        foreach ($types as $type) {
437
            $tags->appendChild(new XMLElement('li', $type));
438
        }
439
440
        $column->appendChild($tags);
441
        $group->appendChild($column);
442
        $fieldset->appendChild($group);
443
        $this->Form->appendChild($fieldset);
444
445
        // Events -------------------------------------------------------------
446
447
        $fieldset = new XMLElement('fieldset');
448
        $fieldset->setAttribute('class', 'settings');
449
        $fieldset->appendChild(new XMLElement('legend', __('Page Resources')));
450
451
        $group = new XMLElement('div');
452
        $group->setAttribute('class', 'two columns');
453
454
        $label = Widget::Label(__('Events'));
455
        $label->setAttribute('class', 'column');
456
457
        $events = ResourceManager::fetch(ResourceManager::RESOURCE_TYPE_EVENT, array(), array(), 'name ASC');
458
        $options = array();
459
460 View Code Duplication
        if (is_array($events) && !empty($events)) {
461
            if (!isset($fields['events'])) {
462
                $fields['events'] = array();
463
            }
464
465
            foreach ($events as $name => $about) {
466
                $options[] = array(
467
                    $name, in_array($name, $fields['events']), $about['name']
468
                );
469
            }
470
        }
471
472
        $label->appendChild(Widget::Select('fields[events][]', $options, array('multiple' => 'multiple')));
473
        $group->appendChild($label);
474
475
        // Data Sources -------------------------------------------------------
476
477
        $label = Widget::Label(__('Data Sources'));
478
        $label->setAttribute('class', 'column');
479
480
        $datasources = ResourceManager::fetch(ResourceManager::RESOURCE_TYPE_DS, array(), array(), 'name ASC');
481
        $options = array();
482
483 View Code Duplication
        if (is_array($datasources) && !empty($datasources)) {
484
            if (!isset($fields['data_sources'])) {
485
                $fields['data_sources'] = array();
486
            }
487
488
            foreach ($datasources as $name => $about) {
489
                $options[] = array(
490
                    $name, in_array($name, $fields['data_sources']), $about['name']
491
                );
492
            }
493
        }
494
495
        $label->appendChild(Widget::Select('fields[data_sources][]', $options, array('multiple' => 'multiple')));
496
        $group->appendChild($label);
497
        $fieldset->appendChild($group);
498
        $this->Form->appendChild($fieldset);
499
500
        // Controls -----------------------------------------------------------
501
502
        /**
503
         * After all Page related Fields have been added to the DOM, just before the
504
         * actions.
505
         *
506
         * @delegate AppendPageContent
507
         * @param string $context
508
         *  '/blueprints/pages/'
509
         * @param XMLElement $form
510
         * @param array $fields
511
         * @param array $errors
512
         */
513
        Symphony::ExtensionManager()->notifyMembers(
514
            'AppendPageContent',
515
            '/blueprints/pages/',
516
            array(
517
                'form'        => &$this->Form,
518
                'fields'    => &$fields,
519
                'errors'    => $this->_errors
520
            )
521
        );
522
523
        $div = new XMLElement('div');
524
        $div->setAttribute('class', 'actions');
525
        $div->appendChild(Widget::Input(
526
            'action[save]', ($this->_context['action'] === 'edit' ? __('Save Changes') : __('Create Page')),
527
            'submit', array('accesskey' => 's')
528
        ));
529
530 View Code Duplication
        if ($this->_context['action'] === 'edit') {
531
            $button = new XMLElement('button', __('Delete'));
532
            $button->setAttributeArray(array('name' => 'action[delete]', 'class' => 'button confirm delete', 'title' => __('Delete this page'), 'accesskey' => 'd', 'data-message' => __('Are you sure you want to delete this page?')));
533
            $div->appendChild($button);
534
        }
535
536
        $this->Form->appendChild($div);
537
538
        if (isset($_REQUEST['parent']) && is_numeric($_REQUEST['parent'])) {
539
            $this->Form->appendChild(new XMLElement('input', null, array('type' => 'hidden', 'name' => 'parent', 'value' => $_REQUEST['parent'])));
540
        }
541
    }
542
543
    public function __compare_pages($a, $b)
544
    {
545
        return strnatcasecmp($a[2], $b[2]);
546
    }
547
548
    public function __actionIndex()
0 ignored issues
show
Coding Style introduced by
__actionIndex uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
549
    {
550
        $checked = (is_array($_POST['items'])) ? array_keys($_POST['items']) : null;
551
552
        if (is_array($checked) && !empty($checked)) {
553
            /**
554
             * Extensions can listen for any custom actions that were added
555
             * through `AddCustomPreferenceFieldsets` or `AddCustomActions`
556
             * delegates.
557
             *
558
             * @delegate CustomActions
559
             * @since Symphony 2.3.2
560
             * @param string $context
561
             *  '/blueprints/pages/'
562
             * @param array $checked
563
             *  An array of the selected rows. The value is usually the ID of the
564
             *  the associated object.
565
             */
566
            Symphony::ExtensionManager()->notifyMembers('CustomActions', '/blueprints/pages/', array(
567
                'checked' => $checked
568
            ));
569
570
            switch ($_POST['with-selected']) {
571
                case 'delete':
572
                    $this->__actionDelete($checked, SYMPHONY_URL . '/blueprints/pages/');
573
                    break;
574
            }
575
        }
576
    }
577
578
    public function __actionNew()
579
    {
580
        $this->__actionEdit();
581
    }
582
583
    public function __actionEdit()
0 ignored issues
show
Coding Style introduced by
__actionEdit uses the super-global variable $_POST which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

    public function __construct($host)
    {
        $this->host = $host;
    }

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
584
    {
585
        if ($this->_context['action'] !== 'new' && !$page_id = (int)$this->_context['id']) {
586
            redirect(SYMPHONY_URL . '/blueprints/pages/');
587
        }
588
589
        $parent_link_suffix = null;
590
591 View Code Duplication
        if (isset($_REQUEST['parent']) && is_numeric($_REQUEST['parent'])) {
592
            $parent_link_suffix = '?parent=' . $_REQUEST['parent'];
593
        }
594
595
        if (@array_key_exists('delete', $_POST['action'])) {
596
            $this->__actionDelete($page_id, SYMPHONY_URL  . '/blueprints/pages/' . $parent_link_suffix);
0 ignored issues
show
Bug introduced by
The variable $page_id 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...
597
        }
598
599
        if (@array_key_exists('save', $_POST['action'])) {
600
            $fields = $_POST['fields'];
601
            $this->_errors = array();
602
            $autogenerated_handle = false;
0 ignored issues
show
Unused Code introduced by
$autogenerated_handle is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
603
604 View Code Duplication
            if (!isset($fields['title']) || trim($fields['title']) === '') {
605
                $this->_errors['title'] = __('This is a required field');
606
            }
607
608
            if (trim($fields['type']) !== '' && preg_match('/(index|404|403)/i', $fields['type'])) {
609
                $types = preg_split('/\s*,\s*/', strtolower($fields['type']), -1, PREG_SPLIT_NO_EMPTY);
610
611
                if (in_array('index', $types) && PageManager::hasPageTypeBeenUsed($page_id, 'index')) {
612
                    $this->_errors['type'] = __('An index type page already exists.');
613
                } elseif (in_array('404', $types) && PageManager::hasPageTypeBeenUsed($page_id, '404')) {
614
                    $this->_errors['type'] = __('A 404 type page already exists.');
615
                } elseif (in_array('403', $types) && PageManager::hasPageTypeBeenUsed($page_id, '403')) {
616
                    $this->_errors['type'] = __('A 403 type page already exists.');
617
                }
618
            }
619
620
            if (trim($fields['handle']) === '') {
621
                $fields['handle'] = $fields['title'];
622
                $autogenerated_handle = true;
0 ignored issues
show
Unused Code introduced by
$autogenerated_handle is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
623
            }
624
625
            $fields['handle'] = PageManager::createHandle($fields['handle']);
626
627
            if (empty($fields['handle']) && !isset($this->_errors['title'])) {
628
                $this->_errors['handle'] = __('Please ensure handle contains at least one Latin-based character.');
629
            }
630
631
            /**
632
             * Just after the Symphony validation has run, allows Developers
633
             * to run custom validation logic on a Page
634
             *
635
             * @delegate PagePostValidate
636
             * @since Symphony 2.2
637
             * @param string $context
638
             * '/blueprints/pages/'
639
             * @param array $fields
640
             *  The `$_POST['fields']` array. This should be read-only and not changed
641
             *  through this delegate.
642
             * @param array $errors
643
             *  An associative array of errors, with the key matching a key in the
644
             *  `$fields` array, and the value being the string of the error. `$errors`
645
             *  is passed by reference.
646
             */
647
            Symphony::ExtensionManager()->notifyMembers('PagePostValidate', '/blueprints/pages/', array('fields' => $fields, 'errors' => &$errors));
0 ignored issues
show
Bug introduced by
The variable $errors does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
648
649
            if (empty($this->_errors)) {
650
                $autogenerated_handle = false;
651
652
                if ($fields['params']) {
653
                    $fields['params'] = trim(preg_replace('@\/{2,}@', '/', $fields['params']), '/');
654
                }
655
656
                // Clean up type list
657
                $types = preg_split('/\s*,\s*/', $fields['type'], -1, PREG_SPLIT_NO_EMPTY);
658
                $types = @array_map('trim', $types);
659
                unset($fields['type']);
660
661
                $fields = array_filter($fields);
662
663
                $fields['parent'] = ($fields['parent'] !== __('None') ? $fields['parent'] : null);
664
                $fields['data_sources'] = is_array($fields['data_sources']) ? implode(',', $fields['data_sources']) : null;
665
                $fields['events'] = is_array($fields['events']) ? implode(',', $fields['events']) : null;
666
                $fields['path'] = null;
667
668
                if ($fields['parent']) {
669
                    $fields['path'] = PageManager::resolvePagePath((integer)$fields['parent']);
670
                }
671
672
                // Check for duplicates:
673
                $current = PageManager::fetchPageByID($page_id);
674
675
                if (empty($current)) {
676
                    $fields['sortorder'] = PageManager::fetchNextSortOrder();
677
                }
678
679
                $where = array();
680
681
                if (!empty($current)) {
682
                    $where[] = "p.id != {$page_id}";
683
                }
684
685
                $where[] = "p.handle = '" . $fields['handle'] . "'";
686
                $where[] = (is_null($fields['path']))
687
                    ? "p.path IS null"
688
                    : "p.path = '" . $fields['path'] . "'";
689
                $duplicate = PageManager::fetch(false, array('*'), $where);
690
691
                // If duplicate
692
                if (!empty($duplicate)) {
693
                    if ($autogenerated_handle) {
694
                        $this->_errors['title'] = __('A page with that title already exists');
695
                    } else {
696
                        $this->_errors['handle'] = __('A page with that handle already exists');
697
                    }
698
699
                    // Create or move files:
700
                } else {
701
                    // New page?
702
                    if (empty($current)) {
703
                        $file_created = PageManager::createPageFiles(
704
                            $fields['path'],
705
                            $fields['handle']
706
                        );
707
708
                        // Existing page, potentially rename files
709
                    } else {
710
                        $file_created = PageManager::createPageFiles(
711
                            $fields['path'],
712
                            $fields['handle'],
713
                            $current['path'],
714
                            $current['handle']
715
                        );
716
                    }
717
718
                    // If the file wasn't created, it's usually permissions related
719
                    if (!$file_created) {
720
                        $redirect = null;
0 ignored issues
show
Unused Code introduced by
$redirect is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
721
                        return $this->pageAlert(
722
                            __('Page Template could not be written to disk.')
723
                            . ' ' . __('Please check permissions on %s.', array('<code>/workspace/pages</code>')),
724
                            Alert::ERROR
725
                        );
726
                    }
727
728
                    // Insert the new data:
729
                    if (empty($current)) {
730
                        /**
731
                         * Just prior to creating a new Page record in `tbl_pages`, provided
732
                         * with the `$fields` associative array. Use with caution, as no
733
                         * duplicate page checks are run after this delegate has fired
734
                         *
735
                         * @delegate PagePreCreate
736
                         * @since Symphony 2.2
737
                         * @param string $context
738
                         * '/blueprints/pages/'
739
                         * @param array $fields
740
                         *  The `$_POST['fields']` array passed by reference
741
                         */
742
                        Symphony::ExtensionManager()->notifyMembers('PagePreCreate', '/blueprints/pages/', array('fields' => &$fields));
743
744 View Code Duplication
                        if (!$page_id = PageManager::add($fields)) {
745
                            $this->pageAlert(
746
                                __('Unknown errors occurred while attempting to save.')
747
                                . '<a href="' . SYMPHONY_URL . '/system/log/">'
748
                                . __('Check your activity log')
749
                                . '</a>.',
750
                                Alert::ERROR
751
                            );
752
                        } else {
753
                            /**
754
                             * Just after the creation of a new page in `tbl_pages`
755
                             *
756
                             * @delegate PagePostCreate
757
                             * @since Symphony 2.2
758
                             * @param string $context
759
                             * '/blueprints/pages/'
760
                             * @param integer $page_id
761
                             *  The ID of the newly created Page
762
                             * @param array $fields
763
                             *  An associative array of data that was just saved for this page
764
                             */
765
                            Symphony::ExtensionManager()->notifyMembers('PagePostCreate', '/blueprints/pages/', array('page_id' => $page_id, 'fields' => &$fields));
766
767
                            $redirect = "/blueprints/pages/edit/{$page_id}/created/{$parent_link_suffix}";
768
                        }
769
770
                        // Update existing:
771
                    } else {
772
                        /**
773
                         * Just prior to updating a Page record in `tbl_pages`, provided
774
                         * with the `$fields` associative array. Use with caution, as no
775
                         * duplicate page checks are run after this delegate has fired
776
                         *
777
                         * @delegate PagePreEdit
778
                         * @since Symphony 2.2
779
                         * @param string $context
780
                         * '/blueprints/pages/'
781
                         * @param integer $page_id
782
                         *  The ID of the Page that is about to be updated
783
                         * @param array $fields
784
                         *  The `$_POST['fields']` array passed by reference
785
                         */
786
                        Symphony::ExtensionManager()->notifyMembers('PagePreEdit', '/blueprints/pages/', array('page_id' => $page_id, 'fields' => &$fields));
787
788 View Code Duplication
                        if (!PageManager::edit($page_id, $fields, true)) {
789
                            return $this->pageAlert(
790
                                __('Unknown errors occurred while attempting to save.')
791
                                . '<a href="' . SYMPHONY_URL . '/system/log/">'
792
                                . __('Check your activity log')
793
                                . '</a>.',
794
                                Alert::ERROR
795
                            );
796
                        } else {
797
                            /**
798
                             * Just after updating a page in `tbl_pages`
799
                             *
800
                             * @delegate PagePostEdit
801
                             * @since Symphony 2.2
802
                             * @param string $context
803
                             * '/blueprints/pages/'
804
                             * @param integer $page_id
805
                             *  The ID of the Page that was just updated
806
                             * @param array $fields
807
                             *  An associative array of data that was just saved for this page
808
                             */
809
                            Symphony::ExtensionManager()->notifyMembers('PagePostEdit', '/blueprints/pages/', array('page_id' => $page_id, 'fields' => $fields));
810
811
                            $redirect = "/blueprints/pages/edit/{$page_id}/saved/{$parent_link_suffix}";
812
                        }
813
                    }
814
                }
815
816
                // Only proceed if there was no errors saving/creating the page
817
                if (empty($this->_errors)) {
818
                    /**
819
                     * Just before the page's types are saved into `tbl_pages_types`.
820
                     * Use with caution as no further processing is done on the `$types`
821
                     * array to prevent duplicate `$types` from occurring (ie. two index
822
                     * page types). Your logic can use the PageManger::hasPageTypeBeenUsed
823
                     * function to perform this logic.
824
                     *
825
                     * @delegate PageTypePreCreate
826
                     * @since Symphony 2.2
827
                     * @see toolkit.PageManager#hasPageTypeBeenUsed
828
                     * @param string $context
829
                     * '/blueprints/pages/'
830
                     * @param integer $page_id
831
                     *  The ID of the Page that was just created or updated
832
                     * @param array $types
833
                     *  An associative array of the types for this page passed by reference.
834
                     */
835
                    Symphony::ExtensionManager()->notifyMembers('PageTypePreCreate', '/blueprints/pages/', array('page_id' => $page_id, 'types' => &$types));
836
837
                    // Assign page types:
838
                    PageManager::addPageTypesToPage($page_id, $types);
839
840
                    // Find and update children:
841
                    if ($this->_context['action'] === 'edit') {
842
                        PageManager::editPageChildren($page_id, $fields['path'] . '/' . $fields['handle']);
843
                    }
844
845
                    if ($redirect) {
846
                        redirect(SYMPHONY_URL . $redirect);
0 ignored issues
show
Bug introduced by
The variable $redirect 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...
847
                    }
848
                }
849
            }
850
851
            // If there was any errors, either with pre processing or because of a
852
            // duplicate page, return.
853 View Code Duplication
            if (is_array($this->_errors) && !empty($this->_errors)) {
854
                return $this->pageAlert(
855
                    __('An error occurred while processing this form. See below for details.'),
856
                    Alert::ERROR
857
                );
858
            }
859
        }
860
    }
861
862
    public function __actionDelete($pages, $redirect)
863
    {
864
        $success = true;
865
        $deleted_page_ids = array();
866
867
        if (!is_array($pages)) {
868
            $pages = array($pages);
869
        }
870
871
        /**
872
         * Prior to deleting Pages
873
         *
874
         * @delegate PagePreDelete
875
         * @since Symphony 2.2
876
         * @param string $context
877
         * '/blueprints/pages/'
878
         * @param array $page_ids
879
         *  An array of Page ID's that are about to be deleted, passed
880
         *  by reference
881
         * @param string $redirect
882
         *  The absolute path that the Developer will be redirected to
883
         *  after the Pages are deleted
884
         */
885
        Symphony::ExtensionManager()->notifyMembers('PagePreDelete', '/blueprints/pages/', array('page_ids' => &$pages, 'redirect' => &$redirect));
886
887
        foreach ($pages as $page_id) {
888
            $page = PageManager::fetchPageByID($page_id);
889
890
            if (empty($page)) {
891
                $success = false;
892
                $this->pageAlert(
893
                    __('Page could not be deleted because it does not exist.'),
894
                    Alert::ERROR
895
                );
896
897
                break;
898
            }
899
900
            if (PageManager::hasChildPages($page_id)) {
901
                $this->_hilights[] = $page['id'];
902
                $success = false;
903
                $this->pageAlert(
904
                    __('Page could not be deleted because it has children.'),
905
                    Alert::ERROR
906
                );
907
908
                continue;
909
            }
910
911
            if (!PageManager::deletePageFiles($page['path'], $page['handle'])) {
912
                $this->_hilights[] = $page['id'];
913
                $success = false;
914
                $this->pageAlert(
915
                    __('One or more pages could not be deleted.')
916
                    . ' ' . __('Please check permissions on %s.', array('<code>/workspace/pages</code>')),
917
                    Alert::ERROR
918
                );
919
920
                continue;
921
            }
922
923
            if (PageManager::delete($page_id, false)) {
924
                $deleted_page_ids[] = $page_id;
925
            }
926
        }
927
928
        if ($success) {
929
            /**
930
             * Fires after all Pages have been deleted
931
             *
932
             * @delegate PagePostDelete
933
             * @since Symphony 2.3
934
             * @param string $context
935
             * '/blueprints/pages/'
936
             * @param array $page_ids
937
             *  The page ID's that were just deleted
938
             */
939
            Symphony::ExtensionManager()->notifyMembers('PagePostDelete', '/blueprints/pages/', array('page_ids' => $deleted_page_ids));
940
            redirect($redirect);
941
        }
942
    }
943
}
944