Passed
Push — master ( 758032...380927 )
by Benjamin
28:34 queued 21:24
created

Reports::getAreaReport()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 44
Code Lines 33

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 33
nc 2
nop 1
dl 0
loc 44
rs 8.8571
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\services;
9
10
use Craft;
11
use craft\helpers\StringHelper;
12
use dukt\analytics\errors\InvalidElementException;
13
use dukt\analytics\models\ReportRequestCriteria;
14
use yii\base\Component;
15
use dukt\analytics\Plugin as Analytics;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, dukt\analytics\services\Analytics. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
16
use \Google_Service_AnalyticsReporting_Report;
17
18
class Reports extends Component
19
{
20
    // Public Methods
21
    // =========================================================================
22
23
    /**
24
     * Returns a realtime report.
25
     *
26
     * @param array $request
27
     *
28
     * @return array
29
     * @throws \yii\base\InvalidConfigException
30
     */
31
    public function getRealtimeReport(array $request)
32
    {
33
        $view = Analytics::$plugin->getViews()->getViewById($request['viewId']);
34
35
        $tableId = null;
36
37
        if ($view) {
38
            $tableId = 'ga:'.$view->gaViewId;
39
        }
40
41
        $metrics = $request['metrics'];
42
        $optParams = $request['optParams'];
43
44
        $cacheId = ['reports.getRealtimeReport', $tableId, $metrics, $optParams];
45
        $response = Analytics::$plugin->cache->get($cacheId);
46
47
        if (!$response) {
48
            $response = Analytics::$plugin->getApis()->getAnalytics()->getService()->data_realtime->get($tableId, $metrics, $optParams);
49
50
            $cacheDuration = Analytics::$plugin->getSettings()->realtimeRefreshInterval;
51
            Analytics::$plugin->cache->set($cacheId, $response, $cacheDuration);
52
        }
53
54
        return (array)$response;
55
    }
56
57
    /**
58
     * Get e-commerce report.
59
     *
60
     * @param $viewId
61
     * @param $period
62
     *
63
     * @return array
64
     */
65
    public function getEcommerceReport($viewId, $period)
66
    {
67
        $startDate = '7daysAgo';
68
        $endDate = 'today';
69
        $dimensions = 'ga:date';
70
71
        switch ($period) {
72
            case 'week':
73
                $startDate = '7daysAgo';
74
                break;
75
            case 'month':
76
                $startDate = '30daysAgo';
77
                break;
78
            case 'year':
79
                $startDate = '365daysAgo';
80
                $dimensions = 'ga:yearMonth';
81
                break;
82
        }
83
84
        $metrics = 'ga:transactionRevenue,ga:revenuePerTransaction,ga:transactions,ga:transactionsPerSession';
85
86
        $criteria = new ReportRequestCriteria;
87
        $criteria->viewId = $viewId;
88
        $criteria->startDate = $startDate;
89
        $criteria->endDate = $endDate;
90
        $criteria->metrics = $metrics;
91
        $criteria->dimensions = $dimensions;
0 ignored issues
show
Documentation Bug introduced by
It seems like $dimensions of type string is incompatible with the declared type array of property $dimensions.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
92
        $criteria->includeEmptyRows = true;
93
94
        $reportResponse = Analytics::$plugin->getApis()->getAnalyticsReporting()->getReport($criteria);
95
        $report = $reportResponse->toSimpleObject();
96
        $reportData = $this->parseReportingReport($reportResponse);
0 ignored issues
show
Bug introduced by
It seems like $reportResponse can also be of type array; however, parameter $_report of dukt\analytics\services\...:parseReportingReport() does only seem to accept Google_Service_AnalyticsReporting_Report, 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

96
        $reportData = $this->parseReportingReport(/** @scrutinizer ignore-type */ $reportResponse);
Loading history...
97
98
        $view = Analytics::$plugin->getViews()->getViewById($viewId);
99
100
        return [
101
            'period' => $startDate.' - '.$endDate,
102
            'totalRevenue' => $report->data->totals[0]->values[0],
103
            'totalRevenuePerTransaction' => $report->data->totals[0]->values[1],
104
            'totalTransactions' => $report->data->totals[0]->values[2],
105
            'totalTransactionsPerSession' => $report->data->totals[0]->values[3],
106
            'reportData' => [
107
                'view' => $view->name,
108
                'chart' => $reportData,
109
                'period' => $period,
110
                'periodLabel' => Craft::t('analytics', 'This '.$period)
111
            ],
112
        ];
113
    }
114
115
    /**
116
     * Returns an element report.
117
     *
118
     * @param int      $elementId
119
     * @param int|null $siteId
120
     * @param string   $metric
121
     *
122
     * @return array
123
     * @throws \Exception
124
     */
125
    public function getElementReport($elementId, $siteId, $metric)
126
    {
127
        $uri = Analytics::$plugin->getAnalytics()->getElementUrlPath($elementId, $siteId);
128
129
        if (!$uri) {
130
            throw new InvalidElementException("Element doesn't support URLs.", 1);
131
        }
132
133
        if ($uri === '__home__') {
134
            $uri = '';
135
        }
136
137
        $siteView = Analytics::$plugin->getViews()->getSiteViewBySiteId($siteId);
138
139
        $viewId = null;
140
141
        if ($siteView) {
142
            $viewId = $siteView->viewId;
143
        }
144
145
        $startDate = date('Y-m-d', strtotime('-1 month'));
146
        $endDate = date('Y-m-d');
147
        $dimensions = 'ga:date';
148
        $metrics = $metric;
149
        $filters = 'ga:pagePath=='.$uri;
150
151
        $request = [
152
            'viewId' => $viewId,
153
            'startDate' => $startDate,
154
            'endDate' => $endDate,
155
            'metrics' => $metrics,
156
            'dimensions' => $dimensions,
157
            'filters' => $filters
158
        ];
159
160
        $cacheId = ['reports.getElementReport', $request];
161
        $response = Analytics::$plugin->cache->get($cacheId);
162
163
        if (!$response) {
164
165
            $criteria = new ReportRequestCriteria;
166
            $criteria->viewId = $viewId;
167
            $criteria->startDate = $startDate;
168
            $criteria->endDate = $endDate;
169
            $criteria->metrics = $metrics;
170
            $criteria->dimensions = $dimensions;
0 ignored issues
show
Documentation Bug introduced by
It seems like $dimensions of type string is incompatible with the declared type array of property $dimensions.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
171
            $criteria->filtersExpression = $filters;
172
173
            $reportResponse = Analytics::$plugin->getApis()->getAnalyticsReporting()->getReport($criteria);
174
            $response = $this->parseReportingReport($reportResponse);
0 ignored issues
show
Bug introduced by
It seems like $reportResponse can also be of type array; however, parameter $_report of dukt\analytics\services\...:parseReportingReport() does only seem to accept Google_Service_AnalyticsReporting_Report, 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

174
            $response = $this->parseReportingReport(/** @scrutinizer ignore-type */ $reportResponse);
Loading history...
175
176
            if ($response) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $response of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
177
                Analytics::$plugin->cache->set($cacheId, $response);
178
            }
179
        }
180
181
        return $response;
182
    }
183
184
    /**
185
     * Returns an area report.
186
     *
187
     * @param array $request
188
     *
189
     * @return array
190
     * @throws \yii\base\InvalidConfigException
191
     */
192
    public function getAreaReport(array $request)
193
    {
194
        $viewId = ($request['viewId'] ?? null);
195
        $period = ($request['period'] ?? null);
196
        $metricString = ($request['options']['metric'] ?? null);
197
198
        switch ($period) {
199
            case 'year':
200
                $dimensionString = 'ga:yearMonth';
201
                $startDate = date('Y-m-01', strtotime('-1 '.$period));
202
                $endDate = date('Y-m-d');
203
                break;
204
205
            default:
206
                $dimensionString = 'ga:date';
207
                $startDate = date('Y-m-d', strtotime('-1 '.$period));
208
                $endDate = date('Y-m-d');
209
        }
210
211
        $criteria = new ReportRequestCriteria;
212
        $criteria->viewId = $viewId;
213
        $criteria->startDate = $startDate;
214
        $criteria->endDate = $endDate;
215
        $criteria->metrics = $metricString;
216
        $criteria->dimensions = $dimensionString;
0 ignored issues
show
Documentation Bug introduced by
It seems like $dimensionString of type string is incompatible with the declared type array of property $dimensions.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
217
        $criteria->orderBys = [
218
            ['fieldName' => $dimensionString, 'orderType' => 'VALUE', 'sortOrder' => 'ASCENDING']
219
        ];
220
221
        $reportResponse = Analytics::$plugin->getApis()->getAnalyticsReporting()->getReport($criteria);
222
        $report = $this->parseReportingReport($reportResponse);
0 ignored issues
show
Bug introduced by
It seems like $reportResponse can also be of type array; however, parameter $_report of dukt\analytics\services\...:parseReportingReport() does only seem to accept Google_Service_AnalyticsReporting_Report, 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

222
        $report = $this->parseReportingReport(/** @scrutinizer ignore-type */ $reportResponse);
Loading history...
223
224
        $total = $report['totals'][0];
225
226
        $view = Analytics::$plugin->getViews()->getViewById($viewId);
227
228
        return [
229
            'view' => $view->name,
230
            'type' => 'area',
231
            'chart' => $report,
232
            'total' => $total,
233
            'metric' => Craft::t('analytics', Analytics::$plugin->metadata->getDimMet($metricString)),
234
            'period' => $period,
235
            'periodLabel' => Craft::t('analytics', 'This '.$period)
236
        ];
237
    }
238
239
    /**
240
     * Returns a counter report.
241
     *
242
     * @param array $request
243
     *
244
     * @return array
245
     * @throws \yii\base\InvalidConfigException
246
     */
247
    public function getCounterReport(array $request)
248
    {
249
        $viewId = ($request['viewId'] ?? null);
250
        $period = ($request['period'] ?? null);
251
        $metricString = ($request['options']['metric'] ?? null);
252
        $startDate = date('Y-m-d', strtotime('-1 '.$period));
253
        $endDate = date('Y-m-d');
254
255
        $criteria = new ReportRequestCriteria;
256
        $criteria->viewId = $viewId;
257
        $criteria->startDate = $startDate;
258
        $criteria->endDate = $endDate;
259
        $criteria->metrics = $metricString;
260
261
262
        $reportResponse = Analytics::$plugin->getApis()->getAnalyticsReporting()->getReport($criteria);
263
        $report = $this->parseReportingReport($reportResponse);
0 ignored issues
show
Bug introduced by
It seems like $reportResponse can also be of type array; however, parameter $_report of dukt\analytics\services\...:parseReportingReport() does only seem to accept Google_Service_AnalyticsReporting_Report, 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

263
        $report = $this->parseReportingReport(/** @scrutinizer ignore-type */ $reportResponse);
Loading history...
264
265
        $total = 0;
266
267
        if (!empty($report['totals'][0])) {
268
            $total = $report['totals'][0];
269
        }
270
271
        $counter = [
272
            'type' => $report['cols'][0]['type'],
273
            'value' => $total,
274
            'label' => StringHelper::toLowerCase(Craft::t('analytics', Analytics::$plugin->metadata->getDimMet($metricString)))
275
        ];
276
277
        $view = Analytics::$plugin->getViews()->getViewById($viewId);
278
279
        return [
280
            'view' => $view->name,
281
            'type' => 'counter',
282
            'counter' => $counter,
283
            'response' => $report,
284
            'metric' => Craft::t('analytics', Analytics::$plugin->metadata->getDimMet($metricString)),
285
            'period' => $period,
286
            'periodLabel' => Craft::t('analytics', 'this '.$period)
287
        ];
288
    }
289
290
    /**
291
     * Returns a pie report.
292
     *
293
     * @param array $request
294
     *
295
     * @return array
296
     * @throws \yii\base\InvalidConfigException
297
     */
298
    public function getPieReport(array $request)
299
    {
300
        $viewId = ($request['viewId'] ?? null);
301
        $period = ($request['period'] ?? null);
302
        $dimensionString = ($request['options']['dimension'] ?? null);
303
        $metricString = ($request['options']['metric'] ?? null);
304
        $startDate = date('Y-m-d', strtotime('-1 '.$period));
305
        $endDate = date('Y-m-d');
306
307
        $criteria = new ReportRequestCriteria;
308
        $criteria->viewId = $viewId;
309
        $criteria->startDate = $startDate;
310
        $criteria->endDate = $endDate;
311
        $criteria->metrics = $metricString;
312
        $criteria->dimensions = $dimensionString;
313
314
        $reportResponse = Analytics::$plugin->getApis()->getAnalyticsReporting()->getReport($criteria);
315
        $report = $this->parseReportingReport($reportResponse);
0 ignored issues
show
Bug introduced by
It seems like $reportResponse can also be of type array; however, parameter $_report of dukt\analytics\services\...:parseReportingReport() does only seem to accept Google_Service_AnalyticsReporting_Report, 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

315
        $report = $this->parseReportingReport(/** @scrutinizer ignore-type */ $reportResponse);
Loading history...
316
317
        $view = Analytics::$plugin->getViews()->getViewById($viewId);
318
319
        return [
320
            'view' => $view->name,
321
            'type' => 'pie',
322
            'chart' => $report,
323
            'dimension' => Craft::t('analytics', Analytics::$plugin->metadata->getDimMet($dimensionString)),
324
            'metric' => Craft::t('analytics', Analytics::$plugin->metadata->getDimMet($metricString)),
325
            'period' => $period,
326
            'periodLabel' => Craft::t('analytics', 'this '.$period)
327
        ];
328
    }
329
330
    /**
331
     * Returns a table report.
332
     *
333
     * @param array $request
334
     *
335
     * @return array
336
     * @throws \yii\base\InvalidConfigException
337
     */
338
    public function getTableReport(array $request)
339
    {
340
        $viewId = ($request['viewId'] ?? null);
341
342
        $period = ($request['period'] ?? null);
343
        $dimensionString = ($request['options']['dimension'] ?? null);
344
        $metricString = ($request['options']['metric'] ?? null);
345
346
        $criteria = new ReportRequestCriteria;
347
        $criteria->viewId = $viewId;
348
        $criteria->dimensions = $dimensionString;
349
        $criteria->metrics = $metricString;
350
        $criteria->startDate = date('Y-m-d', strtotime('-1 '.$period));
351
        $criteria->endDate = date('Y-m-d');
352
353
        $reportResponse = Analytics::$plugin->getApis()->getAnalyticsReporting()->getReport($criteria);
354
        $report = $this->parseReportingReport($reportResponse);
0 ignored issues
show
Bug introduced by
It seems like $reportResponse can also be of type array; however, parameter $_report of dukt\analytics\services\...:parseReportingReport() does only seem to accept Google_Service_AnalyticsReporting_Report, 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

354
        $report = $this->parseReportingReport(/** @scrutinizer ignore-type */ $reportResponse);
Loading history...
355
356
        $view = Analytics::$plugin->getViews()->getViewById($viewId);
357
358
        return [
359
            'view' => $view->name,
360
            'type' => 'table',
361
            'chart' => $report,
362
            'dimension' => Craft::t('analytics', Analytics::$plugin->metadata->getDimMet($dimensionString)),
363
            'metric' => Craft::t('analytics', Analytics::$plugin->metadata->getDimMet($metricString)),
364
            'period' => $period,
365
            'periodLabel' => Craft::t('analytics', 'This '.$period)
366
        ];
367
    }
368
369
    /**
370
     * Returns a geo report.
371
     *
372
     * @param array $request
373
     *
374
     * @return array
375
     * @throws \yii\base\InvalidConfigException
376
     */
377
    public function getGeoReport(array $request)
378
    {
379
        $viewId = ($request['viewId'] ?? null);
380
        $period = ($request['period'] ?? null);
381
        $dimensionString = ($request['options']['dimension'] ?? null);
382
        $metricString = ($request['options']['metric'] ?? null);
383
384
        $originDimension = $dimensionString;
385
386
        if ($dimensionString === 'ga:city') {
387
            $dimensionString = 'ga:latitude,ga:longitude,'.$dimensionString;
388
        }
389
390
        $criteria = new ReportRequestCriteria;
391
        $criteria->viewId = $viewId;
392
        $criteria->dimensions = $dimensionString;
393
        $criteria->metrics = $metricString;
394
        $criteria->startDate = date('Y-m-d', strtotime('-1 '.$period));
395
        $criteria->endDate = date('Y-m-d');
396
397
        $reportResponse = Analytics::$plugin->getApis()->getAnalyticsReporting()->getReport($criteria);
398
        $report = $this->parseReportingReport($reportResponse);
0 ignored issues
show
Bug introduced by
It seems like $reportResponse can also be of type array; however, parameter $_report of dukt\analytics\services\...:parseReportingReport() does only seem to accept Google_Service_AnalyticsReporting_Report, 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

398
        $report = $this->parseReportingReport(/** @scrutinizer ignore-type */ $reportResponse);
Loading history...
399
400
        $view = Analytics::$plugin->getViews()->getViewById($viewId);
401
402
        return [
403
            'view' => $view->name,
404
            'type' => 'geo',
405
            'chart' => $report,
406
            'dimensionRaw' => $originDimension,
407
            'dimension' => Craft::t('analytics', Analytics::$plugin->metadata->getDimMet($originDimension)),
408
            'metric' => Craft::t('analytics', Analytics::$plugin->metadata->getDimMet($metricString)),
409
            'period' => $period,
410
            'periodLabel' => Craft::t('analytics', 'This '.$period)
411
        ];
412
    }
413
414
    // Private Methods
415
    // =========================================================================
416
417
    /**
418
     * @param Google_Service_AnalyticsReporting_Report $_report
419
     *
420
     * @return array
421
     */
422
    private function parseReportingReport(Google_Service_AnalyticsReporting_Report $_report)
423
    {
424
        $columnHeader = $_report->getColumnHeader();
425
        $columnHeaderDimensions = $columnHeader->getDimensions();
426
        $metricHeaderEntries = $columnHeader->getMetricHeader()->getMetricHeaderEntries();
427
428
429
        // Columns
430
431
        $cols = [];
432
433
        if ($columnHeaderDimensions) {
434
            foreach ($columnHeaderDimensions as $columnHeaderDimension) {
435
436
                $id = $columnHeaderDimension;
437
                $label = Analytics::$plugin->metadata->getDimMet($columnHeaderDimension);
438
439
                switch ($columnHeaderDimension) {
440
                    case 'ga:date':
441
                    case 'ga:yearMonth':
442
                        $type = 'date';
443
                        break;
444
445
                    case 'ga:continent':
446
                        $type = 'continent';
447
                        break;
448
                    case 'ga:subContinent':
449
                        $type = 'subContinent';
450
                        break;
451
452
                    case 'ga:latitude':
453
                    case 'ga:longitude':
454
                        $type = 'float';
455
                        break;
456
457
                    default:
458
                        $type = 'string';
459
                }
460
461
                $col = [
462
                    'type' => $type,
463
                    'label' => Craft::t('analytics', $label),
464
                    'id' => $id,
465
                ];
466
467
                array_push($cols, $col);
468
            }
469
        }
470
471
        foreach ($metricHeaderEntries as $metricHeaderEntry) {
472
            $label = Analytics::$plugin->metadata->getDimMet($metricHeaderEntry['name']);
473
474
            $col = [
475
                'type' => strtolower($metricHeaderEntry['type']),
476
                'label' => Craft::t('analytics', $label),
477
                'id' => $metricHeaderEntry['name'],
478
            ];
479
480
            array_push($cols, $col);
481
        }
482
483
484
        // Rows
485
486
        $rows = [];
487
488
        foreach ($_report->getData()->getRows() as $_row) {
489
490
            $colIndex = 0;
491
            $row = [];
492
493
            $dimensions = $_row->getDimensions();
494
495
            if ($dimensions) {
496
                foreach ($dimensions as $_dimension) {
497
498
                    $value = $_dimension;
499
500
                    if ($columnHeaderDimensions) {
501
                        if (isset($columnHeaderDimensions[$colIndex])) {
502
                            switch ($columnHeaderDimensions[$colIndex]) {
503
                                case 'ga:continent':
504
                                    $value = Analytics::$plugin->metadata->getContinentCode($value);
505
                                    break;
506
                                case 'ga:subContinent':
507
                                    $value = Analytics::$plugin->metadata->getSubContinentCode($value);
508
                                    break;
509
                            }
510
                        }
511
                    }
512
513
                    array_push($row, $value);
514
515
                    $colIndex++;
516
                }
517
            }
518
519
            foreach ($_row->getMetrics() as $_metric) {
520
                array_push($row, $_metric->getValues()[0]);
521
                $colIndex++;
522
            }
523
524
            array_push($rows, $row);
525
        }
526
527
        $totals = $_report->getData()->getTotals()[0]->getValues();
528
529
        return [
530
            'cols' => $cols,
531
            'rows' => $rows,
532
            'totals' => $totals
533
        ];
534
    }
535
}
536