ReportsController::getRealtimeDemoResponse()   A
last analyzed

Complexity

Conditions 4
Paths 5

Size

Total Lines 34
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 20
c 1
b 0
f 0
nc 5
nop 0
dl 0
loc 34
rs 9.6
1
<?php
2
/**
3
 * @link      https://dukt.net/analytics/
4
 * @copyright Copyright (c) 2022, Dukt
5
 * @license   https://github.com/dukt/analytics/blob/master/LICENSE.md
6
 */
7
8
namespace dukt\analytics\controllers;
9
10
use Craft;
11
use craft\web\Controller;
12
use dukt\analytics\errors\InvalidChartTypeException;
13
use dukt\analytics\Plugin as Analytics;
14
use yii\web\Response;
15
16
class ReportsController extends Controller
17
{
18
    // Public Methods
19
    // =========================================================================
20
21
    /**
22
     * E-commerce Report
23
     *
24
     * @return null
25
     * @throws \Google_Service_Exception
26
     * @throws \yii\base\InvalidConfigException
27
     */
28
    public function actionEcommerceWidget()
29
    {
30
        if (Analytics::getInstance()->getAnalytics()->demoMode) {
31
            return $this->getEcommerceDemoResponse();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getEcommerceDemoResponse() returns the type craft\web\Response which is incompatible with the documented return type null.
Loading history...
32
        }
33
34
        $viewId = Craft::$app->getRequest()->getBodyParam('viewId');
35
        $period = Craft::$app->getRequest()->getBodyParam('period');
36
37
        try {
38
            $response = Analytics::$plugin->getReports()->getEcommerceReport($viewId, $period);
39
        } catch(\Google_Service_Exception $e) {
40
            return $this->handleGoogleServiceException($e);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->handleGoogleServiceException($e) returns the type craft\web\Response which is incompatible with the documented return type null.
Loading history...
41
        }
42
43
        return $this->asJson($response);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->asJson($response) returns the type craft\web\Response which is incompatible with the documented return type null.
Loading history...
44
    }
45
46
    /**
47
     * Get element report.
48
     *
49
     * @return Response
50
     * @throws \Google_Service_Exception
51
     * @throws \yii\base\InvalidConfigException
52
     * @throws \yii\web\BadRequestHttpException
53
     */
54
    public function actionElement()
55
    {
56
        $elementId = Craft::$app->getRequest()->getRequiredParam('elementId');
57
        $siteId = (int)Craft::$app->getRequest()->getRequiredParam('siteId');
58
        $metric = Craft::$app->getRequest()->getRequiredParam('metric');
59
60
        try {
61
            $response = Analytics::$plugin->getReports()->getElementReport($elementId, $siteId, $metric);
62
        } catch(\Google_Service_Exception $e) {
63
            return $this->handleGoogleServiceException($e);
64
        }
65
66
        return $this->asJson([
67
            'type' => 'area',
68
            'chart' => $response
69
        ]);
70
    }
71
72
    /**
73
     * Get realtime widget report.
74
     *
75
     * @return Response
76
     * @throws \Google_Exception
77
     * @throws \yii\base\InvalidConfigException
78
     */
79
    public function actionRealtimeWidget()
80
    {
81
        if (Analytics::getInstance()->getAnalytics()->demoMode) {
82
            return $this->getRealtimeDemoResponse();
83
        }
84
85
86
        // Active users
87
88
        $activeUsers = 0;
89
90
        $viewId = Craft::$app->getRequest()->getBodyParam('viewId');
91
92
        $request = [
93
            'viewId' => $viewId,
94
            'metrics' => 'ga:activeVisitors',
95
            'optParams' => []
96
        ];
97
98
        try {
99
            $response = Analytics::$plugin->getReports()->getRealtimeReport($request);
100
        } catch(\Google_Service_Exception $e) {
101
            return $this->handleGoogleServiceException($e);
102
        }
103
104
        if (!empty($response['totalsForAllResults']) && isset($response['totalsForAllResults']['ga:activeVisitors'])) {
105
            $activeUsers = $response['totalsForAllResults']['ga:activeVisitors'];
106
        }
107
108
109
        // Pageviews
110
111
        $pageviewsRequest = [
112
            'viewId' => $viewId,
113
            'metrics' => 'rt:pageviews',
114
            'optParams' => ['dimensions' => 'rt:minutesAgo']
115
        ];
116
117
        $pageviews = Analytics::$plugin->getReports()->getRealtimeReport($pageviewsRequest);
118
119
120
        // Active pages
121
122
        $activePagesRequest = [
123
            'viewId' => $viewId,
124
            'metrics' => 'rt:activeUsers',
125
            'optParams' => ['dimensions' => 'rt:pagePath', 'max-results' => 5]
126
        ];
127
128
        $activePages = Analytics::$plugin->getReports()->getRealtimeReport($activePagesRequest);
129
130
        return $this->asJson([
131
            'activeUsers' => $activeUsers,
132
            'pageviews' => $pageviews,
133
            'activePages' => $activePages,
134
        ]);
135
    }
136
137
    /**
138
     * Get report widget report.
139
     *
140
     * @return Response
141
     * @throws InvalidChartTypeException
142
     * @throws \Google_Service_Exception
143
     * @throws \yii\base\InvalidConfigException
144
     */
145
    public function actionReportWidget()
146
    {
147
        $viewId = Craft::$app->getRequest()->getBodyParam('viewId');
148
        $chart = Craft::$app->getRequest()->getBodyParam('chart');
149
        $period = Craft::$app->getRequest()->getBodyParam('period');
150
        $options = Craft::$app->getRequest()->getBodyParam('options');
151
152
        $request = [
153
            'viewId' => $viewId,
154
            'chart' => $chart,
155
            'period' => $period,
156
            'options' => $options,
157
        ];
158
159
        $cacheId = ['getReport', $request];
160
161
        try {
162
            $response = Analytics::$plugin->cache->get($cacheId);
163
164
            if (!$response) {
165
                switch ($chart) {
166
                    case 'area':
167
                        $response = Analytics::$plugin->getReports()->getAreaReport($request);
168
                        break;
169
                    case 'counter':
170
                        $response = Analytics::$plugin->getReports()->getCounterReport($request);
171
                        break;
172
                    case 'pie':
173
                        $response = Analytics::$plugin->getReports()->getPieReport($request);
174
                        break;
175
                    case 'table':
176
                        $response = Analytics::$plugin->getReports()->getTableReport($request);
177
                        break;
178
                    case 'geo':
179
                        $response = Analytics::$plugin->getReports()->getGeoReport($request);
180
                        break;
181
                    default:
182
                        throw new InvalidChartTypeException('Chart type `'.$chart.'` not supported.');
183
                }
184
185
                if ($response) {
186
                    Analytics::$plugin->cache->set($cacheId, $response);
187
                }
188
            }
189
190
191
            return $this->asJson($response);
192
        } catch(\Google_Service_Exception $e) {
193
            return $this->handleGoogleServiceException($e);
194
        }
195
    }
196
197
    // Private Methods
198
    // =========================================================================
199
200
    /**
201
     * Handle Google service exception.
202
     *
203
     * @param \Google_Service_Exception $e
204
     * @return Response
205
     * @throws \Google_Service_Exception
206
     */
207
    private function handleGoogleServiceException(\Google_Service_Exception $e): Response
208
    {
209
        $errors = $e->getErrors();
210
211
        if(empty($errors)) {
212
            throw $e;
213
        }
214
215
        Craft::error("Couldn’t generate Report widget’s report: \r\n".print_r($errors, true)."\r\n".$e->getTraceAsString(), __METHOD__);
0 ignored issues
show
Bug introduced by
Are you sure print_r($errors, true) of type string|true can be used in concatenation? ( Ignorable by Annotation )

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

215
        Craft::error("Couldn’t generate Report widget’s report: \r\n"./** @scrutinizer ignore-type */ print_r($errors, true)."\r\n".$e->getTraceAsString(), __METHOD__);
Loading history...
216
217
        return $this->asErrorJson($errors[0]['message']);
218
    }
219
220
    /**
221
     * Get realtime demo response.
222
     *
223
     * @return Response
224
     * @throws \yii\base\InvalidConfigException
225
     */
226
    private function getRealtimeDemoResponse(): Response
227
    {
228
        if (Analytics::$plugin->getAnalytics()->demoMode === 'test') {
229
            return $this->getRealtimeDemoTestResponse();
230
        }
231
232
        $pageviews = [
233
            'rows' => []
234
        ];
235
236
        for ($i = 0; $i <= 30; $i++) {
237
            $pageviews['rows'][] = [$i, random_int(0, 20)];
238
        }
239
240
        $activePages = [
241
            'rows' => [
242
                ['/a-new-toga/', random_int(1, 20)],
243
                ['/parka-with-stripes-on-back/', random_int(1, 20)],
244
                ['/romper-for-a-red-eye/', random_int(1, 20)],
245
                ['/the-fleece-awakens/', random_int(1, 20)],
246
                ['/the-last-knee-high/', random_int(1, 20)],
247
            ]
248
        ];
249
250
        $activeUsers = 0;
251
252
        foreach ($activePages['rows'] as $row) {
253
            $activeUsers += $row[1];
254
        }
255
256
        return $this->asJson([
257
            'activeUsers' => $activeUsers,
258
            'pageviews' => $pageviews,
259
            'activePages' => $activePages,
260
        ]);
261
    }
262
263
    /**
264
     * Get realtime demo test response.
265
     *
266
     * @return Response
267
     * @throws \Exception
268
     */
269
    private function getRealtimeDemoTestResponse(): Response
270
    {
271
        $pageviews = [
272
            'rows' => []
273
        ];
274
275
        for ($i = 0; $i <= 30; $i++) {
276
            $pageviews['rows'][] = [$i, random_int(0, 20)];
277
        }
278
279
        $activePages = [
280
            'rows' => [
281
                ['/some-url/', random_int(1, 20)],
282
                ['/some-super-long-url/with-kebab-case/', random_int(1, 20)],
283
                ['/somesuperlongurlwithoutkebabcasebutstillsuperlong/', random_int(10000000, 20000000)],
284
                ['/someothersuperlongurl/withoutkebabcasebutstillsuperlong/', random_int(1, 20)],
285
                ['/one-last-url/', random_int(1, 20)],
286
            ]
287
        ];
288
289
        $activeUsers = 0;
290
291
        foreach ($activePages['rows'] as $row) {
292
            $activeUsers += $row[1];
293
        }
294
295
        return $this->asJson([
296
            'activeUsers' => $activeUsers,
297
            'pageviews' => $pageviews,
298
            'activePages' => $activePages,
299
        ]);
300
    }
301
302
    /**
303
     * @return Response
304
     * @throws \Exception
305
     */
306
    private function getEcommerceDemoResponse(): Response
307
    {
308
        $date = new \DateTime();
309
        $date = $date->modify('-12 months');
310
        $rows = [];
311
312
        for ($i = 1; $i <= 12; $i++) {
313
            $rows[] = [
314
                $date->format('Ym'),
315
                random_int(50000, 150000)
316
            ];
317
318
            $date->modify('+1 month');
319
        }
320
321
        $reportData = [
322
            'chart' => [
323
                'cols' => [
324
                    [
325
                        'id' => 'ga:yearMonth',
326
                        'label' => 'Month of Year',
327
                        'type' => 'date',
328
                    ],
329
                    [
330
                        'id' => 'ga:transactionRevenue',
331
                        'label' => 'Revenue',
332
                        'type' => 'currency',
333
                    ],
334
                ],
335
                'rows' => $rows,
336
                'totals' => [
337
                    [
338
                        '11385.0',
339
                        '97.3076923076923',
340
                    ]
341
                ],
342
            ],
343
            'period' => 'year',
344
            'periodLabel' => 'This year',
345
            'view' => 'Craft Shop',
346
        ];
347
348
        $totalRevenue = 0;
349
350
        foreach($rows as $row) {
351
            $totalRevenue += $row[1];
352
        }
353
354
        $totalTransactions = random_int(3400, 3800);
355
        $totalRevenuePerTransaction = $totalRevenue / $totalTransactions;
356
        $totalTransactionsPerSession = 8.291991495393338;
357
358
        return $this->asJson([
359
            'period' =>  '365daysAgo - today',
360
            'reportData' => $reportData,
361
            'totalRevenue' => $totalRevenue,
362
            'totalRevenuePerTransaction' => $totalRevenuePerTransaction,
363
            'totalTransactions' => $totalTransactions,
364
            'totalTransactionsPerSession' => $totalTransactionsPerSession,
365
        ]);
366
    }
367
}
368