SettingsController   B
last analyzed

Complexity

Total Complexity 32

Size/Duplication

Total Lines 482
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 15

Test Coverage

Coverage 0%

Importance

Changes 1
Bugs 1 Features 0
Metric Value
wmc 32
c 1
b 1
f 0
lcom 1
cbo 15
dl 0
loc 482
ccs 0
cts 273
cp 0
rs 8.8

16 Methods

Rating   Name   Duplication   Size   Complexity  
A init() 0 8 1
B index() 0 42 6
A github() 0 18 2
A email() 0 19 2
A build() 0 18 2
A basic() 0 17 2
A authentication() 0 19 2
B githubCallback() 0 29 3
A storeSettings() 0 12 2
B getGithubForm() 0 38 3
A getEmailForm() 0 69 1
A getGithubUser() 0 7 1
A canWriteConfig() 0 4 1
B getBuildForm() 0 30 1
B getBasicForm() 0 24 1
B getAuthenticationForm() 0 29 2
1
<?php
2
/**
3
 * PHPCI - Continuous Integration for PHP.
4
 *
5
 * @copyright    Copyright 2014, Block 8 Limited.
6
 * @license      https://github.com/Block8/PHPCI/blob/master/LICENSE.md
7
 *
8
 * @link         https://www.phptesting.org/
9
 */
10
11
namespace PHPCI\Controller;
12
13
use b8;
14
use b8\Form;
15
use b8\HttpClient;
16
use PHPCI\Controller;
17
use PHPCI\Helper\Lang;
18
use Symfony\Component\Yaml\Dumper;
19
use Symfony\Component\Yaml\Parser;
20
21
/**
22
 * Settings Controller.
23
 *
24
 * @author       Dan Cryer <[email protected]>
25
 */
26
class SettingsController extends Controller
27
{
28
    /**
29
     * @var array
30
     */
31
    protected $settings;
32
33
    /**
34
     * Initialise the controller, set up stores and services.
35
     */
36
    public function init()
37
    {
38
        parent::init();
39
40
        $parser = new Parser();
41
        $yaml = file_get_contents(PHPCI_CONFIG_FILE);
42
        $this->settings = $parser->parse($yaml);
0 ignored issues
show
Documentation Bug introduced by
It seems like $parser->parse($yaml) can also be of type string or object<stdClass>. However, the property $settings is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

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

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
43
    }
44
45
    /**
46
     * Display settings forms.
47
     *
48
     * @return string
49
     */
50
    public function index()
51
    {
52
        $this->requireAdmin();
53
54
        $this->layout->title = Lang::get('settings');
55
56
        $this->view->settings = $this->settings;
57
58
        $basicSettings = array();
59
        if (isset($this->settings['phpci']['basic'])) {
60
            $basicSettings = $this->settings['phpci']['basic'];
61
        }
62
63
        $buildSettings = array();
64
        if (isset($this->settings['phpci']['build'])) {
65
            $buildSettings = $this->settings['phpci']['build'];
66
        }
67
68
        $emailSettings = array();
69
        if (isset($this->settings['phpci']['email_settings'])) {
70
            $emailSettings = $this->settings['phpci']['email_settings'];
71
        }
72
73
        $authSettings = array();
74
        if (isset($this->settings['phpci']['authentication_settings'])) {
75
            $authSettings = $this->settings['phpci']['authentication_settings'];
76
        }
77
78
        $this->view->configFile = PHPCI_CONFIG_FILE;
79
        $this->view->basicSettings = $this->getBasicForm($basicSettings);
80
        $this->view->buildSettings = $this->getBuildForm($buildSettings);
81
        $this->view->github = $this->getGithubForm();
82
        $this->view->emailSettings = $this->getEmailForm($emailSettings);
83
        $this->view->authenticationSettings = $this->getAuthenticationForm($authSettings);
84
        $this->view->isWriteable = $this->canWriteConfig();
85
86
        if (!empty($this->settings['phpci']['github']['token'])) {
87
            $this->view->githubUser = $this->getGithubUser($this->settings['phpci']['github']['token']);
88
        }
89
90
        return $this->view->render();
91
    }
92
93
    /**
94
     * Save Github settings.
95
     */
96
    public function github()
97
    {
98
        $this->requireAdmin();
99
100
        $this->settings['phpci']['github']['id'] = $this->getParam('githubid', '');
101
        $this->settings['phpci']['github']['secret'] = $this->getParam('githubsecret', '');
102
        $error = $this->storeSettings();
103
104
        $response = new b8\Http\Response\RedirectResponse();
105
106
        if ($error) {
107
            $response->setHeader('Location', PHPCI_URL.'settings?saved=2');
108
        } else {
109
            $response->setHeader('Location', PHPCI_URL.'settings?saved=1');
110
        }
111
112
        return $response;
113
    }
114
115
    /**
116
     * Save email settings.
117
     */
118
    public function email()
119
    {
120
        $this->requireAdmin();
121
122
        $this->settings['phpci']['email_settings'] = $this->getParams();
123
        $this->settings['phpci']['email_settings']['smtp_encryption'] = $this->getParam('smtp_encryption', 0);
124
125
        $error = $this->storeSettings();
126
127
        $response = new b8\Http\Response\RedirectResponse();
128
129
        if ($error) {
130
            $response->setHeader('Location', PHPCI_URL.'settings?saved=2');
131
        } else {
132
            $response->setHeader('Location', PHPCI_URL.'settings?saved=1');
133
        }
134
135
        return $response;
136
    }
137
138
    /**
139
     * Save build settings.
140
     */
141
    public function build()
142
    {
143
        $this->requireAdmin();
144
145
        $this->settings['phpci']['build'] = $this->getParams();
146
147
        $error = $this->storeSettings();
148
149
        $response = new b8\Http\Response\RedirectResponse();
150
151
        if ($error) {
152
            $response->setHeader('Location', PHPCI_URL.'settings?saved=2');
153
        } else {
154
            $response->setHeader('Location', PHPCI_URL.'settings?saved=1');
155
        }
156
157
        return $response;
158
    }
159
160
    /**
161
     * Save basic settings.
162
     */
163
    public function basic()
164
    {
165
        $this->requireAdmin();
166
167
        $this->settings['phpci']['basic'] = $this->getParams();
168
        $error = $this->storeSettings();
169
170
        $response = new b8\Http\Response\RedirectResponse();
171
172
        if ($error) {
173
            $response->setHeader('Location', PHPCI_URL.'settings?saved=2');
174
        } else {
175
            $response->setHeader('Location', PHPCI_URL.'settings?saved=1');
176
        }
177
178
        return $response;
179
    }
180
181
    /**
182
     * Handle authentication settings.
183
     */
184
    public function authentication()
0 ignored issues
show
Coding Style introduced by
authentication uses the super-global variable $_SESSION 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...
185
    {
186
        $this->requireAdmin();
187
188
        $this->settings['phpci']['authentication_settings']['state'] = $this->getParam('disable_authentication', 0);
189
        $this->settings['phpci']['authentication_settings']['user_id'] = $_SESSION['phpci_user_id'];
190
191
        $error = $this->storeSettings();
192
193
        $response = new b8\Http\Response\RedirectResponse();
194
195
        if ($error) {
196
            $response->setHeader('Location', PHPCI_URL.'settings?saved=2');
197
        } else {
198
            $response->setHeader('Location', PHPCI_URL.'settings?saved=1');
199
        }
200
201
        return $response;
202
    }
203
204
    /**
205
     * Github redirects users back to this URL when t.
206
     */
207
    public function githubCallback()
208
    {
209
        $code = $this->getParam('code', null);
210
        $github = $this->settings['phpci']['github'];
211
212
        if (!is_null($code)) {
213
            $http = new HttpClient();
214
            $url = 'https://github.com/login/oauth/access_token';
215
            $params = array('client_id' => $github['id'], 'client_secret' => $github['secret'], 'code' => $code);
216
            $resp = $http->post($url, $params);
217
218
            if ($resp['success']) {
219
                parse_str($resp['body'], $resp);
220
221
                $this->settings['phpci']['github']['token'] = $resp['access_token'];
222
                $this->storeSettings();
223
224
                $response = new b8\Http\Response\RedirectResponse();
225
                $response->setHeader('Location', PHPCI_URL.'settings?linked=1');
226
227
                return $response;
228
            }
229
        }
230
231
        $response = new b8\Http\Response\RedirectResponse();
232
        $response->setHeader('Location', PHPCI_URL.'settings?linked=2');
233
234
        return $response;
235
    }
236
237
    /**
238
     * Convert config to yaml and store to file.
239
     *
240
     * @return mixed
241
     */
242
    protected function storeSettings()
243
    {
244
        $dumper = new Dumper();
245
        $yaml = $dumper->dump($this->settings, 4);
246
        file_put_contents(PHPCI_CONFIG_FILE, $yaml);
247
248
        if (error_get_last()) {
249
            $error_get_last = error_get_last();
250
251
            return $error_get_last['message'];
252
        }
253
    }
254
255
    /**
256
     * Get the Github settings form.
257
     *
258
     * @return Form
259
     */
260
    protected function getGithubForm()
261
    {
262
        $form = new Form();
263
        $form->setMethod('POST');
264
        $form->setAction(PHPCI_URL.'settings/github');
265
        $form->addField(new Form\Element\Csrf('csrf'));
266
267
        $field = new Form\Element\Text('githubid');
268
        $field->setRequired(true);
269
        $field->setPattern('[a-zA-Z0-9]+');
270
        $field->setLabel(Lang::get('application_id'));
271
        $field->setClass('form-control');
272
        $field->setContainerClass('form-group');
273
        $form->addField($field);
274
275
        if (isset($this->settings['phpci']['github']['id'])) {
276
            $field->setValue($this->settings['phpci']['github']['id']);
277
        }
278
279
        $field = new Form\Element\Text('githubsecret');
280
        $field->setRequired(true);
281
        $field->setPattern('[a-zA-Z0-9]+');
282
        $field->setLabel(Lang::get('application_secret'));
283
        $field->setClass('form-control');
284
        $field->setContainerClass('form-group');
285
        $form->addField($field);
286
287
        if (isset($this->settings['phpci']['github']['secret'])) {
288
            $field->setValue($this->settings['phpci']['github']['secret']);
289
        }
290
291
        $field = new Form\Element\Submit();
292
        $field->setValue(Lang::get('save'));
293
        $field->setClass('btn btn-success pull-right');
294
        $form->addField($field);
295
296
        return $form;
297
    }
298
299
    /**
300
     * Get the email settings form.
301
     *
302
     * @param array $values
303
     *
304
     * @return Form
305
     */
306
    protected function getEmailForm($values = array())
307
    {
308
        $form = new Form();
309
        $form->setMethod('POST');
310
        $form->setAction(PHPCI_URL.'settings/email');
311
        $form->addField(new Form\Element\Csrf('csrf'));
312
313
        $field = new Form\Element\Text('smtp_address');
314
        $field->setRequired(false);
315
        $field->setLabel(Lang::get('smtp_server'));
316
        $field->setClass('form-control');
317
        $field->setContainerClass('form-group');
318
        $field->setValue('localhost');
319
        $form->addField($field);
320
321
        $field = new Form\Element\Text('smtp_port');
322
        $field->setRequired(false);
323
        $field->setPattern('[0-9]+');
324
        $field->setLabel(Lang::get('smtp_port'));
325
        $field->setClass('form-control');
326
        $field->setContainerClass('form-group');
327
        $field->setValue(25);
328
        $form->addField($field);
329
330
        $field = new Form\Element\Text('smtp_username');
331
        $field->setRequired(false);
332
        $field->setLabel(Lang::get('smtp_username'));
333
        $field->setClass('form-control');
334
        $field->setContainerClass('form-group');
335
        $form->addField($field);
336
337
        $field = new Form\Element\Password('smtp_password');
338
        $field->setRequired(false);
339
        $field->setLabel(Lang::get('smtp_password'));
340
        $field->setClass('form-control');
341
        $field->setContainerClass('form-group');
342
        $form->addField($field);
343
344
        $field = new Form\Element\Email('from_address');
345
        $field->setRequired(false);
346
        $field->setLabel(Lang::get('from_email_address'));
347
        $field->setClass('form-control');
348
        $field->setContainerClass('form-group');
349
        $form->addField($field);
350
351
        $field = new Form\Element\Email('default_mailto_address');
352
        $field->setRequired(false);
353
        $field->setLabel(Lang::get('default_notification_address'));
354
        $field->setClass('form-control');
355
        $field->setContainerClass('form-group');
356
        $form->addField($field);
357
358
        $field = new Form\Element\Select('smtp_encryption');
359
        $field->setOptions(array('' => Lang::get('none'), 'tls' => Lang::get('tls'), 'ssl' => Lang::get('ssl')));
360
        $field->setRequired(false);
361
        $field->setLabel(Lang::get('use_smtp_encryption'));
362
        $field->setContainerClass('form-group');
363
        $field->setValue(1);
364
        $form->addField($field);
365
366
        $field = new Form\Element\Submit();
367
        $field->setValue(Lang::get('save'));
368
        $field->setClass('btn btn-success pull-right');
369
        $form->addField($field);
370
371
        $form->setValues($values);
372
373
        return $form;
374
    }
375
376
    /**
377
     * Call Github API for our Github user object.
378
     *
379
     * @param $token
380
     *
381
     * @return mixed
382
     */
383
    protected function getGithubUser($token)
384
    {
385
        $http = new HttpClient('https://api.github.com');
386
        $user = $http->get('/user', array('access_token' => $token));
387
388
        return $user['body'];
389
    }
390
391
    /**
392
     * Check if we can write the PHPCI config file.
393
     *
394
     * @return bool
395
     */
396
    protected function canWriteConfig()
397
    {
398
        return is_writeable(PHPCI_CONFIG_FILE);
399
    }
400
401
    /**
402
     * Get the Build settings form.
403
     *
404
     * @param array $values
405
     *
406
     * @return Form
407
     */
408
    protected function getBuildForm($values = array())
409
    {
410
        $form = new Form();
411
        $form->setMethod('POST');
412
        $form->setAction(PHPCI_URL.'settings/build');
413
414
        $field = new Form\Element\Select('failed_after');
415
        $field->setRequired(false);
416
        $field->setLabel(Lang::get('failed_after'));
417
        $field->setClass('form-control');
418
        $field->setContainerClass('form-group');
419
        $field->setOptions(array(
420
            300 => Lang::get('5_mins'),
421
            900 => Lang::get('15_mins'),
422
            1800 => Lang::get('30_mins'),
423
            3600 => Lang::get('1_hour'),
424
            10800 => Lang::get('3_hours'),
425
        ));
426
        $field->setValue(1800);
427
        $form->addField($field);
428
429
        $field = new Form\Element\Submit();
430
        $field->setValue(Lang::get('save'));
431
        $field->setClass('btn btn-success pull-right');
432
        $form->addField($field);
433
434
        $form->setValues($values);
435
436
        return $form;
437
    }
438
439
    /**
440
     * Get the Basic settings form.
441
     *
442
     * @param array $values
443
     *
444
     * @return Form
445
     */
446
    protected function getBasicForm($values = array())
447
    {
448
        $form = new Form();
449
        $form->setMethod('POST');
450
        $form->setAction(PHPCI_URL.'settings/basic');
451
452
        $field = new Form\Element\Select('language');
453
        $field->setRequired(true);
454
        $field->setLabel(Lang::get('language'));
455
        $field->setClass('form-control');
456
        $field->setContainerClass('form-group');
457
        $field->setOptions(Lang::getLanguageOptions());
458
        $field->setValue(Lang::getLanguage());
459
        $form->addField($field);
460
461
        $field = new Form\Element\Submit();
462
        $field->setValue(Lang::get('save'));
463
        $field->setClass('btn btn-success pull-right');
464
        $form->addField($field);
465
466
        $form->setValues($values);
467
468
        return $form;
469
    }
470
471
    /**
472
     * Form for disabling user authentication while using a default user.
473
     *
474
     * @param array $values
475
     *
476
     * @return Form
477
     */
478
    protected function getAuthenticationForm($values = array())
479
    {
480
        $form = new Form();
481
        $form->setMethod('POST');
482
        $form->setAction(PHPCI_URL.'settings/authentication');
483
        $form->addField(new Form\Element\Csrf('csrf'));
484
485
        $field = new Form\Element\Checkbox('disable_authentication');
486
        $field->setCheckedValue(1);
487
        $field->setRequired(false);
488
        $field->setLabel('Disable Authentication?');
489
        $field->setContainerClass('form-group');
490
        $field->setValue(0);
491
492
        if (isset($values['state'])) {
493
            $field->setValue((int) $values['state']);
494
        }
495
496
        $form->addField($field);
497
498
        $field = new Form\Element\Submit();
499
        $field->setValue('Save &raquo;');
500
        $field->setClass('btn btn-success pull-right');
501
        $form->addField($field);
502
503
        $form->setValues($values);
504
505
        return $form;
506
    }
507
}
508