Passed
Push — v4 ( 89edfc...bc28ae )
by Benjamin
03:50
created

SettingsController   B

Complexity

Total Complexity 53

Size/Duplication

Total Lines 469
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 469
rs 7.4757
c 0
b 0
f 0
wmc 53

15 Methods

Rating   Name   Duplication   Size   Complexity  
A actionOauth() 0 7 1
C actionIndex() 0 60 11
B actionSites() 0 27 5
B actionViews() 0 26 5
B actionSaveSite() 0 25 2
A actionEditSite() 0 10 1
A getAccountOptions() 0 13 3
A getViewOptions() 0 13 3
A actionGetAccountExplorerData() 0 7 1
A getPropertyOptions() 0 13 3
A getAccountExplorerOptions() 0 8 1
A actionDeleteView() 0 11 1
B actionSaveSettings() 0 28 3
C actionSaveView() 0 49 8
B actionEditView() 0 29 5

How to fix   Complexity   

Complex Class

Complex classes like SettingsController often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use SettingsController, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * @link      https://dukt.net/craft/analytics/
4
 * @copyright Copyright (c) 2018, Dukt
5
 * @license   https://dukt.net/craft/analytics/docs/license
6
 */
7
8
namespace dukt\analytics\controllers;
9
10
use Craft;
11
use craft\errors\InvalidPluginException;
12
use craft\web\Controller;
13
use dukt\analytics\models\SiteView;
14
use dukt\analytics\models\View;
15
use dukt\analytics\web\assets\settings\SettingsAsset;
16
use dukt\analytics\Plugin as Analytics;
17
use Exception;
18
use Google_Service_Exception;
19
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
20
use yii\web\NotFoundHttpException;
21
use yii\web\Response;
22
23
class SettingsController extends Controller
24
{
25
    // Public Methods
26
    // =========================================================================
27
28
    /**
29
     * Index.
30
     *
31
     * @return Response
32
     * @throws \yii\base\InvalidConfigException
33
     */
34
    public function actionIndex(): Response
35
    {
36
        $isOauthProviderConfigured = Analytics::$plugin->getAnalytics()->isOauthProviderConfigured();
37
38
        if ($isOauthProviderConfigured) {
39
            $errors = [];
40
41
            try {
42
                $provider = Analytics::$plugin->oauth->getOauthProvider();
43
                $token = Analytics::$plugin->oauth->getToken();
44
45
                if ($token) {
46
                    $oauthAccount = Analytics::$plugin->cache->get(['getAccount', $token]);
47
48
                    if (!$oauthAccount) {
49
                        $oauthAccount = $provider->getResourceOwner($token);
50
                        Analytics::$plugin->cache->set(['getAccount', $token], $oauthAccount);
51
                    }
52
53
                    if ($oauthAccount) {
54
                        Craft::info("Account:\r\n".print_r($oauthAccount, true), __METHOD__);
55
56
                        $plugin = Craft::$app->getPlugins()->getPlugin('analytics');
57
                        $settings = $plugin->getSettings();
58
                    }
59
                }
60
            } catch (Google_Service_Exception $e) {
61
                Craft::info('Couldn’t get OAuth account: '.$e->getMessage(), __METHOD__);
62
63
                foreach ($e->getErrors() as $error) {
64
                    $errors[] = $error['message'];
65
                }
66
            } catch (IdentityProviderException $e) {
67
                $error = $e->getMessage();
68
                $data = $e->getResponseBody();
69
70
                if (isset($data['error_description'])) {
71
                    $error = $data['error_description'];
72
                }
73
74
                $errors[] = $error;
75
            } catch (Exception $e) {
76
                if (method_exists($e, 'getResponse')) {
77
                    Craft::info('Couldn’t get OAuth account: '.$e->getResponse(), __METHOD__);
78
                } else {
79
                    Craft::info('Couldn’t get OAuth account: '.$e->getMessage(), __METHOD__);
80
                }
81
82
                $errors[] = $e->getMessage();
83
            }
84
        }
85
86
        Craft::$app->getView()->registerAssetBundle(SettingsAsset::class);
87
88
        return $this->renderTemplate('analytics/settings/_index', [
89
            'isOauthProviderConfigured' => $isOauthProviderConfigured,
90
            'errors' => $errors ?? null,
91
            'oauthAccount' => $oauthAccount ?? null,
92
            'settings' => $settings ?? null,
93
            'googleIconUrl' => Craft::$app->assetManager->getPublishedUrl('@dukt/analytics/icons/google.svg', true),
94
        ]);
95
    }
96
97
    /**
98
     * OAuth Settings.
99
     *
100
     * @return Response
101
     * @throws \craft\errors\SiteNotFoundException
102
     */
103
    public function actionOauth(): Response
104
    {
105
        return $this->renderTemplate('analytics/settings/_oauth', [
106
            'javascriptOrigin' => Analytics::$plugin->oauth->getJavascriptOrigin(),
107
            'redirectUri' => Analytics::$plugin->oauth->getRedirectUri(),
108
            'googleIconUrl' => Craft::$app->assetManager->getPublishedUrl('@dukt/analytics/icons/google.svg', true),
109
            'settings' => Analytics::$plugin->getSettings(),
110
        ]);
111
    }
112
113
    /**
114
     * Saves the settings.
115
     *
116
     * @return null|Response
117
     * @throws InvalidPluginException
118
     * @throws \yii\base\InvalidConfigException
119
     * @throws \yii\web\BadRequestHttpException
120
     */
121
    public function actionSaveSettings()
122
    {
123
        $this->requirePostRequest();
124
125
        $pluginHandle = Craft::$app->getRequest()->getRequiredBodyParam('pluginHandle');
126
        $settings = Craft::$app->getRequest()->getBodyParam('settings');
127
        $plugin = Craft::$app->getPlugins()->getPlugin($pluginHandle);
0 ignored issues
show
Bug introduced by
It seems like $pluginHandle can also be of type array; however, parameter $handle of craft\services\Plugins::getPlugin() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

127
        $plugin = Craft::$app->getPlugins()->getPlugin(/** @scrutinizer ignore-type */ $pluginHandle);
Loading history...
128
129
        if (!$plugin) {
130
            throw new InvalidPluginException($pluginHandle);
0 ignored issues
show
Bug introduced by
It seems like $pluginHandle can also be of type array; however, parameter $handle of craft\errors\InvalidPluginException::__construct() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

130
            throw new InvalidPluginException(/** @scrutinizer ignore-type */ $pluginHandle);
Loading history...
131
        }
132
133
        $settings = Analytics::$plugin->getApis()->getAnalytics()->populateAccountExplorerSettings($settings);
0 ignored issues
show
Bug introduced by
It seems like $settings can also be of type string; however, parameter $settings of dukt\analytics\apis\Anal...countExplorerSettings() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

133
        $settings = Analytics::$plugin->getApis()->getAnalytics()->populateAccountExplorerSettings(/** @scrutinizer ignore-type */ $settings);
Loading history...
134
135
        if (Craft::$app->getPlugins()->savePluginSettings($plugin, $settings)) {
136
            Craft::$app->getSession()->setNotice(Craft::t('analytics', 'Plugin settings saved.'));
137
138
            return $this->redirectToPostedUrl();
139
        }
140
141
        Craft::$app->getSession()->setError(Craft::t('analytics', 'Couldn’t save plugin settings.'));
142
143
        // Send the plugin back to the template
144
        Craft::$app->getUrlManager()->setRouteParams([
145
            'plugin' => $plugin
146
        ]);
147
148
        return null;
149
    }
150
151
    /**
152
     * Returns the account explorer data.
153
     *
154
     * @return Response
155
     * @throws \yii\base\InvalidConfigException
156
     */
157
    public function actionGetAccountExplorerData(): Response
158
    {
159
        $accountExplorerData = Analytics::$plugin->getApis()->getAnalytics()->getAccountExplorerData();
160
161
        Analytics::$plugin->cache->set(['accountExplorerData'], $accountExplorerData);
162
163
        return $this->asJson($accountExplorerData);
164
    }
165
166
    /**
167
     * Views index.
168
     *
169
     * @return Response
170
     * @throws \yii\base\InvalidConfigException
171
     */
172
    public function actionViews(): Response
173
    {
174
        $isOauthProviderConfigured = Analytics::$plugin->getAnalytics()->isOauthProviderConfigured();
175
176
        $variables = [
177
            'isConnected' => false
178
        ];
179
180
        try {
181
            $token = Analytics::$plugin->oauth->getToken();
182
183
            if ($isOauthProviderConfigured && $token) {
184
                $variables['isConnected'] = true;
185
                $variables['reportingViews'] = Analytics::$plugin->getViews()->getViews();
186
            }
187
        } catch (IdentityProviderException $e) {
188
            $variables['error'] = $e->getMessage();
189
190
            $data = $e->getResponseBody();
191
192
            if (isset($data['error_description'])) {
193
                $variables['error'] = $data['error_description'];
194
            }
195
        }
196
197
        return $this->renderTemplate('analytics/settings/views/_index', $variables);
198
    }
199
200
    /**
201
     * Edit a view.
202
     *
203
     * @param int|null  $viewId
204
     * @param View|null $reportingView
205
     *
206
     * @return Response
207
     * @throws NotFoundHttpException
208
     * @throws \yii\base\InvalidConfigException
209
     */
210
    public function actionEditView(int $viewId = null, View $reportingView = null): Response
211
    {
212
        $variables['isNewView'] = false;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$variables was never initialized. Although not strictly required by PHP, it is generally a good practice to add $variables = array(); before regardless.
Loading history...
213
214
        if ($viewId !== null) {
215
            if ($reportingView === null) {
216
                $reportingView = Analytics::$plugin->getViews()->getViewById($viewId);
217
218
                if (!$reportingView) {
219
                    throw new NotFoundHttpException('View not found');
220
                }
221
            }
222
223
            $variables['title'] = $reportingView->name;
224
            $variables['reportingView'] = $reportingView;
225
        } else {
226
            if ($reportingView === null) {
227
                $reportingView = new View();
228
                $variables['isNewView'] = true;
229
            }
230
            $variables['title'] = Craft::t('analytics', 'Create a new view');
231
        }
232
233
        $variables['reportingView'] = $reportingView;
234
        $variables['accountExplorerOptions'] = $this->getAccountExplorerOptions($reportingView);
235
236
        Craft::$app->getView()->registerAssetBundle(SettingsAsset::class);
237
238
        return $this->renderTemplate('analytics/settings/views/_edit', $variables);
239
    }
240
241
    /**
242
     * Saves a view.
243
     *
244
     * @return null|Response
245
     * @throws \dukt\analytics\errors\InvalidViewException
246
     * @throws \yii\base\InvalidConfigException
247
     * @throws \yii\web\BadRequestHttpException
248
     */
249
    public function actionSaveView()
250
    {
251
        $this->requirePostRequest();
252
253
        $request = Craft::$app->getRequest();
254
        $accountExplorer = $request->getBodyParam('accountExplorer');
255
256
        $reportingView = new View();
257
        $reportingView->id = $request->getBodyParam('viewId');
258
        $reportingView->name = $request->getBodyParam('name');
0 ignored issues
show
Documentation Bug introduced by
It seems like $request->getBodyParam('name') can also be of type array. However, the property $name is declared as type string. 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...
259
        $reportingView->gaAccountId = $accountExplorer['account'];
260
        $reportingView->gaPropertyId = $accountExplorer['property'];
261
        $reportingView->gaViewId = $accountExplorer['view'];
262
263
        $accountExplorerData = Analytics::$plugin->getApis()->getAnalytics()->getAccountExplorerData();
264
265
        foreach ($accountExplorerData['accounts'] as $dataAccount) {
266
            if ($dataAccount->id == $reportingView->gaAccountId) {
267
                $reportingView->gaAccountName = $dataAccount->name;
268
            }
269
        }
270
271
        foreach ($accountExplorerData['properties'] as $dataProperty) {
272
            if ($dataProperty->id == $reportingView->gaPropertyId) {
273
                $reportingView->gaPropertyName = $dataProperty->name;
274
            }
275
        }
276
        foreach ($accountExplorerData['views'] as $dataView) {
277
            if ($dataView->id == $reportingView->gaViewId) {
278
                $reportingView->gaViewName = $dataView->name;
279
                $reportingView->gaViewCurrency = $dataView->currency;
280
            }
281
        }
282
283
        // Save it
284
        if (!Analytics::$plugin->getViews()->saveView($reportingView)) {
285
            Craft::$app->getSession()->setError(Craft::t('analytics', 'Couldn’t save the view.'));
286
287
            // Send the view back to the template
288
            Craft::$app->getUrlManager()->setRouteParams([
289
                'reportingView' => $reportingView
290
            ]);
291
292
            return null;
293
        }
294
295
        Craft::$app->getSession()->setNotice(Craft::t('analytics', 'View saved.'));
296
297
        return $this->redirectToPostedUrl($reportingView);
298
    }
299
300
    /**
301
     * Deletes a view.
302
     *
303
     * @return Response
304
     * @throws \Throwable
305
     * @throws \yii\db\StaleObjectException
306
     * @throws \yii\web\BadRequestHttpException
307
     */
308
    public function actionDeleteView(): Response
309
    {
310
        $this->requirePostRequest();
311
        $this->requireAcceptsJson();
312
313
        $request = Craft::$app->getRequest();
314
        $viewId = $request->getRequiredBodyParam('id');
315
316
        Analytics::$plugin->getViews()->deleteViewById($viewId);
317
318
        return $this->asJson(['success' => true]);
319
    }
320
321
    /**
322
     * Sites index.
323
     *
324
     * @return Response
325
     * @throws \yii\base\InvalidConfigException
326
     */
327
    public function actionSites(): Response
328
    {
329
        $isOauthProviderConfigured = Analytics::$plugin->getAnalytics()->isOauthProviderConfigured();
330
331
        $variables = [
332
            'isConnected' => false
333
        ];
334
335
        try {
336
            $token = Analytics::$plugin->oauth->getToken();
337
338
            if ($isOauthProviderConfigured && $token) {
339
                $variables['isConnected'] = true;
340
                $variables['sites'] = Craft::$app->getSites()->getAllSites();
341
                $variables['siteViews'] = Analytics::$plugin->getViews()->getSiteViews();
342
            }
343
        } catch (IdentityProviderException $e) {
344
            $variables['error'] = $e->getMessage();
345
346
            $data = $e->getResponseBody();
347
348
            if (isset($data['error_description'])) {
349
                $variables['error'] = $data['error_description'];
350
            }
351
        }
352
353
        return $this->renderTemplate('analytics/settings/sites/_index', $variables);
354
    }
355
356
    /**
357
     * Edit a site.
358
     *
359
     * @param $siteId
360
     *
361
     * @return Response
362
     * @throws \yii\base\InvalidConfigException
363
     */
364
    public function actionEditSite($siteId): Response
365
    {
366
        $site = Craft::$app->getSites()->getSiteById($siteId);
367
        $siteView = Analytics::$plugin->getViews()->getSiteViewBySiteId($siteId);
368
        $reportingViews = Analytics::$plugin->getViews()->getViews();
369
370
        return $this->renderTemplate('analytics/settings/sites/_edit', [
371
            'site' => $site,
372
            'siteView' => $siteView,
373
            'reportingViews' => $reportingViews,
374
        ]);
375
    }
376
377
    /**
378
     * Saves a site.
379
     *
380
     * @return null|Response
381
     * @throws \yii\base\InvalidConfigException
382
     * @throws \yii\db\Exception
383
     * @throws \yii\web\BadRequestHttpException
384
     */
385
    public function actionSaveSite()
386
    {
387
        $this->requirePostRequest();
388
389
        $request = Craft::$app->getRequest();
390
391
        $siteView = new SiteView();
392
        $siteView->siteId = $request->getBodyParam('siteId');
393
        $siteView->viewId = $request->getBodyParam('viewId');
394
395
        // Save it
396
        if (!Analytics::$plugin->getViews()->saveSiteView($siteView)) {
397
            Craft::$app->getSession()->setError(Craft::t('analytics', 'Couldn’t save the site view.'));
398
399
            // Send the view back to the template
400
            Craft::$app->getUrlManager()->setRouteParams([
401
                'siteView' => $siteView
402
            ]);
403
404
            return null;
405
        }
406
407
        Craft::$app->getSession()->setNotice(Craft::t('analytics', 'Site view saved.'));
408
409
        return $this->redirectToPostedUrl($siteView);
410
    }
411
412
    // Private Methods
413
    // =========================================================================
414
415
    /**
416
     * @param View $reportingView
417
     *
418
     * @return array
419
     */
420
    private function getAccountExplorerOptions(View $reportingView): array
421
    {
422
        $accountExplorerData = Analytics::$plugin->cache->get(['accountExplorerData']);
423
424
        return [
425
            'accounts' => $this->getAccountOptions($accountExplorerData, $reportingView),
426
            'properties' => $this->getPropertyOptions($accountExplorerData, $reportingView),
427
            'views' => $this->getViewOptions($accountExplorerData, $reportingView),
428
        ];
429
    }
430
431
    /**
432
     * @param      $accountExplorerData
433
     * @param View $reportingView
434
     *
435
     * @return array
436
     */
437
    private function getAccountOptions($accountExplorerData, View $reportingView): array
438
    {
439
        $accountOptions = [];
440
441
        if (isset($accountExplorerData['accounts'])) {
442
            foreach ($accountExplorerData['accounts'] as $account) {
443
                $accountOptions[] = ['label' => $account['name'], 'value' => $account['id']];
444
            }
445
        } else {
446
            $accountOptions[] = ['label' => $reportingView->gaAccountName, 'value' => $reportingView->gaAccountId];
447
        }
448
449
        return $accountOptions;
450
    }
451
452
    /**
453
     * @param      $accountExplorerData
454
     * @param View $reportingView
455
     *
456
     * @return array
457
     */
458
    private function getPropertyOptions($accountExplorerData, View $reportingView): array
459
    {
460
        $propertyOptions = [];
461
462
        if (isset($accountExplorerData['properties'])) {
463
            foreach ($accountExplorerData['properties'] as $webProperty) {
464
                $propertyOptions[] = ['label' => $webProperty['name'], 'value' => $webProperty['id']];
465
            }
466
        } else {
467
            $propertyOptions[] = ['label' => $reportingView->gaPropertyName, 'value' => $reportingView->gaPropertyId];
468
        }
469
470
        return $propertyOptions;
471
    }
472
473
    /**
474
     * @param      $accountExplorerData
475
     * @param View $reportingView
476
     *
477
     * @return array
478
     */
479
    private function getViewOptions($accountExplorerData, View $reportingView): array
480
    {
481
        $viewOptions = [];
482
483
        if (isset($accountExplorerData['views'])) {
484
            foreach ($accountExplorerData['views'] as $dataView) {
485
                $viewOptions[] = ['label' => $dataView['name'], 'value' => $dataView['id']];
486
            }
487
        } else {
488
            $viewOptions[] = ['label' => $reportingView->gaViewName, 'value' => $reportingView->gaViewId];
489
        }
490
491
        return $viewOptions;
492
    }
493
}