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

contentSystemAuthors::__actionEdit()   F

Complexity

Conditions 53
Paths > 20000

Size

Total Lines 179
Code Lines 90

Duplication

Lines 34
Ratio 18.99 %

Importance

Changes 4
Bugs 1 Features 0
Metric Value
cc 53
eloc 90
c 4
b 1
f 0
nc 123172
nop 0
dl 34
loc 179
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
 * Controller page for all Symphony Author related activity
9
 * including making new Authors, editing Authors or deleting
10
 * Authors from Symphony
11
 */
12
13
class contentSystemAuthors extends AdministrationPage
14
{
15
    public $_Author;
16
    public $_errors = array();
17
18
    /**
19
     * The Authors 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 sort(&$sort, &$order, $params)
0 ignored issues
show
Unused Code introduced by
The parameter $params is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
41
    {
42
        if (is_null($sort) || $sort === 'name') {
43
            return AuthorManager::fetch("first_name $order,  last_name", $order);
44
        } else {
45
            $sort = General::sanitize($sort);
46
        }
47
48
        return AuthorManager::fetch($sort, $order);
49
    }
50
51
    public function __viewIndex()
52
    {
53
        $this->setPageType('table');
54
        $this->setTitle(__('%1$s &ndash; %2$s', array(__('Authors'), __('Symphony'))));
55
56
        if (Symphony::Author()->isDeveloper() || Symphony::Author()->isManager()) {
57
            $this->appendSubheading(__('Authors'), Widget::Anchor(__('Create New'), Administration::instance()->getCurrentPageURL().'new/', __('Create a new author'), 'create button', null, array('accesskey' => 'c')));
58
        } else {
59
            $this->appendSubheading(__('Authors'));
60
        }
61
62
        Sortable::initialize($this, $authors, $sort, $order);
63
64
        $columns = array(
65
            array(
66
                'label' => __('Name'),
67
                'sortable' => true,
68
                'handle' => 'name'
69
            ),
70
            array(
71
                'label' => __('Email Address'),
72
                'sortable' => true,
73
                'handle' => 'email'
74
            ),
75
            array(
76
                'label' => __('Last Seen'),
77
                'sortable' => true,
78
                'handle' => 'last_seen'
79
            )
80
        );
81
82
        if (Symphony::Author()->isDeveloper() || Symphony::Author()->isManager()) {
83
            $columns = array_merge($columns, array(
84
                array(
85
                    'label' => __('User Type'),
86
                    'sortable' => true,
87
                    'handle' => 'user_type'
88
                ),
89
                array(
90
                    'label' => __('Language'),
91
                    'sortable' => true,
92
                    'handle' => 'language'
93
                )
94
            ));
95
        }
96
97
        $aTableHead = Sortable::buildTableHeaders($columns, $sort, $order, (isset($_REQUEST['filter']) ? '&amp;filter=' . $_REQUEST['filter'] : ''));
98
99
        $aTableBody = array();
100
101
        if (!is_array($authors) || empty($authors)) {
102
            $aTableBody = array(
103
                Widget::TableRow(array(Widget::TableData(__('None found.'), 'inactive', null, count($aTableHead))), 'odd')
104
            );
105
        } else {
106
            foreach ($authors as $a) {
107
                // Setup each cell
108
                if (
109
                    (Symphony::Author()->isDeveloper() || (Symphony::Author()->isManager() && !$a->isDeveloper()))
110
                    || Symphony::Author()->get('id') === $a->get('id')
111
                ) {
112
                    $td1 = Widget::TableData(
113
                        Widget::Anchor($a->getFullName(), Administration::instance()->getCurrentPageURL() . 'edit/' . $a->get('id') . '/', $a->get('username'), 'author')
114
                    );
115
                } else {
116
                    $td1 = Widget::TableData($a->getFullName(), 'inactive');
117
                }
118
119
                // Can this Author be edited by the current Author?
120
                if (Symphony::Author()->isDeveloper() || Symphony::Author()->isManager()) {
121
                    if ($a->get('id') !== Symphony::Author()->get('id')) {
122
                        $td1->appendChild(Widget::Label(__('Select Author %s', array($a->getFullName())), null, 'accessible', null, array(
123
                            'for' => 'author-' . $a->get('id')
124
                        )));
125
                        $td1->appendChild(Widget::Input('items['.$a->get('id').']', 'on', 'checkbox', array(
126
                            'id' => 'author-' . $a->get('id')
127
                        )));
128
                    }
129
                }
130
131
                $td2 = Widget::TableData(Widget::Anchor($a->get('email'), 'mailto:'.$a->get('email'), __('Email this author')));
132
133
                if (!is_null($a->get('last_seen'))) {
134
                    $td3 = Widget::TableData(
135
                        DateTimeObj::format($a->get('last_seen'), __SYM_DATETIME_FORMAT__)
0 ignored issues
show
Security Bug introduced by
It seems like \DateTimeObj::format($a-..._SYM_DATETIME_FORMAT__) targeting DateTimeObj::format() can also be of type false; however, Widget::TableData() does only seem to accept object<XMLElement>|string, did you maybe forget to handle an error condition?
Loading history...
136
                    );
137
                } else {
138
                    $td3 = Widget::TableData(__('Unknown'), 'inactive');
139
                }
140
141
                if ($a->isDeveloper()) {
142
                    $type = 'Developer';
143
                } elseif ($a->isManager()) {
144
                    $type = 'Manager';
145
                } else {
146
                    $type = 'Author';
147
                }
148
149
                $td4 = Widget::TableData(__($type));
150
151
                $languages = Lang::getAvailableLanguages();
152
153
                $td5 = Widget::TableData($a->get("language") === null ? __("System Default") : $languages[$a->get("language")]);
154
155
                // Add a row to the body array, assigning each cell to the row
156
                if (Symphony::Author()->isDeveloper() || Symphony::Author()->isManager()) {
157
                    $aTableBody[] = Widget::TableRow(array($td1, $td2, $td3, $td4, $td5));
158
                } else {
159
                    $aTableBody[] = Widget::TableRow(array($td1, $td2, $td3));
160
                }
161
            }
162
        }
163
164
        $table = Widget::Table(
165
            Widget::TableHead($aTableHead),
166
            null,
167
            Widget::TableBody($aTableBody),
168
            'selectable',
169
            null,
170
            array('role' => 'directory', 'aria-labelledby' => 'symphony-subheading')
171
        );
172
173
        $this->Form->appendChild($table);
174
175
        $version = new XMLElement('p', 'Symphony ' . Symphony::Configuration()->get('version', 'symphony'), array(
176
            'id' => 'version'
177
        ));
178
179
        $this->Form->appendChild($version);
180
    }
181
182
    // Both the Edit and New pages need the same form
183
    public function __viewNew()
184
    {
185
        $this->__form();
186
    }
187
188
    public function __viewEdit()
189
    {
190
        $this->__form();
191
    }
192
193
    public function __form()
0 ignored issues
show
Coding Style introduced by
__form 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...
194
    {
195
        // Handle unknown context
196
        if (!in_array($this->_context['action'], array('new', 'edit'))) {
197
            Administration::instance()->errorPageNotFound();
198
        }
199
200
        if ($this->_context['action'] === 'new' && !Symphony::Author()->isDeveloper() && !Symphony::Author()->isManager()) {
201
            Administration::instance()->throwCustomError(
202
                __('You are not authorised to access this page.'),
203
                __('Access Denied'),
204
                Page::HTTP_STATUS_UNAUTHORIZED
205
            );
206
        }
207
208
        if (isset($this->_context['flag'])) {
209
            $time = Widget::Time();
210
211
            switch ($this->_context['flag']) {
212
                case 'saved':
213
                    $message = __('Author updated at %s.', array($time->generate()));
214
                    break;
215
                case 'created':
216
                    $message = __('Author created at %s.', array($time->generate()));
217
            }
218
219
            $this->pageAlert(
220
                $message
0 ignored issues
show
Bug introduced by
The variable $message 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...
221
                . ' <a href="' . SYMPHONY_URL . '/system/authors/new/" accesskey="c">'
222
                . __('Create another?')
223
                . '</a> <a href="' . SYMPHONY_URL . '/system/authors/" accesskey="a">'
224
                . __('View all Authors')
225
                . '</a>',
226
                Alert::SUCCESS
227
            );
228
        }
229
230
        $this->setPageType('form');
231
        $isOwner = false;
232
        $isEditing = ($this->_context['action'] === 'edit');
233
234
        if (isset($_POST['fields'])) {
235
            $author = $this->_Author;
236
        } elseif ($isEditing) {
237
            if (!$author_id = $this->_context['id']) {
238
                redirect(SYMPHONY_URL . '/system/authors/');
239
            }
240
241
            if (!$author = AuthorManager::fetchByID($author_id)) {
242
                Administration::instance()->throwCustomError(
243
                    __('The author profile you requested does not exist.'),
244
                    __('Author not found'),
245
                    Page::HTTP_STATUS_NOT_FOUND
246
                );
247
            }
248
        } else {
249
            $author = new Author;
250
        }
251
252
        if ($isEditing && $author->get('id') === Symphony::Author()->get('id')) {
253
            $isOwner = true;
254
        }
255
256
        if ($isEditing && !$isOwner && !Symphony::Author()->isDeveloper() && !Symphony::Author()->isManager()) {
257
            Administration::instance()->throwCustomError(
258
                __('You are not authorised to edit other authors.'),
259
                __('Access Denied'),
260
                Page::HTTP_STATUS_FORBIDDEN
261
            );
262
        }
263
264
        $this->setTitle(__(($this->_context['action'] === 'new' ? '%2$s &ndash; %3$s' : '%1$s &ndash; %2$s &ndash; %3$s'), array($author->getFullName(), __('Authors'), __('Symphony'))));
265
        $this->appendSubheading(($this->_context['action'] === 'new' ? __('Untitled') : $author->getFullName()));
266
        $this->insertBreadcrumbs(array(
267
            Widget::Anchor(__('Authors'), SYMPHONY_URL . '/system/authors/'),
268
        ));
269
270
        // Essentials
271
        $group = new XMLElement('fieldset');
272
        $group->setAttribute('class', 'settings');
273
        $group->appendChild(new XMLElement('legend', __('Essentials')));
274
275
        $div = new XMLElement('div');
276
        $div->setAttribute('class', 'two columns');
277
278
        $label = Widget::Label(__('First Name'), null, 'column');
279
        $label->appendChild(Widget::Input('fields[first_name]', $author->get('first_name')));
280
        $div->appendChild((isset($this->_errors['first_name']) ? Widget::Error($label, $this->_errors['first_name']) : $label));
281
282
283
        $label = Widget::Label(__('Last Name'), null, 'column');
284
        $label->appendChild(Widget::Input('fields[last_name]', $author->get('last_name')));
285
        $div->appendChild((isset($this->_errors['last_name']) ? Widget::Error($label, $this->_errors['last_name']) : $label));
286
287
        $group->appendChild($div);
288
289
        $label = Widget::Label(__('Email Address'));
290
        $label->appendChild(Widget::Input('fields[email]', $author->get('email'), 'text', array('autocomplete' => 'off')));
291
        $group->appendChild((isset($this->_errors['email']) ? Widget::Error($label, $this->_errors['email']) : $label));
292
293
        $this->Form->appendChild($group);
294
295
        // Login Details
296
        $group = new XMLElement('fieldset');
297
        $group->setAttribute('class', 'settings');
298
        $group->appendChild(new XMLElement('legend', __('Login Details')));
299
300
        $div = new XMLElement('div');
301
302
        $label = Widget::Label(__('Username'));
303
        $label->appendChild(Widget::Input('fields[username]', $author->get('username'), 'text', array('autocomplete' => 'off')));
304
        $div->appendChild((isset($this->_errors['username']) ? Widget::Error($label, $this->_errors['username']) : $label));
305
306
        // Only developers can change the user type. Primary account should NOT be able to change this
307
        if ((Symphony::Author()->isDeveloper() || Symphony::Author()->isManager()) && !$author->isPrimaryAccount()) {
308
309
            // Create columns
310
            $div->setAttribute('class', 'two columns');
311
            $label->setAttribute('class', 'column');
312
313
            // User type
314
            $label = Widget::Label(__('User Type'), null, 'column');
315
316
            $options = array(
317
                array('author', false, __('Author')),
318
                array('manager', $author->isManager(), __('Manager'))
319
            );
320
321
            if (Symphony::Author()->isDeveloper()) {
322
                $options[] = array('developer', $author->isDeveloper(), __('Developer'));
323
            }
324
325
            $label->appendChild(Widget::Select('fields[user_type]', $options));
326
            $div->appendChild($label);
327
        }
328
329
        $group->appendChild($div);
330
331
        // Password
332
        $fieldset = new XMLElement('fieldset', null, array('class' => 'two columns', 'id' => 'password'));
333
        $legend = new XMLElement('legend', __('Password'));
334
        $help = new XMLElement('i', __('Leave password fields blank to keep the current password'));
335
        $fieldset->appendChild($legend);
336
        $fieldset->appendChild($help);
337
338
        /*
339
            Password reset rules:
340
            - Primary account can edit all accounts.
341
            - Developers can edit all developers, managers and authors, and their own.
342
            - Managers can edit all Authors, and their own.
343
            - Authors can edit their own.
344
        */
345
        if ($isEditing && !(
346
            // All accounts can edit their own
347
            $isOwner
348
            // Managers can edit all Authors, and their own.
349
            || (Symphony::Author()->isManager() && $author->isAuthor())
350
            // Primary account can edit all accounts.
351
            || Symphony::Author()->isPrimaryAccount()
352
            // Developers can edit all developers, managers and authors, and their own.
353
            || Symphony::Author()->isDeveloper() && $author->isPrimaryAccount() === false
354
        )) {
355
            $fieldset->setAttribute('class', 'three columns');
356
357
            $label = Widget::Label(null, null, 'column');
358
            $label->appendChild(Widget::Input('fields[old-password]', null, 'password', array('placeholder' => __('Old Password'), 'autocomplete' => 'off')));
359
            $fieldset->appendChild((isset($this->_errors['old-password']) ? Widget::Error($label, $this->_errors['old-password']) : $label));
360
        }
361
362
        // New password
363
        $placeholder = ($isEditing ? __('New Password') : __('Password'));
364
        $label = Widget::Label(null, null, 'column');
365
        $label->appendChild(Widget::Input('fields[password]', null, 'password', array('placeholder' => $placeholder, 'autocomplete' => 'off')));
366
        $fieldset->appendChild((isset($this->_errors['password']) ? Widget::Error($label, $this->_errors['password']) : $label));
367
368
        // Confirm password
369
        $label = Widget::Label(null, null, 'column');
370
        $label->appendChild(Widget::Input('fields[password-confirmation]', null, 'password', array('placeholder' => __('Confirm Password'), 'autocomplete' => 'off')));
371
        $fieldset->appendChild((isset($this->_errors['password-confirmation']) ? Widget::Error($label, $this->_errors['password']) : $label));
372
373
        $group->appendChild($fieldset);
374
375
        // Auth token
376
        if (Symphony::Author()->isDeveloper() || Symphony::Author()->isManager()) {
377
            $label = Widget::Label();
378
            $group->appendChild(Widget::Input('fields[auth_token_active]', 'no', 'hidden'));
379
            $input = Widget::Input('fields[auth_token_active]', 'yes', 'checkbox');
380
381
            if ($author->isTokenActive()) {
382
                $input->setAttribute('checked', 'checked');
383
            }
384
385
            $temp = SYMPHONY_URL . '/login/' . $author->createAuthToken() . '/';
386
            $label->setValue(__('%s Allow remote login via', array($input->generate())) . ' <a href="' . $temp . '">' . $temp . '</a>');
387
            $group->appendChild($label);
388
        }
389
390
        $label = Widget::Label(__('Default Area'));
391
392
        $sections = SectionManager::fetch(null, 'ASC', 'sortorder');
393
394
        $options = array();
395
396
        // If the Author is the Developer, allow them to set the Default Area to
397
        // be the Sections Index.
398
        if ($author->isDeveloper()) {
399
            $options[] = array('/blueprints/sections/', $author->get('default_area') === '/blueprints/sections/', __('Sections Index'));
400
        }
401
402
        if (is_array($sections) && !empty($sections)) {
403
            foreach ($sections as $s) {
404
                $options[] = array($s->get('id'), $author->get('default_area') === $s->get('id'), $s->get('name'));
405
            }
406
        }
407
408
        /**
409
        * Allows injection or manipulation of the Default Area dropdown for an Author.
410
        * Take care with adding in options that are only valid for Developers, as if a
411
        * normal Author is set to that option, they will be redirected to their own
412
        * Author record.
413
        *
414
        *
415
        * @delegate AddDefaultAuthorAreas
416
        * @since Symphony 2.2
417
        * @param string $context
418
        * '/system/authors/'
419
        * @param array $options
420
        * An associative array of options, suitable for use for the Widget::Select
421
        * function. By default this will be an array of the Sections in the current
422
        * installation. New options should be the path to the page after the `SYMPHONY_URL`
423
        * constant.
424
        * @param string $default_area
425
        * The current `default_area` for this Author.
426
        */
427
        Symphony::ExtensionManager()->notifyMembers('AddDefaultAuthorAreas', '/system/authors/', array(
428
            'options' => &$options,
429
            'default_area' => $author->get('default_area')
430
        ));
431
432
        $label->appendChild(Widget::Select('fields[default_area]', $options));
433
        $group->appendChild($label);
434
435
        $this->Form->appendChild($group);
436
437
        // Custom Language Selection
438
        $languages = Lang::getAvailableLanguages();
439
        if (count($languages) > 1) {
440
            // Get language names
441
            asort($languages);
442
443
            $group = new XMLElement('fieldset');
444
            $group->setAttribute('class', 'settings');
445
            $group->appendChild(new XMLElement('legend', __('Custom Preferences')));
446
447
            $label = Widget::Label(__('Language'));
448
449
            $options = array(
450
                array(null, is_null($author->get('language')), __('System Default'))
451
            );
452
453
            foreach ($languages as $code => $name) {
454
                $options[] = array($code, $code === $author->get('language'), $name);
455
            }
456
            $select = Widget::Select('fields[language]', $options);
457
            $label->appendChild($select);
458
            $group->appendChild($label);
459
460
            $this->Form->appendChild($group);
461
        }
462
463
        // Administration password double check
464
        if ($isEditing && !$isOwner) {
465
            $group = new XMLElement('fieldset');
466
            $group->setAttribute('class', 'settings');
467
            $group->setAttribute('id', 'confirmation');
468
            $group->appendChild(new XMLElement('legend', __('Confirmation')));
469
            $group->appendChild(new XMLELement('p', __('Please confirm changes to this author with your password.'), array('class' => 'help')));
470
471
            $label = Widget::Label(__('Password'));
472
            $label->appendChild(Widget::Input('fields[confirm-change-password]', null, 'password', array(
473
                'autocomplete' => 'off',
474
                'placeholder' => __('Your Password')
475
            )));
476
            $group->appendChild(
477
                isset($this->_errors['confirm-change-password']) ? Widget::Error($label, $this->_errors['confirm-change-password']) : $label
478
            );
479
480
            $this->Form->appendChild($group);
481
        }
482
483
        // Actions
484
        $div = new XMLElement('div');
485
        $div->setAttribute('class', 'actions');
486
487
        $div->appendChild(Widget::Input('action[save]', ($this->_context['action'] === 'edit' ? __('Save Changes') : __('Create Author')), 'submit', array('accesskey' => 's')));
488
489
        if ($isEditing && !$isOwner && !$author->isPrimaryAccount()) {
490
            $button = new XMLElement('button', __('Delete'));
491
            $button->setAttributeArray(array('name' => 'action[delete]', 'class' => 'button confirm delete', 'title' => __('Delete this author'), 'type' => 'submit', 'accesskey' => 'd', 'data-message' => __('Are you sure you want to delete this author?')));
492
            $div->appendChild($button);
493
        }
494
495
        $this->Form->appendChild($div);
496
497
        /**
498
        * Allows the injection of custom form fields given the current `$this->Form`
499
        * object. Please note that this custom data should be saved in own extension
500
        * tables and that modifying `tbl_authors` to house your data is highly discouraged.
501
        *
502
        * @delegate AddElementstoAuthorForm
503
        * @since Symphony 2.2
504
        * @param string $context
505
        * '/system/authors/'
506
        * @param XMLElement $form
507
        * The contents of `$this->Form` after all the default form elements have been appended.
508
        * @param Author $author
509
        * The current Author object that is being edited
510
        */
511
        Symphony::ExtensionManager()->notifyMembers('AddElementstoAuthorForm', '/system/authors/', array(
512
            'form' => &$this->Form,
513
            'author' => $author
514
        ));
515
    }
516
517
    public function __actionNew()
0 ignored issues
show
Coding Style introduced by
__actionNew 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...
518
    {
519
        if (@array_key_exists('save', $_POST['action']) || @array_key_exists('done', $_POST['action'])) {
520
            $fields = $_POST['fields'];
521
522
            $this->_Author = new Author;
523
            $this->_Author->set('user_type', $fields['user_type']);
524
            $this->_Author->set('primary', 'no');
525
            $this->_Author->set('email', $fields['email']);
526
            $this->_Author->set('username', General::sanitize($fields['username']));
527
            $this->_Author->set('first_name', General::sanitize($fields['first_name']));
528
            $this->_Author->set('last_name', General::sanitize($fields['last_name']));
529
            $this->_Author->set('last_seen', null);
530
            $this->_Author->set('password', (trim($fields['password']) === '' ? '' : Cryptography::hash(Symphony::Database()->cleanValue($fields['password']))));
531
            $this->_Author->set('default_area', $fields['default_area']);
532
            $this->_Author->set('auth_token_active', ($fields['auth_token_active'] ? $fields['auth_token_active'] : 'no'));
533
            $this->_Author->set('language', isset($fields['language']) ? $fields['language'] : null);
534
535
            if ($this->_Author->validate($this->_errors)) {
536
                if ($fields['password'] !== $fields['password-confirmation']) {
537
                    $this->_errors['password'] = $this->_errors['password-confirmation'] = __('Passwords did not match');
538
                } elseif ($author_id = $this->_Author->commit()) {
539
                    /**
540
                     * Creation of a new Author. The Author object is provided as read
541
                     * only through this delegate.
542
                     *
543
                     * @delegate AuthorPostCreate
544
                     * @since Symphony 2.2
545
                     * @param string $context
546
                     * '/system/authors/'
547
                     * @param Author $author
548
                     *  The Author object that has just been created
549
                     */
550
                    Symphony::ExtensionManager()->notifyMembers('AuthorPostCreate', '/system/authors/', array('author' => $this->_Author));
551
552
                    redirect(SYMPHONY_URL . "/system/authors/edit/$author_id/created/");
553
                }
554
            }
555
556
            if (is_array($this->_errors) && !empty($this->_errors)) {
557
                $this->pageAlert(__('There were some problems while attempting to save. Please check below for problem fields.'), Alert::ERROR);
558 View Code Duplication
            } else {
559
                $this->pageAlert(
560
                    __('Unknown errors occurred while attempting to save.')
561
                    . '<a href="' . SYMPHONY_URL . '/system/log/">'
562
                    . __('Check your activity log')
563
                    . '</a>.',
564
                    Alert::ERROR
565
                );
566
            }
567
        }
568
    }
569
570
    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...
571
    {
572
        if (!$author_id = $this->_context['id']) {
573
            redirect(SYMPHONY_URL . '/system/authors/');
574
        }
575
576
        $isOwner = ($author_id == Symphony::Author()->get('id'));
577
        $fields = $_POST['fields'];
578
        $this->_Author = AuthorManager::fetchByID($author_id);
579
580
        $canEdit = // Managers can edit all Authors, and their own.
581
                (Symphony::Author()->isManager() && $this->_Author->isAuthor())
582
                // Primary account can edit all accounts.
583
                || Symphony::Author()->isPrimaryAccount()
584
                // Developers can edit all developers, managers and authors, and their own,
585
                // but not the primary account
586
                || (Symphony::Author()->isDeveloper() && $this->_Author->isPrimaryAccount() === false);
587
588
        if (@array_key_exists('save', $_POST['action']) || @array_key_exists('done', $_POST['action'])) {
589
            $authenticated = false;
590
591
            if ($fields['email'] !== $this->_Author->get('email')) {
592
                $changing_email = true;
593
            }
594
595
            // Check the old password was correct
596
            if (isset($fields['old-password']) && strlen(trim($fields['old-password'])) > 0 && Cryptography::compare(Symphony::Database()->cleanValue(trim($fields['old-password'])), $this->_Author->get('password'))) {
597
                $authenticated = true;
598
599
                // Developers don't need to specify the old password, unless it's their own account
600
            } elseif (
601
                // All accounts can edit their own
602
                $isOwner ||
603
                // Is allowed to edit?
604
                $canEdit
605
            ) {
606
                $authenticated = true;
607
            }
608
609
            $this->_Author->set('id', $author_id);
610
611
            if ($this->_Author->isPrimaryAccount() || ($isOwner && Symphony::Author()->isDeveloper())) {
612
                $this->_Author->set('user_type', 'developer'); // Primary accounts are always developer, Developers can't lower their level
613
            } elseif ((Symphony::Author()->isDeveloper() || Symphony::Author()->isManager()) && isset($fields['user_type'])) {
614
                $this->_Author->set('user_type', $fields['user_type']); // Only developer can change user type
615
            }
616
617
            $this->_Author->set('email', $fields['email']);
618
            $this->_Author->set('username', General::sanitize($fields['username']));
619
            $this->_Author->set('first_name', General::sanitize($fields['first_name']));
620
            $this->_Author->set('last_name', General::sanitize($fields['last_name']));
621
            $this->_Author->set('language', isset($fields['language']) ? $fields['language'] : null);
622
623
            if (trim($fields['password']) !== '') {
624
                $this->_Author->set('password', Cryptography::hash(Symphony::Database()->cleanValue($fields['password'])));
625
                $changing_password = true;
626
            }
627
628
            // Don't allow authors to set the Section Index as a default area
629
            // If they had it previously set, just save `null` which will redirect
630
            // the Author (when logging in) to their own Author record
631
            if (
632
                $this->_Author->get('user_type') === 'author'
633
                && $fields['default_area'] === '/blueprints/sections/'
634
            ) {
635
                $this->_Author->set('default_area', null);
636
            } else {
637
                $this->_Author->set('default_area', $fields['default_area']);
638
            }
639
640
            $this->_Author->set('auth_token_active', ($fields['auth_token_active'] ? $fields['auth_token_active'] : 'no'));
641
642
            if ($this->_Author->validate($this->_errors)) {
643
                // Admin changing another profile
644 View Code Duplication
                if (!$isOwner) {
645
                    $entered_password = Symphony::Database()->cleanValue($fields['confirm-change-password']);
646
647
                    if (!isset($fields['confirm-change-password']) || empty($fields['confirm-change-password'])) {
648
                        $this->_errors['confirm-change-password'] = __('Please provide your own password to make changes to this author.');
649
                    } elseif (Cryptography::compare($entered_password, Symphony::Author()->get('password')) !== true) {
650
                        $this->_errors['confirm-change-password'] = __('Wrong password, please enter your own password to make changes to this author.');
651
                    }
652
                }
653
654
                // Author is changing their password
655
                if (!$authenticated && ($changing_password || $changing_email)) {
656
                    if ($changing_password) {
0 ignored issues
show
Bug introduced by
The variable $changing_password 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...
657
                        $this->_errors['old-password'] = __('Wrong password. Enter old password to change it.');
658
                    } elseif ($changing_email) {
0 ignored issues
show
Bug introduced by
The variable $changing_email 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...
659
                        $this->_errors['old-password'] = __('Wrong password. Enter old one to change email address.');
660
                    }
661
662
                    // Passwords provided, but doesn't match.
663
                } elseif (($fields['password'] !== '' || $fields['password-confirmation'] !== '') && $fields['password'] !== $fields['password-confirmation']) {
664
                    $this->_errors['password'] = $this->_errors['password-confirmation'] = __('Passwords did not match');
665
                }
666
667
                // All good, let's save the Author
668
                if (is_array($this->_errors) && empty($this->_errors) && $this->_Author->commit()) {
669
                    Symphony::Database()->delete('tbl_forgotpass', "`expiry` < ? OR `author_id` = ?", array(
670
                        DateTimeObj::getGMT('c'),
671
                        $author_id
672
                    ));
673
674
                    if ($isOwner) {
675
                        Administration::instance()->login($this->_Author->get('username'), $this->_Author->get('password'), true);
676
                    }
677
678
                    /**
679
                     * After editing an author, provided with the Author object
680
                     *
681
                     * @delegate AuthorPostEdit
682
                     * @since Symphony 2.2
683
                     * @param string $context
684
                     * '/system/authors/'
685
                     * @param Author $author
686
                     * An Author object
687
                     */
688
                    Symphony::ExtensionManager()->notifyMembers('AuthorPostEdit', '/system/authors/', array('author' => $this->_Author));
689
690
                    redirect(SYMPHONY_URL . '/system/authors/edit/' . $author_id . '/saved/');
691
692
                    // Problems.
693 View Code Duplication
                } else {
694
                    $this->pageAlert(
695
                        __('Unknown errors occurred while attempting to save.')
696
                        . '<a href="' . SYMPHONY_URL . '/system/log/">'
697
                        . __('Check your activity log')
698
                        . '</a>.',
699
                        Alert::ERROR
700
                    );
701
                }
702
            }
703
704
            // Author doesn't have valid data, throw back.
705 View Code Duplication
            if (is_array($this->_errors) && !empty($this->_errors)) {
706
                $this->pageAlert(__('There were some problems while attempting to save. Please check below for problem fields.'), Alert::ERROR);
707
            }
708
        } elseif (@array_key_exists('delete', $_POST['action'])) {
709
            // Validate rights
710
            if (!$canEdit) {
711
                $this->pageAlert(__('You are not allowed to delete this author.'), Alert::ERROR);
712
                return;
713
            }
714
            // Admin changing another profile
715 View Code Duplication
            if (!$isOwner) {
716
                $entered_password = Symphony::Database()->cleanValue($fields['confirm-change-password']);
717
718
                if (!isset($fields['confirm-change-password']) || empty($fields['confirm-change-password'])) {
719
                    $this->_errors['confirm-change-password'] = __('Please provide your own password to make changes to this author.');
720
                } elseif (Cryptography::compare($entered_password, Symphony::Author()->get('password')) !== true) {
721
                    $this->_errors['confirm-change-password'] = __('Wrong password, please enter your own password to make changes to this author.');
722
                }
723
            }
724 View Code Duplication
            if (is_array($this->_errors) && !empty($this->_errors)) {
725
                $this->pageAlert(__('There were some problems while attempting to save. Please check below for problem fields.'), Alert::ERROR);
726
                return;
727
            }
728
729
            /**
730
             * Prior to deleting an author, provided with the Author ID.
731
             *
732
             * @delegate AuthorPreDelete
733
             * @since Symphony 2.2
734
             * @param string $context
735
             * '/system/authors/'
736
             * @param integer $author_id
737
             *  The ID of Author ID that is about to be deleted
738
             */
739
            Symphony::ExtensionManager()->notifyMembers('AuthorPreDelete', '/system/authors/', array('author_id' => $author_id));
740
741
            if (!$isOwner) {
742
                AuthorManager::delete($author_id);
743
                redirect(SYMPHONY_URL . '/system/authors/');
744
            } else {
745
                $this->pageAlert(__('You cannot remove yourself as you are the active Author.'), Alert::ERROR);
746
            }
747
        }
748
    }
749
}
750