Passed
Push — v4 ( aa6f20...5e2fe5 )
by Benjamin
09:22 queued 04:16
created

Reports   A

Complexity

Total Complexity 35

Size/Duplication

Total Lines 457
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 457
rs 9
c 0
b 0
f 0
wmc 35

8 Methods

Rating   Name   Duplication   Size   Complexity  
B getElementReport() 0 57 6
D parseReportingReport() 0 111 18
B getRealtimeReport() 0 24 3
B getAreaReport() 0 44 2
B getPieReport() 0 29 1
B getCounterReport() 0 40 2
B getTableReport() 0 28 1
B getGeoReport() 0 34 2
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
     * Returns an element report.
59
     *
60
     * @param int      $elementId
61
     * @param int|null $siteId
62
     * @param string   $metric
63
     *
64
     * @return array
65
     * @throws \Exception
66
     */
67
    public function getElementReport($elementId, $siteId, $metric)
68
    {
69
        $uri = Analytics::$plugin->getAnalytics()->getElementUrlPath($elementId, $siteId);
70
71
        if (!$uri) {
72
            throw new InvalidElementException("Element doesn't support URLs.", 1);
73
        }
74
75
        if ($uri === '__home__') {
76
            $uri = '';
77
        }
78
79
        $siteView = Analytics::$plugin->getViews()->getSiteViewBySiteId($siteId);
80
81
        $viewId = null;
82
83
        if ($siteView) {
84
            $viewId = $siteView->viewId;
85
        }
86
87
        $startDate = date('Y-m-d', strtotime('-1 month'));
88
        $endDate = date('Y-m-d');
89
        $dimensions = 'ga:date';
90
        $metrics = $metric;
91
        $filters = 'ga:pagePath=='.$uri;
92
93
        $request = [
94
            'viewId' => $viewId,
95
            'startDate' => $startDate,
96
            'endDate' => $endDate,
97
            'metrics' => $metrics,
98
            'dimensions' => $dimensions,
99
            'filters' => $filters
100
        ];
101
102
        $cacheId = ['reports.getElementReport', $request];
103
        $response = Analytics::$plugin->cache->get($cacheId);
104
105
        if (!$response) {
106
107
            $criteria = new ReportRequestCriteria;
108
            $criteria->viewId = $viewId;
109
            $criteria->startDate = $startDate;
110
            $criteria->endDate = $endDate;
111
            $criteria->metrics = $metrics;
112
            $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...
113
            $criteria->filtersExpression = $filters;
114
115
            $reportResponse = Analytics::$plugin->getApis()->getAnalyticsReporting()->getReport($criteria);
116
            $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

116
            $response = $this->parseReportingReport(/** @scrutinizer ignore-type */ $reportResponse);
Loading history...
117
118
            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...
119
                Analytics::$plugin->cache->set($cacheId, $response);
120
            }
121
        }
122
123
        return $response;
124
    }
125
126
    /**
127
     * Returns an area report.
128
     *
129
     * @param array $request
130
     *
131
     * @return array
132
     * @throws \yii\base\InvalidConfigException
133
     */
134
    public function getAreaReport(array $request)
135
    {
136
        $viewId = ($request['viewId'] ?? null);
137
        $period = ($request['period'] ?? null);
138
        $metricString = ($request['options']['metric'] ?? null);
139
140
        switch ($period) {
141
            case 'year':
142
                $dimensionString = 'ga:yearMonth';
143
                $startDate = date('Y-m-01', strtotime('-1 '.$period));
144
                $endDate = date('Y-m-d');
145
                break;
146
147
            default:
148
                $dimensionString = 'ga:date';
149
                $startDate = date('Y-m-d', strtotime('-1 '.$period));
150
                $endDate = date('Y-m-d');
151
        }
152
153
        $criteria = new ReportRequestCriteria;
154
        $criteria->viewId = $viewId;
155
        $criteria->startDate = $startDate;
156
        $criteria->endDate = $endDate;
157
        $criteria->metrics = $metricString;
158
        $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...
159
        $criteria->orderBys = [
160
            ['fieldName' => $dimensionString, 'orderType' => 'VALUE', 'sortOrder' => 'ASCENDING']
161
        ];
162
163
        $reportResponse = Analytics::$plugin->getApis()->getAnalyticsReporting()->getReport($criteria);
164
        $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

164
        $report = $this->parseReportingReport(/** @scrutinizer ignore-type */ $reportResponse);
Loading history...
165
166
        $total = $report['totals'][0];
167
168
        $view = Analytics::$plugin->getViews()->getViewById($viewId);
169
170
        return [
171
            'view' => $view->name,
172
            'type' => 'area',
173
            'chart' => $report,
174
            'total' => $total,
175
            'metric' => Craft::t('analytics', Analytics::$plugin->metadata->getDimMet($metricString)),
176
            'period' => $period,
177
            'periodLabel' => Craft::t('analytics', 'This '.$period)
178
        ];
179
    }
180
181
    /**
182
     * Returns a counter report.
183
     *
184
     * @param array $request
185
     *
186
     * @return array
187
     * @throws \yii\base\InvalidConfigException
188
     */
189
    public function getCounterReport(array $request)
190
    {
191
        $viewId = ($request['viewId'] ?? null);
192
        $period = ($request['period'] ?? null);
193
        $metricString = ($request['options']['metric'] ?? null);
194
        $startDate = date('Y-m-d', strtotime('-1 '.$period));
195
        $endDate = date('Y-m-d');
196
197
        $criteria = new ReportRequestCriteria;
198
        $criteria->viewId = $viewId;
199
        $criteria->startDate = $startDate;
200
        $criteria->endDate = $endDate;
201
        $criteria->metrics = $metricString;
202
203
204
        $reportResponse = Analytics::$plugin->getApis()->getAnalyticsReporting()->getReport($criteria);
205
        $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

205
        $report = $this->parseReportingReport(/** @scrutinizer ignore-type */ $reportResponse);
Loading history...
206
207
        $total = 0;
208
209
        if (!empty($report['totals'][0])) {
210
            $total = $report['totals'][0];
211
        }
212
213
        $counter = [
214
            'type' => $report['cols'][0]['type'],
215
            'value' => $total,
216
            'label' => StringHelper::toLowerCase(Craft::t('analytics', Analytics::$plugin->metadata->getDimMet($metricString)))
217
        ];
218
219
        $view = Analytics::$plugin->getViews()->getViewById($viewId);
220
221
        return [
222
            'view' => $view->name,
223
            'type' => 'counter',
224
            'counter' => $counter,
225
            'response' => $report,
226
            'metric' => Craft::t('analytics', Analytics::$plugin->metadata->getDimMet($metricString)),
227
            'period' => $period,
228
            'periodLabel' => Craft::t('analytics', 'this '.$period)
229
        ];
230
    }
231
232
    /**
233
     * Returns a pie report.
234
     *
235
     * @param array $request
236
     *
237
     * @return array
238
     * @throws \yii\base\InvalidConfigException
239
     */
240
    public function getPieReport(array $request)
241
    {
242
        $viewId = ($request['viewId'] ?? null);
243
        $period = ($request['period'] ?? null);
244
        $dimensionString = ($request['options']['dimension'] ?? null);
245
        $metricString = ($request['options']['metric'] ?? null);
246
        $startDate = date('Y-m-d', strtotime('-1 '.$period));
247
        $endDate = date('Y-m-d');
248
249
        $criteria = new ReportRequestCriteria;
250
        $criteria->viewId = $viewId;
251
        $criteria->startDate = $startDate;
252
        $criteria->endDate = $endDate;
253
        $criteria->metrics = $metricString;
254
        $criteria->dimensions = $dimensionString;
255
256
        $reportResponse = Analytics::$plugin->getApis()->getAnalyticsReporting()->getReport($criteria);
257
        $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

257
        $report = $this->parseReportingReport(/** @scrutinizer ignore-type */ $reportResponse);
Loading history...
258
259
        $view = Analytics::$plugin->getViews()->getViewById($viewId);
260
261
        return [
262
            'view' => $view->name,
263
            'type' => 'pie',
264
            'chart' => $report,
265
            'dimension' => Craft::t('analytics', Analytics::$plugin->metadata->getDimMet($dimensionString)),
266
            'metric' => Craft::t('analytics', Analytics::$plugin->metadata->getDimMet($metricString)),
267
            'period' => $period,
268
            'periodLabel' => Craft::t('analytics', 'this '.$period)
269
        ];
270
    }
271
272
    /**
273
     * Returns a table report.
274
     *
275
     * @param array $request
276
     *
277
     * @return array
278
     * @throws \yii\base\InvalidConfigException
279
     */
280
    public function getTableReport(array $request)
281
    {
282
        $viewId = ($request['viewId'] ?? null);
283
284
        $period = ($request['period'] ?? null);
285
        $dimensionString = ($request['options']['dimension'] ?? null);
286
        $metricString = ($request['options']['metric'] ?? null);
287
288
        $criteria = new ReportRequestCriteria;
289
        $criteria->viewId = $viewId;
290
        $criteria->dimensions = $dimensionString;
291
        $criteria->metrics = $metricString;
292
        $criteria->startDate = date('Y-m-d', strtotime('-1 '.$period));
293
        $criteria->endDate = date('Y-m-d');
294
295
        $reportResponse = Analytics::$plugin->getApis()->getAnalyticsReporting()->getReport($criteria);
296
        $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

296
        $report = $this->parseReportingReport(/** @scrutinizer ignore-type */ $reportResponse);
Loading history...
297
298
        $view = Analytics::$plugin->getViews()->getViewById($viewId);
299
300
        return [
301
            'view' => $view->name,
302
            'type' => 'table',
303
            'chart' => $report,
304
            'dimension' => Craft::t('analytics', Analytics::$plugin->metadata->getDimMet($dimensionString)),
305
            'metric' => Craft::t('analytics', Analytics::$plugin->metadata->getDimMet($metricString)),
306
            'period' => $period,
307
            'periodLabel' => Craft::t('analytics', 'this '.$period)
308
        ];
309
    }
310
311
    /**
312
     * Returns a geo report.
313
     *
314
     * @param array $request
315
     *
316
     * @return array
317
     * @throws \yii\base\InvalidConfigException
318
     */
319
    public function getGeoReport(array $request)
320
    {
321
        $viewId = ($request['viewId'] ?? null);
322
        $period = ($request['period'] ?? null);
323
        $dimensionString = ($request['options']['dimension'] ?? null);
324
        $metricString = ($request['options']['metric'] ?? null);
325
326
        $originDimension = $dimensionString;
327
328
        if ($dimensionString === 'ga:city') {
329
            $dimensionString = 'ga:latitude,ga:longitude,'.$dimensionString;
330
        }
331
332
        $criteria = new ReportRequestCriteria;
333
        $criteria->viewId = $viewId;
334
        $criteria->dimensions = $dimensionString;
335
        $criteria->metrics = $metricString;
336
        $criteria->startDate = date('Y-m-d', strtotime('-1 '.$period));
337
        $criteria->endDate = date('Y-m-d');
338
339
        $reportResponse = Analytics::$plugin->getApis()->getAnalyticsReporting()->getReport($criteria);
340
        $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

340
        $report = $this->parseReportingReport(/** @scrutinizer ignore-type */ $reportResponse);
Loading history...
341
342
        $view = Analytics::$plugin->getViews()->getViewById($viewId);
343
344
        return [
345
            'view' => $view->name,
346
            'type' => 'geo',
347
            'chart' => $report,
348
            'dimensionRaw' => $originDimension,
349
            'dimension' => Craft::t('analytics', Analytics::$plugin->metadata->getDimMet($originDimension)),
350
            'metric' => Craft::t('analytics', Analytics::$plugin->metadata->getDimMet($metricString)),
351
            'period' => $period,
352
            'periodLabel' => Craft::t('analytics', 'this '.$period)
353
        ];
354
    }
355
356
    // Private Methods
357
    // =========================================================================
358
359
    /**
360
     * @param Google_Service_AnalyticsReporting_Report $_report
361
     *
362
     * @return array
363
     */
364
    private function parseReportingReport(Google_Service_AnalyticsReporting_Report $_report)
365
    {
366
        $columnHeader = $_report->getColumnHeader();
367
        $columnHeaderDimensions = $columnHeader->getDimensions();
368
        $metricHeaderEntries = $columnHeader->getMetricHeader()->getMetricHeaderEntries();
369
370
371
        // Columns
372
373
        $cols = [];
374
375
        if ($columnHeaderDimensions) {
376
            foreach ($columnHeaderDimensions as $columnHeaderDimension) {
377
378
                $id = $columnHeaderDimension;
379
                $label = Analytics::$plugin->metadata->getDimMet($columnHeaderDimension);
380
381
                switch ($columnHeaderDimension) {
382
                    case 'ga:date':
383
                    case 'ga:yearMonth':
384
                        $type = 'date';
385
                        break;
386
387
                    case 'ga:continent':
388
                        $type = 'continent';
389
                        break;
390
                    case 'ga:subContinent':
391
                        $type = 'subContinent';
392
                        break;
393
394
                    case 'ga:latitude':
395
                    case 'ga:longitude':
396
                        $type = 'float';
397
                        break;
398
399
                    default:
400
                        $type = 'string';
401
                }
402
403
                $col = [
404
                    'type' => $type,
405
                    'label' => Craft::t('analytics', $label),
406
                    'id' => $id,
407
                ];
408
409
                array_push($cols, $col);
410
            }
411
        }
412
413
        foreach ($metricHeaderEntries as $metricHeaderEntry) {
414
            $label = Analytics::$plugin->metadata->getDimMet($metricHeaderEntry['name']);
415
416
            $col = [
417
                'type' => strtolower($metricHeaderEntry['type']),
418
                'label' => Craft::t('analytics', $label),
419
                'id' => $metricHeaderEntry['name'],
420
            ];
421
422
            array_push($cols, $col);
423
        }
424
425
426
        // Rows
427
428
        $rows = [];
429
430
        foreach ($_report->getData()->getRows() as $_row) {
431
432
            $colIndex = 0;
433
            $row = [];
434
435
            $dimensions = $_row->getDimensions();
436
437
            if ($dimensions) {
438
                foreach ($dimensions as $_dimension) {
439
440
                    $value = $_dimension;
441
442
                    if ($columnHeaderDimensions) {
443
                        if (isset($columnHeaderDimensions[$colIndex])) {
444
                            switch ($columnHeaderDimensions[$colIndex]) {
445
                                case 'ga:continent':
446
                                    $value = Analytics::$plugin->metadata->getContinentCode($value);
447
                                    break;
448
                                case 'ga:subContinent':
449
                                    $value = Analytics::$plugin->metadata->getSubContinentCode($value);
450
                                    break;
451
                            }
452
                        }
453
                    }
454
455
                    array_push($row, $value);
456
457
                    $colIndex++;
458
                }
459
            }
460
461
            foreach ($_row->getMetrics() as $_metric) {
462
                array_push($row, $_metric->getValues()[0]);
463
                $colIndex++;
464
            }
465
466
            array_push($rows, $row);
467
        }
468
469
        $totals = $_report->getData()->getTotals()[0]->getValues();
470
471
        return [
472
            'cols' => $cols,
473
            'rows' => $rows,
474
            'totals' => $totals
475
        ];
476
    }
477
}
478