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
Pull Request — integration (#2604)
by Brendan
04:24
created

contentBlueprintsPages::__viewEdit()   F

Complexity

Conditions 42
Paths > 20000

Size

Total Lines 323
Code Lines 190

Duplication

Lines 30
Ratio 9.29 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 42
eloc 190
c 3
b 0
f 0
nc 429496.7295
nop 0
dl 30
loc 323
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
    class contentBlueprintsPages extends AdministrationPage
13
    {
14
        public $_errors = array();
15
        protected $_hilights = array();
16
17
        /**
18
         * The Pages page has /action/id/flag/ context.
19
         * eg. /edit/1/saved/
20
         *
21
         * @param array $context
22
         * @param array $parts
23
         * @return array
24
         */
25 View Code Duplication
        public function parseContext(array &$context, array $parts)
26
        {
27
            // Order is important!
28
            $params = array_fill_keys(array('action', 'id', 'flag'), null);
29
30
            if (isset($parts[2])) {
31
                $extras = preg_split('/\//', $parts[2], -1, PREG_SPLIT_NO_EMPTY);
32
                list($params['action'], $params['id'], $params['flag']) = $extras;
33
                $params['id'] = (int)$params['id'];
34
            }
35
36
            $context = array_filter($params);
37
        }
38
39
        public function __viewIndex()
40
        {
41
            $this->setPageType('table');
42
            $this->setTitle(__('%1$s &ndash; %2$s', array(__('Pages'), __('Symphony'))));
43
44
            $nesting = Symphony::Configuration()->get('pages_table_nest_children', 'symphony') === 'yes';
45
46
            if ($nesting && isset($_GET['parent']) && is_numeric($_GET['parent'])) {
47
                $parent = PageManager::fetchPageByID((int)$_GET['parent'], array('title', 'id'));
48
            }
49
50
            $this->appendSubheading(isset($parent) ? $parent['title'] : __('Pages'), Widget::Anchor(
51
                __('Create New'),
52
                Administration::instance()->getCurrentPageURL() . 'new/' . ($nesting && isset($parent) ? "?parent={$parent['id']}" : null),
53
                __('Create a new page'), 'create button', null, array('accesskey' => 'c')
54
            ));
55
56
            if (isset($parent)) {
57
                $this->insertBreadcrumbsUsingPageIdentifier($parent['id'], false);
58
            }
59
60
            $aTableHead = array(
61
                array(__('Name'), 'col'),
62
                array(__('Template'), 'col'),
63
                array('<abbr title="' . __('Universal Resource Locator') . '">' . __('URL') . '</abbr>', 'col'),
64
                array(__('Parameters'), 'col'),
65
                array(__('Type'), 'col')
66
            );
67
            $aTableBody = array();
68
69
            if ($nesting) {
70
                $aTableHead[] = array(__('Children'), 'col');
71
                $where = array(
72
                    'parent ' . (isset($parent) ? " = {$parent['id']} " : ' IS NULL ')
73
                );
74
            } else {
75
                $where = array();
76
            }
77
78
            $pages = PageManager::fetch(true, array('*'), $where);
79
80
            if (!is_array($pages) || empty($pages)) {
81
                $aTableBody = array(
82
                    Widget::TableRow(array(
83
                        Widget::TableData(__('None found.'), 'inactive', null, count($aTableHead))
84
                    ), 'odd')
85
                );
86
            } else {
87
                foreach ($pages as $page) {
88
                    $class = array();
89
90
                    $page_title = ($nesting ? $page['title'] : PageManager::resolvePageTitle($page['id']));
91
                    $page_url = URL . '/' . PageManager::resolvePagePath($page['id']) . '/';
92
                    $page_edit_url = Administration::instance()->getCurrentPageURL() . 'edit/' . $page['id'] . '/';
93
                    $page_template = PageManager::createFilePath($page['path'], $page['handle']);
94
95
                    $col_title = Widget::TableData(Widget::Anchor($page_title, $page_edit_url, $page['handle']));
96
                    $col_title->appendChild(Widget::Label(__('Select Page %s', array($page_title)), null, 'accessible',
97
                        null, array(
98
                            'for' => 'page-' . $page['id']
99
                        )));
100
                    $col_title->appendChild(Widget::Input('items[' . $page['id'] . ']', 'on', 'checkbox', array(
101
                        'id' => 'page-' . $page['id']
102
                    )));
103
104
                    $col_template = Widget::TableData($page_template . '.xsl');
105
106
                    $col_url = Widget::TableData(Widget::Anchor($page_url, $page_url));
107
108 View Code Duplication
                    if ($page['params']) {
109
                        $col_params = Widget::TableData(trim($page['params'], '/'));
110
                    } else {
111
                        $col_params = Widget::TableData(__('None'), 'inactive');
112
                    }
113
114 View Code Duplication
                    if (!empty($page['type'])) {
115
                        $col_types = Widget::TableData(implode(', ', $page['type']));
116
                    } else {
117
                        $col_types = Widget::TableData(__('None'), 'inactive');
118
                    }
119
120
                    if (in_array($page['id'], $this->_hilights)) {
121
                        $class[] = 'failed';
122
                    }
123
124
                    $columns = array($col_title, $col_template, $col_url, $col_params, $col_types);
125
126
                    if ($nesting) {
127
                        if (PageManager::hasChildPages($page['id'])) {
128
                            $col_children = Widget::TableData(
129
                                Widget::Anchor(PageManager::getChildPagesCount($page['id']) . ' &rarr;',
130
                                    SYMPHONY_URL . '/blueprints/pages/?parent=' . $page['id'])
131
                            );
132
                        } else {
133
                            $col_children = Widget::TableData(__('None'), 'inactive');
134
                        }
135
136
                        $columns[] = $col_children;
137
                    }
138
139
                    $aTableBody[] = Widget::TableRow(
140
                        $columns,
141
                        implode(' ', $class)
142
                    );
143
                }
144
            }
145
146
            $table = Widget::Table(
147
                Widget::TableHead($aTableHead), null,
148
                Widget::TableBody($aTableBody), 'orderable selectable',
149
                null, array(
150
                    'role' => 'directory',
151
                    'aria-labelledby' => 'symphony-subheading',
152
                    'data-interactive' => 'data-interactive'
153
                )
154
            );
155
156
            $this->Form->appendChild($table);
157
158
            $version = new XMLElement('p', 'Symphony ' . Symphony::Configuration()->get('version', 'symphony'), array(
159
                'id' => 'version'
160
            ));
161
            $this->Form->appendChild($version);
162
163
            $tableActions = new XMLElement('div');
164
            $tableActions->setAttribute('class', 'actions');
165
166
            $options = array(
167
                array(null, false, __('With Selected...')),
168
                array(
169
                    'delete',
170
                    false,
171
                    __('Delete'),
172
                    'confirm',
173
                    null,
174
                    array(
175
                        'data-message' => __('Are you sure you want to delete the selected pages?')
176
                    )
177
                )
178
            );
179
180
            /**
181
             * Allows an extension to modify the existing options for this page's
182
             * With Selected menu. If the `$options` parameter is an empty array,
183
             * the 'With Selected' menu will not be rendered.
184
             *
185
             * @delegate AddCustomActions
186
             * @since Symphony 2.3.2
187
             * @param string $context
188
             * '/blueprints/pages/'
189
             * @param array $options
190
             *  An array of arrays, where each child array represents an option
191
             *  in the With Selected menu. Options should follow the same format
192
             *  expected by `Widget::__SelectBuildOption`. Passed by reference.
193
             */
194
            Symphony::ExtensionManager()->notifyMembers('AddCustomActions', '/blueprints/pages/', array(
195
                'options' => &$options
196
            ));
197
198
            if (!empty($options)) {
199
                $tableActions->appendChild(Widget::Apply($options));
200
                $this->Form->appendChild($tableActions);
201
            }
202
        }
203
204
        public function insertBreadcrumbsUsingPageIdentifier($page_id, $preserve_last = true)
205
        {
206
            if ($page_id === 0) {
207
                return $this->insertBreadcrumbs(
208
                    array(Widget::Anchor(__('Pages'), SYMPHONY_URL . '/blueprints/pages/'))
209
                );
210
            }
211
212
            $pages = PageManager::resolvePage($page_id, 'handle');
213
214
            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...
215
                // If we are viewing the Page Editor, the Breadcrumbs should link
216
                // to the parent's Page Editor.
217
                if ($this->_context['action'] === 'edit') {
218
                    $page = Widget::Anchor(
219
                        PageManager::fetchTitleFromHandle($page),
220
                        SYMPHONY_URL . '/blueprints/pages/edit/' . PageManager::fetchIDFromHandle($page) . '/'
221
                    );
222
223
                    // If the pages index is nested, the Breadcrumb should link to the
224
                    // Pages Index filtered by parent
225
                } elseif (Symphony::Configuration()->get('pages_table_nest_children', 'symphony') === 'yes') {
226
                    $page = Widget::Anchor(
227
                        PageManager::fetchTitleFromHandle($page),
228
                        SYMPHONY_URL . '/blueprints/pages/?parent=' . PageManager::fetchIDFromHandle($page)
229
                    );
230
231
                    // If there is no nesting on the Pages Index, the breadcrumb is
232
                    // not a link, just plain text
233
                } else {
234
                    $page = new XMLElement('span', PageManager::fetchTitleFromHandle($page));
235
                }
236
            }
237
238
            if (!$preserve_last) {
239
                array_pop($pages);
240
            }
241
242
            $this->insertBreadcrumbs(array_merge(
243
                array(Widget::Anchor(__('Pages'), SYMPHONY_URL . '/blueprints/pages/')),
244
                $pages
245
            ));
246
        }
247
248
        public function __viewNew()
249
        {
250
            $this->__viewEdit();
251
        }
252
253
        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...
254
        {
255
            $this->setPageType('form');
256
            $fields = array(
257
                "title" => null,
258
                "handle" => null,
259
                "parent" => null,
260
                "params" => null,
261
                "type" => null,
262
                "data_sources" => null
263
            );
264
            $existing = $fields;
265
266
            $nesting = (Symphony::Configuration()->get('pages_table_nest_children', 'symphony') === 'yes');
267
268
            // Verify page exists:
269
            if ($this->_context['action'] === 'edit') {
270
                if (!$page_id = (int)$this->_context['id']) {
271
                    redirect(SYMPHONY_URL . '/blueprints/pages/');
272
                }
273
274
                $existing = PageManager::fetchPageByID($page_id);
275
276
                if (!$existing) {
277
                    Administration::instance()->errorPageNotFound();
278
                } else {
279
                    $existing['type'] = PageManager::fetchPageTypes($page_id);
280
                }
281
            }
282
283
            // Status message:
284
            if (isset($this->_context['flag'])) {
285
                $flag = $this->_context['flag'];
286
                $parent_link_suffix = $message = '';
287
                $time = Widget::Time();
288
289
                if (isset($_REQUEST['parent']) && is_numeric($_REQUEST['parent'])) {
290
                    $parent_link_suffix = "?parent=" . $_REQUEST['parent'];
291
                } elseif ($nesting && isset($existing) && !is_null($existing['parent'])) {
292
                    $parent_link_suffix = '?parent=' . $existing['parent'];
293
                }
294
295
                switch ($flag) {
296
                    case 'saved':
297
                        $message = __('Page updated at %s.', array($time->generate()));
298
                        break;
299
                    case 'created':
300
                        $message = __('Page created at %s.', array($time->generate()));
301
                }
302
303
                $this->pageAlert(
304
                    $message
305
                    . ' <a href="' . SYMPHONY_URL . '/blueprints/pages/new/' . $parent_link_suffix . '" accesskey="c">'
306
                    . __('Create another?')
307
                    . '</a> <a href="' . SYMPHONY_URL . '/blueprints/pages/" accesskey="a">'
308
                    . __('View all Pages')
309
                    . '</a>',
310
                    Alert::SUCCESS
311
                );
312
            }
313
314
            // Find values:
315
            if (isset($_POST['fields'])) {
316
                $fields = $_POST['fields'];
317
            } elseif ($this->_context['action'] === 'edit') {
318
                $fields = $existing;
319
320
                if (!is_null($fields['type'])) {
321
                    $fields['type'] = implode(', ', $fields['type']);
322
                }
323
324
                $fields['data_sources'] = preg_split('/,/i', $fields['data_sources'], -1, PREG_SPLIT_NO_EMPTY);
325
                $fields['events'] = preg_split('/,/i', $fields['events'], -1, PREG_SPLIT_NO_EMPTY);
326 View Code Duplication
            } elseif (isset($_REQUEST['parent']) && is_numeric($_REQUEST['parent'])) {
327
                $fields['parent'] = $_REQUEST['parent'];
328
            }
329
330
            $title = $fields['title'];
331
332
            if (trim($title) === '') {
333
                $title = $existing['title'];
334
            }
335
336
            $this->setTitle(__(
337
                ($title ? '%1$s &ndash; %2$s &ndash; %3$s' : '%2$s &ndash; %3$s'),
338
                array(
339
                    $title,
340
                    __('Pages'),
341
                    __('Symphony')
342
                )
343
            ));
344
345
            $page_id = isset($page_id) ? $page_id : null;
346
347
            if (!empty($title)) {
348
                $page_url = URL . '/' . PageManager::resolvePagePath($page_id) . '/';
349
350
                $this->appendSubheading($title, array(
351
                    Widget::Anchor(__('View Page'), $page_url, __('View Page on Frontend'), 'button', null,
352
                        array('target' => '_blank', 'accesskey' => 'v'))
353
                ));
354
            } else {
355
                $this->appendSubheading(!empty($title) ? $title : __('Untitled'));
356
            }
357
358
            if (isset($page_id)) {
359
                $this->insertBreadcrumbsUsingPageIdentifier($page_id, false);
360
            } else {
361
                $_GET['parent'] = isset($_GET['parent']) ? $_GET['parent'] : null;
362
                $this->insertBreadcrumbsUsingPageIdentifier((int)$_GET['parent'], true);
363
            }
364
365
            // Title --------------------------------------------------------------
366
367
            $fieldset = new XMLElement('fieldset');
368
            $fieldset->setAttribute('class', 'settings');
369
            $fieldset->appendChild(new XMLElement('legend', __('Page Settings')));
370
371
            $label = Widget::Label(__('Name'));
372
            $label->appendChild(Widget::Input(
373
                'fields[title]', General::sanitize($fields['title'])
374
            ));
375
376
            if (isset($this->_errors['title'])) {
377
                $label = Widget::Error($label, $this->_errors['title']);
378
            }
379
380
            $fieldset->appendChild($label);
381
382
            // Handle -------------------------------------------------------------
383
384
            $group = new XMLElement('div');
385
            $group->setAttribute('class', 'two columns');
386
            $column = new XMLElement('div');
387
            $column->setAttribute('class', 'column');
388
389
            $label = Widget::Label(__('Handle'));
390
            $label->appendChild(Widget::Input(
391
                'fields[handle]', $fields['handle']
392
            ));
393
394
            if (isset($this->_errors['handle'])) {
395
                $label = Widget::Error($label, $this->_errors['handle']);
396
            }
397
398
            $column->appendChild($label);
399
400
            // Parent ---------------------------------------------------------
401
402
            $label = Widget::Label(__('Parent Page'));
403
404
            $where = array(
405
                sprintf('id != %d', $page_id)
406
            );
407
            $pages = PageManager::fetch(false, array('id'), $where, 'title ASC');
408
409
            $options = array(
410
                array('', false, '/')
411
            );
412
413
            if (!empty($pages)) {
414
                foreach ($pages as $page) {
415
                    $options[] = array(
416
                        $page['id'],
417
                        $fields['parent'] === $page['id'],
418
                        '/' . PageManager::resolvePagePath($page['id'])
419
                    );
420
                }
421
422
                usort($options, array($this, '__compare_pages'));
423
            }
424
425
            $label->appendChild(Widget::Select(
426
                'fields[parent]', $options
427
            ));
428
            $column->appendChild($label);
429
            $group->appendChild($column);
430
431
            // Parameters ---------------------------------------------------------
432
433
            $column = new XMLElement('div');
434
            $column->setAttribute('class', 'column');
435
436
            $label = Widget::Label(__('Parameters'));
437
            $label->appendChild(Widget::Input(
438
                'fields[params]', $fields['params'], 'text', array('placeholder' => 'param1/param2')
439
            ));
440
            $column->appendChild($label);
441
442
            // Type -----------------------------------------------------------
443
444
            $label = Widget::Label(__('Type'));
445
            $label->appendChild(Widget::Input('fields[type]', $fields['type']));
446
447
            if (isset($this->_errors['type'])) {
448
                $label = Widget::Error($label, $this->_errors['type']);
449
            }
450
451
            $column->appendChild($label);
452
453
            $tags = new XMLElement('ul');
454
            $tags->setAttribute('class', 'tags');
455
            $tags->setAttribute('data-interactive', 'data-interactive');
456
457
            $types = PageManager::fetchAvailablePageTypes();
458
459
            foreach ($types as $type) {
460
                $tags->appendChild(new XMLElement('li', $type));
461
            }
462
463
            $column->appendChild($tags);
464
            $group->appendChild($column);
465
            $fieldset->appendChild($group);
466
            $this->Form->appendChild($fieldset);
467
468
            // Events -------------------------------------------------------------
469
470
            $fieldset = new XMLElement('fieldset');
471
            $fieldset->setAttribute('class', 'settings');
472
            $fieldset->appendChild(new XMLElement('legend', __('Page Resources')));
473
474
            $group = new XMLElement('div');
475
            $group->setAttribute('class', 'two columns');
476
477
            $label = Widget::Label(__('Events'));
478
            $label->setAttribute('class', 'column');
479
480
            $events = ResourceManager::fetch(ResourceManager::RESOURCE_TYPE_EVENT, array(), array(), 'name ASC');
481
            $options = array();
482
483 View Code Duplication
            if (is_array($events) && !empty($events)) {
484
                if (!isset($fields['events'])) {
485
                    $fields['events'] = array();
486
                }
487
488
                foreach ($events as $name => $about) {
489
                    $options[] = array(
490
                        $name,
491
                        in_array($name, $fields['events']),
492
                        $about['name']
493
                    );
494
                }
495
            }
496
497
            $label->appendChild(Widget::Select('fields[events][]', $options, array('multiple' => 'multiple')));
498
            $group->appendChild($label);
499
500
            // Data Sources -------------------------------------------------------
501
502
            $label = Widget::Label(__('Data Sources'));
503
            $label->setAttribute('class', 'column');
504
505
            $datasources = ResourceManager::fetch(ResourceManager::RESOURCE_TYPE_DS, array(), array(), 'name ASC');
506
            $options = array();
507
508 View Code Duplication
            if (is_array($datasources) && !empty($datasources)) {
509
                if (!isset($fields['data_sources'])) {
510
                    $fields['data_sources'] = array();
511
                }
512
513
                foreach ($datasources as $name => $about) {
514
                    $options[] = array(
515
                        $name,
516
                        in_array($name, $fields['data_sources']),
517
                        $about['name']
518
                    );
519
                }
520
            }
521
522
            $label->appendChild(Widget::Select('fields[data_sources][]', $options, array('multiple' => 'multiple')));
523
            $group->appendChild($label);
524
            $fieldset->appendChild($group);
525
            $this->Form->appendChild($fieldset);
526
527
            // Controls -----------------------------------------------------------
528
529
            /**
530
             * After all Page related Fields have been added to the DOM, just before the
531
             * actions.
532
             *
533
             * @delegate AppendPageContent
534
             * @param string $context
535
             *  '/blueprints/pages/'
536
             * @param XMLElement $form
537
             * @param array $fields
538
             * @param array $errors
539
             */
540
            Symphony::ExtensionManager()->notifyMembers(
541
                'AppendPageContent',
542
                '/blueprints/pages/',
543
                array(
544
                    'form' => &$this->Form,
545
                    'fields' => &$fields,
546
                    'errors' => $this->_errors
547
                )
548
            );
549
550
            $div = new XMLElement('div');
551
            $div->setAttribute('class', 'actions');
552
            $div->appendChild(Widget::Input(
553
                'action[save]', ($this->_context['action'] === 'edit' ? __('Save Changes') : __('Create Page')),
554
                'submit', array('accesskey' => 's')
555
            ));
556
557 View Code Duplication
            if ($this->_context['action'] === 'edit') {
558
                $button = new XMLElement('button', __('Delete'));
559
                $button->setAttributeArray(array(
560
                    'name' => 'action[delete]',
561
                    'class' => 'button confirm delete',
562
                    'title' => __('Delete this page'),
563
                    'accesskey' => 'd',
564
                    'data-message' => __('Are you sure you want to delete this page?')
565
                ));
566
                $div->appendChild($button);
567
            }
568
569
            $this->Form->appendChild($div);
570
571
            if (isset($_REQUEST['parent']) && is_numeric($_REQUEST['parent'])) {
572
                $this->Form->appendChild(new XMLElement('input', null,
573
                    array('type' => 'hidden', 'name' => 'parent', 'value' => $_REQUEST['parent'])));
574
            }
575
        }
576
577
        public function __compare_pages($a, $b)
578
        {
579
            return strnatcasecmp($a[2], $b[2]);
580
        }
581
582
        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...
583
        {
584
            $checked = (is_array($_POST['items'])) ? array_keys($_POST['items']) : null;
585
586
            if (is_array($checked) && !empty($checked)) {
587
                /**
588
                 * Extensions can listen for any custom actions that were added
589
                 * through `AddCustomPreferenceFieldsets` or `AddCustomActions`
590
                 * delegates.
591
                 *
592
                 * @delegate CustomActions
593
                 * @since Symphony 2.3.2
594
                 * @param string $context
595
                 *  '/blueprints/pages/'
596
                 * @param array $checked
597
                 *  An array of the selected rows. The value is usually the ID of the
598
                 *  the associated object.
599
                 */
600
                Symphony::ExtensionManager()->notifyMembers('CustomActions', '/blueprints/pages/', array(
601
                    'checked' => $checked
602
                ));
603
604
                switch ($_POST['with-selected']) {
605
                    case 'delete':
606
                        $this->__actionDelete($checked, SYMPHONY_URL . '/blueprints/pages/');
607
                        break;
608
                }
609
            }
610
        }
611
612
        public function __actionDelete($pages, $redirect)
613
        {
614
            $success = true;
615
            $deleted_page_ids = array();
616
617
            if (!is_array($pages)) {
618
                $pages = array($pages);
619
            }
620
621
            /**
622
             * Prior to deleting Pages
623
             *
624
             * @delegate PagePreDelete
625
             * @since Symphony 2.2
626
             * @param string $context
627
             * '/blueprints/pages/'
628
             * @param array $page_ids
629
             *  An array of Page ID's that are about to be deleted, passed
630
             *  by reference
631
             * @param string $redirect
632
             *  The absolute path that the Developer will be redirected to
633
             *  after the Pages are deleted
634
             */
635
            Symphony::ExtensionManager()->notifyMembers('PagePreDelete', '/blueprints/pages/',
636
                array('page_ids' => &$pages, 'redirect' => &$redirect));
637
638
            foreach ($pages as $page_id) {
639
                $page = PageManager::fetchPageByID($page_id);
640
641
                if (empty($page)) {
642
                    $success = false;
643
                    $this->pageAlert(
644
                        __('Page could not be deleted because it does not exist.'),
645
                        Alert::ERROR
646
                    );
647
648
                    break;
649
                }
650
651
                if (PageManager::hasChildPages($page_id)) {
652
                    $this->_hilights[] = $page['id'];
653
                    $success = false;
654
                    $this->pageAlert(
655
                        __('Page could not be deleted because it has children.'),
656
                        Alert::ERROR
657
                    );
658
659
                    continue;
660
                }
661
662
                if (!PageManager::deletePageFiles($page['path'], $page['handle'])) {
663
                    $this->_hilights[] = $page['id'];
664
                    $success = false;
665
                    $this->pageAlert(
666
                        __('One or more pages could not be deleted.')
667
                        . ' ' . __('Please check permissions on %s.', array('<code>/workspace/pages</code>')),
668
                        Alert::ERROR
669
                    );
670
671
                    continue;
672
                }
673
674
                if (PageManager::delete($page_id, false)) {
675
                    $deleted_page_ids[] = $page_id;
676
                }
677
            }
678
679
            if ($success) {
680
                /**
681
                 * Fires after all Pages have been deleted
682
                 *
683
                 * @delegate PagePostDelete
684
                 * @since Symphony 2.3
685
                 * @param string $context
686
                 * '/blueprints/pages/'
687
                 * @param array $page_ids
688
                 *  The page ID's that were just deleted
689
                 */
690
                Symphony::ExtensionManager()->notifyMembers('PagePostDelete', '/blueprints/pages/',
691
                    array('page_ids' => $deleted_page_ids));
692
                redirect($redirect);
693
            }
694
        }
695
696
        public function __actionNew()
697
        {
698
            $this->__actionEdit();
699
        }
700
701
        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...
702
        {
703
            if ($this->_context['action'] !== 'new' && !$page_id = (int)$this->_context['id']) {
704
                redirect(SYMPHONY_URL . '/blueprints/pages/');
705
            }
706
707
            $parent_link_suffix = null;
708
709 View Code Duplication
            if (isset($_REQUEST['parent']) && is_numeric($_REQUEST['parent'])) {
710
                $parent_link_suffix = '?parent=' . $_REQUEST['parent'];
711
            }
712
713
            if (@array_key_exists('delete', $_POST['action'])) {
714
                $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...
715
            }
716
717
            if (@array_key_exists('save', $_POST['action'])) {
718
                $fields = $_POST['fields'];
719
                $this->_errors = array();
720
                $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...
721
722 View Code Duplication
                if (!isset($fields['title']) || trim($fields['title']) === '') {
723
                    $this->_errors['title'] = __('This is a required field');
724
                }
725
726
                if (trim($fields['type']) !== '' && preg_match('/(index|404|403)/i', $fields['type'])) {
727
                    $types = preg_split('/\s*,\s*/', strtolower($fields['type']), -1, PREG_SPLIT_NO_EMPTY);
728
729
                    if (in_array('index', $types) && PageManager::hasPageTypeBeenUsed($page_id, 'index')) {
730
                        $this->_errors['type'] = __('An index type page already exists.');
731
                    } elseif (in_array('404', $types) && PageManager::hasPageTypeBeenUsed($page_id, '404')) {
732
                        $this->_errors['type'] = __('A 404 type page already exists.');
733
                    } elseif (in_array('403', $types) && PageManager::hasPageTypeBeenUsed($page_id, '403')) {
734
                        $this->_errors['type'] = __('A 403 type page already exists.');
735
                    }
736
                }
737
738
                if (trim($fields['handle']) === '') {
739
                    $fields['handle'] = $fields['title'];
740
                    $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...
741
                }
742
743
                $fields['handle'] = PageManager::createHandle($fields['handle']);
744
745
                if (empty($fields['handle']) && !isset($this->_errors['title'])) {
746
                    $this->_errors['handle'] = __('Please ensure handle contains at least one Latin-based character.');
747
                }
748
749
                /**
750
                 * Just after the Symphony validation has run, allows Developers
751
                 * to run custom validation logic on a Page
752
                 *
753
                 * @delegate PagePostValidate
754
                 * @since Symphony 2.2
755
                 * @param string $context
756
                 * '/blueprints/pages/'
757
                 * @param array $fields
758
                 *  The `$_POST['fields']` array. This should be read-only and not changed
759
                 *  through this delegate.
760
                 * @param array $errors
761
                 *  An associative array of errors, with the key matching a key in the
762
                 *  `$fields` array, and the value being the string of the error. `$errors`
763
                 *  is passed by reference.
764
                 */
765
                Symphony::ExtensionManager()->notifyMembers('PagePostValidate', '/blueprints/pages/',
766
                    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...
767
768
                if (empty($this->_errors)) {
769
                    $autogenerated_handle = false;
770
771
                    if ($fields['params']) {
772
                        $fields['params'] = trim(preg_replace('@\/{2,}@', '/', $fields['params']), '/');
773
                    }
774
775
                    // Clean up type list
776
                    $types = preg_split('/\s*,\s*/', $fields['type'], -1, PREG_SPLIT_NO_EMPTY);
777
                    $types = @array_map('trim', $types);
778
                    unset($fields['type']);
779
780
                    $fields = array_filter($fields);
781
782
                    $fields['parent'] = ($fields['parent'] !== __('None') ? $fields['parent'] : null);
783
                    $fields['data_sources'] = is_array($fields['data_sources']) ? implode(',',
784
                        $fields['data_sources']) : null;
785
                    $fields['events'] = is_array($fields['events']) ? implode(',', $fields['events']) : null;
786
                    $fields['path'] = null;
787
788
                    if ($fields['parent']) {
789
                        $fields['path'] = PageManager::resolvePagePath((integer)$fields['parent']);
790
                    }
791
792
                    // Check for duplicates:
793
                    $current = PageManager::fetchPageByID($page_id);
794
795
                    if (empty($current)) {
796
                        $fields['sortorder'] = PageManager::fetchNextSortOrder();
797
                    }
798
799
                    $where = array();
800
801
                    if (!empty($current)) {
802
                        $where[] = "p.id != {$page_id}";
803
                    }
804
805
                    $where[] = "p.handle = '" . $fields['handle'] . "'";
806
                    $where[] = (is_null($fields['path']))
807
                        ? "p.path IS null"
808
                        : "p.path = '" . $fields['path'] . "'";
809
                    $duplicate = PageManager::fetch(false, array('*'), $where);
810
811
                    // If duplicate
812
                    if (!empty($duplicate)) {
813
                        if ($autogenerated_handle) {
814
                            $this->_errors['title'] = __('A page with that title already exists');
815
                        } else {
816
                            $this->_errors['handle'] = __('A page with that handle already exists');
817
                        }
818
819
                        // Create or move files:
820
                    } else {
821
                        // New page?
822
                        if (empty($current)) {
823
                            $file_created = PageManager::createPageFiles(
824
                                $fields['path'],
825
                                $fields['handle']
826
                            );
827
828
                            // Existing page, potentially rename files
829
                        } else {
830
                            $file_created = PageManager::createPageFiles(
831
                                $fields['path'],
832
                                $fields['handle'],
833
                                $current['path'],
834
                                $current['handle']
835
                            );
836
                        }
837
838
                        // If the file wasn't created, it's usually permissions related
839
                        if (!$file_created) {
840
                            $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...
841
842
                            return $this->pageAlert(
843
                                __('Page Template could not be written to disk.')
844
                                . ' ' . __('Please check permissions on %s.', array('<code>/workspace/pages</code>')),
845
                                Alert::ERROR
846
                            );
847
                        }
848
849
                        // Insert the new data:
850
                        if (empty($current)) {
851
                            /**
852
                             * Just prior to creating a new Page record in `tbl_pages`, provided
853
                             * with the `$fields` associative array. Use with caution, as no
854
                             * duplicate page checks are run after this delegate has fired
855
                             *
856
                             * @delegate PagePreCreate
857
                             * @since Symphony 2.2
858
                             * @param string $context
859
                             * '/blueprints/pages/'
860
                             * @param array $fields
861
                             *  The `$_POST['fields']` array passed by reference
862
                             */
863
                            Symphony::ExtensionManager()->notifyMembers('PagePreCreate', '/blueprints/pages/',
864
                                array('fields' => &$fields));
865
866 View Code Duplication
                            if (!$page_id = PageManager::add($fields)) {
867
                                $this->pageAlert(
868
                                    __('Unknown errors occurred while attempting to save.')
869
                                    . '<a href="' . SYMPHONY_URL . '/system/log/">'
870
                                    . __('Check your activity log')
871
                                    . '</a>.',
872
                                    Alert::ERROR
873
                                );
874
                            } else {
875
                                /**
876
                                 * Just after the creation of a new page in `tbl_pages`
877
                                 *
878
                                 * @delegate PagePostCreate
879
                                 * @since Symphony 2.2
880
                                 * @param string $context
881
                                 * '/blueprints/pages/'
882
                                 * @param integer $page_id
883
                                 *  The ID of the newly created Page
884
                                 * @param array $fields
885
                                 *  An associative array of data that was just saved for this page
886
                                 */
887
                                Symphony::ExtensionManager()->notifyMembers('PagePostCreate', '/blueprints/pages/',
888
                                    array('page_id' => $page_id, 'fields' => &$fields));
889
890
                                $redirect = "/blueprints/pages/edit/{$page_id}/created/{$parent_link_suffix}";
891
                            }
892
893
                            // Update existing:
894
                        } else {
895
                            /**
896
                             * Just prior to updating a Page record in `tbl_pages`, provided
897
                             * with the `$fields` associative array. Use with caution, as no
898
                             * duplicate page checks are run after this delegate has fired
899
                             *
900
                             * @delegate PagePreEdit
901
                             * @since Symphony 2.2
902
                             * @param string $context
903
                             * '/blueprints/pages/'
904
                             * @param integer $page_id
905
                             *  The ID of the Page that is about to be updated
906
                             * @param array $fields
907
                             *  The `$_POST['fields']` array passed by reference
908
                             */
909
                            Symphony::ExtensionManager()->notifyMembers('PagePreEdit', '/blueprints/pages/',
910
                                array('page_id' => $page_id, 'fields' => &$fields));
911
912 View Code Duplication
                            if (!PageManager::edit($page_id, $fields, true)) {
913
                                return $this->pageAlert(
914
                                    __('Unknown errors occurred while attempting to save.')
915
                                    . '<a href="' . SYMPHONY_URL . '/system/log/">'
916
                                    . __('Check your activity log')
917
                                    . '</a>.',
918
                                    Alert::ERROR
919
                                );
920
                            } else {
921
                                /**
922
                                 * Just after updating a page in `tbl_pages`
923
                                 *
924
                                 * @delegate PagePostEdit
925
                                 * @since Symphony 2.2
926
                                 * @param string $context
927
                                 * '/blueprints/pages/'
928
                                 * @param integer $page_id
929
                                 *  The ID of the Page that was just updated
930
                                 * @param array $fields
931
                                 *  An associative array of data that was just saved for this page
932
                                 */
933
                                Symphony::ExtensionManager()->notifyMembers('PagePostEdit', '/blueprints/pages/',
934
                                    array('page_id' => $page_id, 'fields' => $fields));
935
936
                                $redirect = "/blueprints/pages/edit/{$page_id}/saved/{$parent_link_suffix}";
937
                            }
938
                        }
939
                    }
940
941
                    // Only proceed if there was no errors saving/creating the page
942
                    if (empty($this->_errors)) {
943
                        /**
944
                         * Just before the page's types are saved into `tbl_pages_types`.
945
                         * Use with caution as no further processing is done on the `$types`
946
                         * array to prevent duplicate `$types` from occurring (ie. two index
947
                         * page types). Your logic can use the PageManger::hasPageTypeBeenUsed
948
                         * function to perform this logic.
949
                         *
950
                         * @delegate PageTypePreCreate
951
                         * @since Symphony 2.2
952
                         * @see toolkit.PageManager#hasPageTypeBeenUsed
953
                         * @param string $context
954
                         * '/blueprints/pages/'
955
                         * @param integer $page_id
956
                         *  The ID of the Page that was just created or updated
957
                         * @param array $types
958
                         *  An associative array of the types for this page passed by reference.
959
                         */
960
                        Symphony::ExtensionManager()->notifyMembers('PageTypePreCreate', '/blueprints/pages/',
961
                            array('page_id' => $page_id, 'types' => &$types));
962
963
                        // Assign page types:
964
                        PageManager::addPageTypesToPage($page_id, $types);
965
966
                        // Find and update children:
967
                        if ($this->_context['action'] === 'edit') {
968
                            PageManager::editPageChildren($page_id, $fields['path'] . '/' . $fields['handle']);
969
                        }
970
971
                        if ($redirect) {
972
                            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...
973
                        }
974
                    }
975
                }
976
977
                // If there was any errors, either with pre processing or because of a
978
                // duplicate page, return.
979 View Code Duplication
                if (is_array($this->_errors) && !empty($this->_errors)) {
980
                    return $this->pageAlert(
981
                        __('An error occurred while processing this form. See below for details.'),
982
                        Alert::ERROR
983
                    );
984
                }
985
            }
986
        }
987
    }
988