Passed
Push — v4 ( ee4d75...958f8a )
by Benjamin
05:17
created

SettingsController::actionEditView()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 29
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 17
nc 5
nop 2
dl 0
loc 29
rs 8.439
c 0
b 0
f 0
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
     * @param null $plugin
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $plugin is correct as it would always require null to be passed?
Loading history...
32
     *
33
     * @return Response
34
     * @throws \craft\errors\SiteNotFoundException
35
     * @throws \yii\base\InvalidConfigException
36
     */
37
    public function actionIndex($plugin = null): Response
38
    {
39
        $isOauthProviderConfigured = Analytics::$plugin->getAnalytics()->isOauthProviderConfigured();
40
41
        if ($isOauthProviderConfigured) {
42
            $errors = [];
43
44
            try {
45
                if (!$plugin) {
46
                    $plugin = Craft::$app->getPlugins()->getPlugin('analytics');
47
                }
48
49
                $provider = Analytics::$plugin->oauth->getOauthProvider();
50
                $token = Analytics::$plugin->oauth->getToken();
51
52
                if ($token) {
53
                    $oauthAccount = Analytics::$plugin->cache->get(['getAccount', $token]);
54
55
                    if (!$oauthAccount) {
56
                        $oauthAccount = $provider->getResourceOwner($token);
57
                        Analytics::$plugin->cache->set(['getAccount', $token], $oauthAccount);
58
                    }
59
60
                    if ($oauthAccount) {
61
                        Craft::info("Account:\r\n".print_r($oauthAccount, true), __METHOD__);
62
63
                        $settings = $plugin->getSettings();
64
                    }
65
                }
66
            } catch (Google_Service_Exception $e) {
67
                Craft::info('Couldn’t get OAuth account: '.$e->getMessage(), __METHOD__);
68
69
                foreach ($e->getErrors() as $error) {
70
                    $errors[] = $error['message'];
71
                }
72
            } catch (IdentityProviderException $e) {
73
                $error = $e->getMessage();
74
75
                $data = $e->getResponseBody();
76
77
                if (isset($data['error_description'])) {
78
                    $error = $data['error_description'];
79
                }
80
81
                $errors[] = $error;
82
            } catch (Exception $e) {
83
                if (method_exists($e, 'getResponse')) {
84
                    Craft::info('Couldn’t get OAuth account: '.$e->getResponse(), __METHOD__);
85
                } else {
86
                    Craft::info('Couldn’t get OAuth account: '.$e->getMessage(), __METHOD__);
87
                }
88
89
                $errors[] = $e->getMessage();
90
            }
91
        }
92
93
        $token = ($token ?? null);
94
95
        Craft::$app->getView()->registerAssetBundle(SettingsAsset::class);
96
97
        return $this->renderTemplate('analytics/settings/_index', [
98
            'isOauthProviderConfigured' => $isOauthProviderConfigured,
99
100
            'errors' => $errors ?? null,
101
            'oauthAccount' => $oauthAccount ?? null,
102
            'provider' => $provider ?? null,
103
            'settings' => $settings ?? null,
104
            'token' => $token ?? null,
105
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
        ]);
110
    }
111
112
    /**
113
     * OAuth Settings.
114
     *
115
     * @return Response
116
     * @throws \craft\errors\SiteNotFoundException
117
     */
118
    public function actionOauth(): Response
119
    {
120
        return $this->renderTemplate('analytics/settings/_oauth', [
121
            'javascriptOrigin' => Analytics::$plugin->oauth->getJavascriptOrigin(),
122
            'redirectUri' => Analytics::$plugin->oauth->getRedirectUri(),
123
            'googleIconUrl' => Craft::$app->assetManager->getPublishedUrl('@dukt/analytics/icons/google.svg', true),
124
            'settings' => Analytics::$plugin->getSettings(),
125
        ]);
126
    }
127
128
    /**
129
     * Saves the settings.
130
     *
131
     * @return null|Response
132
     * @throws InvalidPluginException
133
     * @throws \yii\base\InvalidConfigException
134
     * @throws \yii\web\BadRequestHttpException
135
     */
136
    public function actionSaveSettings()
137
    {
138
        $this->requirePostRequest();
139
140
        $pluginHandle = Craft::$app->getRequest()->getRequiredBodyParam('pluginHandle');
141
        $settings = Craft::$app->getRequest()->getBodyParam('settings');
142
143
        $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

143
        $plugin = Craft::$app->getPlugins()->getPlugin(/** @scrutinizer ignore-type */ $pluginHandle);
Loading history...
144
145
        if (!$plugin) {
146
            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

146
            throw new InvalidPluginException(/** @scrutinizer ignore-type */ $pluginHandle);
Loading history...
147
        }
148
149
        $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

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