Completed
Push — master ( 7f0603...aacf62 )
by Iurii
01:13
created

Report::getResults()   C

Complexity

Conditions 7
Paths 8

Size

Total Lines 35
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 35
rs 6.7272
c 0
b 0
f 0
cc 7
eloc 20
nc 8
nop 1
1
<?php
2
3
/**
4
 * @package Google Analytics Report
5
 * @author Iurii Makukh <[email protected]>
6
 * @copyright Copyright (c) 2015, Iurii Makukh
7
 * @license https://www.gnu.org/licenses/gpl.html GNU/GPLv3
8
 */
9
10
namespace gplcart\modules\ga_report\models;
11
12
use Exception;
13
use OutOfRangeException;
14
use gplcart\core\Cache;
15
use gplcart\core\Hook;
16
use gplcart\core\Module;
17
18
/**
19
 * Manages basic behaviors and data related to Google Analytics Report
20
 */
21
class Report
22
{
23
24
    /**
25
     * Hook class instance
26
     * @var \gplcart\core\Hook $hook
27
     */
28
    protected $hook;
29
30
    /**
31
     * Cache class instance
32
     * @var \gplcart\core\Cache $cache
33
     */
34
    protected $cache;
35
36
    /** Module class instance
37
     * @var \gplcart\core\Module $module
38
     */
39
    protected $module;
40
41
    /**
42
     * @param Hook $hook
43
     * @param Cache $cache
44
     * @param Module $module
45
     */
46
    public function __construct(Hook $hook, Cache $cache, Module $module)
47
    {
48
        $this->hook = $hook;
49
        $this->cache = $cache;
50
        $this->module = $module;
51
    }
52
53
    /**
54
     * Returns an array of parsed reporting data
55
     * @param array $handler
56
     * @param string|array $settings
57
     * @return array
58
     * @throws OutOfRangeException
59
     */
60
    public function get($handler, $settings)
61
    {
62
        if (empty($handler['id'])) {
63
            throw new OutOfRangeException('Handler ID is empty');
64
        }
65
66
        if (empty($settings['store_id'])) {
67
            throw new OutOfRangeException('Store ID is empty in the settings');
68
        }
69
70
        if (empty($settings['ga_profile_id'][$settings['store_id']])) {
71
            throw new OutOfRangeException("Google Analytics profile ID is empty for store {$settings['store_id']}");
72
        }
73
74
        $settings += array('cache' => 0);
75
        $settings['ga_profile_id'] = $settings['ga_profile_id'][$settings['store_id']];
76
77
        $cache_key = "ga_report.{$handler['id']}.{$settings['store_id']}";
78
        $cache = $this->cache->get($cache_key, array('lifespan' => $settings['cache']));
79
80
        if (!empty($settings['cache']) && isset($cache)) {
81
            return array(
82
                'data' => $cache,
83
                'updated' => $this->cache->getFileMtime()
84
            );
85
        }
86
87
        try {
88
            $response = $this->request($settings, $handler);
89
            $results = $this->getResults($response);
90
        } catch (Exception $ex) {
91
            return array('error' => $ex->getMessage());
92
        }
93
94
        $report = array('data' => $results, 'updated' => GC_TIME);
95
        $this->cache->set($cache_key, $results);
96
        return $report;
97
    }
98
99
    /**
100
     * Clear cached report data
101
     * @param string|null $handler_id
102
     * @param integer|string|null $store_id
103
     */
104
    public function clearCache($handler_id = null, $store_id = null)
105
    {
106
        $pattern = 'ga_report.';
107
108
        if (isset($handler_id)) {
109
            $pattern .= "$handler_id.";
110
        }
111
112
        if (isset($store_id)) {
113
            $pattern .= "$store_id";
114
        }
115
116
        $this->cache->clear('', array('pattern' => "$pattern*"));
117
    }
118
119
    /**
120
     * Returns a handler data
121
     * @param string $handler_id
122
     * @return array
123
     */
124
    public function getHandler($handler_id)
125
    {
126
        $handlers = $this->getHandlers();
127
        return empty($handlers[$handler_id]) ? array() : $handlers[$handler_id];
128
    }
129
130
    /**
131
     * Returns an array of handlers
132
     * @return array
133
     */
134
    public function getHandlers()
135
    {
136
        $handlers = &gplcart_static('module.ga_report.handlers');
137
138
        if (isset($handlers)) {
139
            return $handlers;
140
        }
141
142
        $handlers = gplcart_config_get(__DIR__ . '/../config/reports.php');
143
144
        foreach ($handlers as $id => &$handler) {
145
            $handler['id'] = $id;
146
        }
147
148
        $this->hook->attach('module.ga_report.handlers', $handlers);
149
        return $handlers;
150
    }
151
152
    /**
153
     * Returns Google Analytics Reporting class instance
154
     * @param array $settings
155
     * @return \Google_Service_AnalyticsReporting
156
     */
157
    protected function getService(array $settings)
158
    {
159
        $client = $this->getClient($settings);
160
        return new \Google_Service_AnalyticsReporting($client);
161
    }
162
163
    /**
164
     * Returns an object of Google Analytics service response
165
     * @param array $settings
166
     * @param array $handler
167
     * @return \Google_Service_AnalyticsReporting_GetReportsResponse
168
     * @throws OutOfRangeException
169
     */
170
    public function request(array $settings, array $handler)
171
    {
172
        if (empty($settings['ga_profile_id'])) {
173
            throw new OutOfRangeException('Google Analytics profile ID is empty in the request settings');
174
        }
175
176
        $service = $this->getService($settings); // Also loads all needed libraries
177
178
        $request = new \Google_Service_AnalyticsReporting_ReportRequest;
179
        $request->setViewId($settings['ga_profile_id']);
180
181
        $this->setRequestDate($request, $handler);
182
        $this->setRequestMetrics($request, $handler);
183
        $this->setRequestSorting($request, $handler);
184
        $this->setRequestDimensions($request, $handler);
185
186
        $body = new \Google_Service_AnalyticsReporting_GetReportsRequest;
187
        $body->setReportRequests(array($request));
188
189
        return $service->reports->batchGet($body);
190
    }
191
192
    /**
193
     * Sets request date range
194
     * @param \Google_Service_AnalyticsReporting_ReportRequest $request
195
     * @param array $handler
196
     */
197
    protected function setRequestDate($request, array $handler)
198
    {
199
        if (!empty($handler['query']['date']) && count($handler['query']['date']) == 2) {
200
201
            list($from, $to) = $handler['query']['date'];
202
203
            $date = new \Google_Service_AnalyticsReporting_DateRange;
204
            $date->setStartDate($from);
205
            $date->setEndDate($to);
206
207
            $request->setDateRanges($date);
208
        }
209
    }
210
211
    /**
212
     * Sets request metrics from a handler
213
     * @param \Google_Service_AnalyticsReporting_ReportRequest $request
214
     * @param array $handler
215
     */
216
    protected function setRequestMetrics($request, array $handler)
217
    {
218
        if (empty($handler['query']['metrics'])) {
219
            throw new OutOfRangeException('No query metrics data found in the handler');
220
        }
221
222
        $metrics = array();
223
224
        foreach ((array) $handler['query']['metrics'] as $i => $name) {
225
            $metric = new \Google_Service_AnalyticsReporting_Metric;
226
            $metric->setExpression($name);
227
            $metrics[] = $metric;
228
        }
229
230
        $request->setMetrics($metrics);
231
    }
232
233
    /**
234
     * Sets request sorting from a handler
235
     * @param \Google_Service_AnalyticsReporting_ReportRequest $request
236
     * @param array $handler
237
     */
238
    protected function setRequestSorting($request, array $handler)
239
    {
240
        if (!empty($handler['query']['sort'])) {
241
242
            $orders = array();
243
            foreach ((array) $handler['query']['sort'] as $field => $params) {
244
245
                $params += array('VALUE', 'ASCENDING');
246
247
                list($type, $direction) = array_map('strtoupper', $params);
248
249
                $order = new \Google_Service_AnalyticsReporting_OrderBy;
250
251
                $order->setFieldName($field);
252
                $order->setOrderType($type);
253
                $order->setSortOrder($direction);
254
255
                $orders[] = $order;
256
            }
257
258
            $request->setOrderBys($orders);
259
        }
260
    }
261
262
    /**
263
     * Sets request dimensions from a handler
264
     * @param \Google_Service_AnalyticsReporting_ReportRequest $request
265
     * @param array $handler
266
     */
267
    protected function setRequestDimensions($request, array $handler)
268
    {
269
        if (!empty($handler['query']['dimensions'])) {
270
271
            $dimensions = array();
272
273
            foreach ((array) $handler['query']['dimensions'] as $name) {
274
                $dimension = new \Google_Service_AnalyticsReporting_Dimension;
275
                $dimension->setName($name);
276
                $dimensions[] = $dimension;
277
            }
278
279
            $request->setDimensions($dimensions);
280
        }
281
    }
282
283
    /**
284
     * Returns an array of results from the response object
285
     * @param \Google_Service_AnalyticsReporting_GetReportsResponse $response
286
     * @return array
287
     */
288
    public function getResults($response)
289
    {
290
        $results = array('rows' => array());
291
292
        for ($report_index = 0; $report_index < count($response); $report_index++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
293
294
            $report = $response[$report_index];
295
            $header = $report->getColumnHeader();
296
297
            $dimension_headers = $header->getDimensions();
298
            $metric_headers = $header->getMetricHeader()->getMetricHeaderEntries();
299
            $rows = $report->getData()->getRows();
300
301
            for ($row_index = 0; $row_index < count($rows); $row_index++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
302
303
                $row = $rows[$row_index];
304
                $dimensions = $row->getDimensions();
305
                $metrics = $row->getMetrics();
306
307
                for ($i = 0; $i < count($dimension_headers) && $i < count($dimensions); $i++) {
308
                    $results['rows'][$row_index][$dimension_headers[$i]] = $dimensions[$i];
309
                }
310
311
                for ($j = 0; $j < count($metrics); $j++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
312
                    $values = $metrics[$j]->getValues();
313
                    for ($k = 0; $k < count($values); $k++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
314
                        $entry = $metric_headers[$k];
315
                        $results['rows'][$row_index][$entry->getName()] = $values[$k];
316
                    }
317
                }
318
            }
319
        }
320
321
        return $results;
322
    }
323
324
    /**
325
     * Returns Google Client class instance
326
     * @param array $settings
327
     * @return \Google_Client
328
     * @throws OutOfRangeException
329
     */
330
    protected function getClient(array $settings)
331
    {
332
        if (empty($settings['credential_id'])) {
333
            throw new OutOfRangeException('Credential ID is empty in Google client settings');
334
        }
335
336
        $client = $this->getApiModule()->getGoogleClient($settings['credential_id']);
337
        $client->setApplicationName('Analytics Reporting');
338
        $client->setScopes(array('https://www.googleapis.com/auth/analytics.readonly'));
339
340
        return $client;
341
    }
342
343
    /**
344
     * Returns Google Api module instance
345
     * @return \gplcart\modules\gapi\Main
346
     */
347
    protected function getApiModule()
348
    {
349
        /** @var \gplcart\modules\gapi\Main $module */
350
        $module = $this->module->getInstance('gapi');
351
        return $module;
352
    }
353
354
355
}
356