Report   B
last analyzed

Complexity

Total Complexity 40

Size/Duplication

Total Lines 336
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 0
Metric Value
wmc 40
lcom 1
cbo 0
dl 0
loc 336
rs 8.2608
c 0
b 0
f 0

14 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
B get() 0 39 6
A clearCache() 0 14 3
A getHandler() 0 5 2
A getHandlers() 0 17 3
A getService() 0 5 1
A request() 0 21 2
A setRequestDate() 0 13 3
A setRequestMetrics() 0 16 3
A setRequestSorting() 0 23 3
A setRequestDimensions() 0 15 3
C getResults() 0 35 7
A getClient() 0 12 2
A getApiModule() 0 6 1

How to fix   Complexity   

Complex Class

Complex classes like Report often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Report, and based on these observations, apply Extract Interface, too.

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 gplcart\core\Cache;
14
use gplcart\core\Hook;
15
use gplcart\core\Module;
16
use OutOfRangeException;
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 array $settings
57
     * @return array
58
     * @throws OutOfRangeException
59
     */
60
    public function get(array $handler, array $settings)
61
    {
62
        $report = null;
63
        $this->hook->attach('module.ga_report.get.before', $handler, $settings, $report, $this);
64
65
        if (isset($report)) {
66
            return $report;
67
        }
68
69
        if (empty($settings['ga_profile_id'][$settings['store_id']])) {
70
            throw new OutOfRangeException("Google Analytics profile ID is empty for store {$settings['store_id']}");
71
        }
72
73
        $settings += array('cache' => 0);
74
        $settings['ga_profile_id'] = $settings['ga_profile_id'][$settings['store_id']];
75
76
        $cache_key = "ga_report.{$handler['id']}.{$settings['store_id']}";
77
        $cache = $this->cache->get($cache_key, array('lifespan' => $settings['cache']));
78
79
        if (!empty($settings['cache']) && isset($cache)) {
80
            return array(
81
                'data' => $cache,
82
                'updated' => $this->cache->getFileMtime()
83
            );
84
        }
85
86
        try {
87
            $response = $this->request($settings, $handler);
88
            $results = $this->getResults($response);
89
        } catch (Exception $ex) {
90
            return array('error' => $ex->getMessage());
91
        }
92
93
        $report = array('data' => $results, 'updated' => GC_TIME);
94
        $this->cache->set($cache_key, $results);
95
96
        $this->hook->attach('module.ga_report.get.after', $handler, $settings, $report, $this);
97
        return $report;
98
    }
99
100
    /**
101
     * Clear cached report data
102
     * @param string|null $handler_id
103
     * @param integer|string|null $store_id
104
     */
105
    public function clearCache($handler_id = null, $store_id = null)
106
    {
107
        $pattern = 'ga_report.';
108
109
        if (isset($handler_id)) {
110
            $pattern .= "$handler_id.";
111
        }
112
113
        if (isset($store_id)) {
114
            $pattern .= "$store_id";
115
        }
116
117
        $this->cache->clear('', array('pattern' => "$pattern*"));
118
    }
119
120
    /**
121
     * Returns a handler data
122
     * @param string $handler_id
123
     * @return array
124
     */
125
    public function getHandler($handler_id)
126
    {
127
        $handlers = $this->getHandlers();
128
        return empty($handlers[$handler_id]) ? array() : $handlers[$handler_id];
129
    }
130
131
    /**
132
     * Returns an array of handlers
133
     * @return array
134
     */
135
    public function getHandlers()
136
    {
137
        $handlers = &gplcart_static('module.ga_report.handlers');
138
139
        if (isset($handlers)) {
140
            return $handlers;
141
        }
142
143
        $handlers = gplcart_config_get(__DIR__ . '/../config/reports.php');
144
145
        foreach ($handlers as $id => &$handler) {
146
            $handler['id'] = $id;
147
        }
148
149
        $this->hook->attach('module.ga_report.handlers', $handlers);
150
        return $handlers;
151
    }
152
153
    /**
154
     * Returns Google Analytics Reporting class instance
155
     * @param array $settings
156
     * @return \Google_Service_AnalyticsReporting
157
     */
158
    protected function getService(array $settings)
159
    {
160
        $client = $this->getClient($settings);
161
        return new \Google_Service_AnalyticsReporting($client);
162
    }
163
164
    /**
165
     * Returns an object of Google Analytics service response
166
     * @param array $settings
167
     * @param array $handler
168
     * @return \Google_Service_AnalyticsReporting_GetReportsResponse
169
     * @throws OutOfRangeException
170
     */
171
    public function request(array $settings, array $handler)
172
    {
173
        if (empty($settings['ga_profile_id'])) {
174
            throw new OutOfRangeException('Google Analytics profile ID is empty in the request settings');
175
        }
176
177
        $service = $this->getService($settings); // Also loads all needed libraries
178
179
        $request = new \Google_Service_AnalyticsReporting_ReportRequest;
180
        $request->setViewId($settings['ga_profile_id']);
181
182
        $this->setRequestDate($request, $handler);
183
        $this->setRequestMetrics($request, $handler);
184
        $this->setRequestSorting($request, $handler);
185
        $this->setRequestDimensions($request, $handler);
186
187
        $body = new \Google_Service_AnalyticsReporting_GetReportsRequest;
188
        $body->setReportRequests(array($request));
189
190
        return $service->reports->batchGet($body);
191
    }
192
193
    /**
194
     * Sets request date range
195
     * @param \Google_Service_AnalyticsReporting_ReportRequest $request
196
     * @param array $handler
197
     */
198
    protected function setRequestDate($request, array $handler)
199
    {
200
        if (!empty($handler['query']['date']) && count($handler['query']['date']) == 2) {
201
202
            list($from, $to) = $handler['query']['date'];
203
204
            $date = new \Google_Service_AnalyticsReporting_DateRange;
205
            $date->setStartDate($from);
206
            $date->setEndDate($to);
207
208
            $request->setDateRanges($date);
209
        }
210
    }
211
212
    /**
213
     * Sets request metrics from a handler
214
     * @param \Google_Service_AnalyticsReporting_ReportRequest $request
215
     * @param array $handler
216
     */
217
    protected function setRequestMetrics($request, array $handler)
218
    {
219
        if (empty($handler['query']['metrics'])) {
220
            throw new OutOfRangeException('No query metrics data found in the handler');
221
        }
222
223
        $metrics = array();
224
225
        foreach ((array) $handler['query']['metrics'] as $i => $name) {
226
            $metric = new \Google_Service_AnalyticsReporting_Metric;
227
            $metric->setExpression($name);
228
            $metrics[] = $metric;
229
        }
230
231
        $request->setMetrics($metrics);
232
    }
233
234
    /**
235
     * Sets request sorting from a handler
236
     * @param \Google_Service_AnalyticsReporting_ReportRequest $request
237
     * @param array $handler
238
     */
239
    protected function setRequestSorting($request, array $handler)
240
    {
241
        if (!empty($handler['query']['sort'])) {
242
243
            $orders = array();
244
            foreach ((array) $handler['query']['sort'] as $field => $params) {
245
246
                $params += array('VALUE', 'ASCENDING');
247
248
                list($type, $direction) = array_map('strtoupper', $params);
249
250
                $order = new \Google_Service_AnalyticsReporting_OrderBy;
251
252
                $order->setFieldName($field);
253
                $order->setOrderType($type);
254
                $order->setSortOrder($direction);
255
256
                $orders[] = $order;
257
            }
258
259
            $request->setOrderBys($orders);
260
        }
261
    }
262
263
    /**
264
     * Sets request dimensions from a handler
265
     * @param \Google_Service_AnalyticsReporting_ReportRequest $request
266
     * @param array $handler
267
     */
268
    protected function setRequestDimensions($request, array $handler)
269
    {
270
        if (!empty($handler['query']['dimensions'])) {
271
272
            $dimensions = array();
273
274
            foreach ((array) $handler['query']['dimensions'] as $name) {
275
                $dimension = new \Google_Service_AnalyticsReporting_Dimension;
276
                $dimension->setName($name);
277
                $dimensions[] = $dimension;
278
            }
279
280
            $request->setDimensions($dimensions);
281
        }
282
    }
283
284
    /**
285
     * Returns an array of results from the response object
286
     * @param \Google_Service_AnalyticsReporting_GetReportsResponse $response
287
     * @return array
288
     */
289
    public function getResults($response)
290
    {
291
        $results = array('rows' => array());
292
293
        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...
294
295
            $report = $response[$report_index];
296
            $header = $report->getColumnHeader();
297
298
            $dimension_headers = $header->getDimensions();
299
            $metric_headers = $header->getMetricHeader()->getMetricHeaderEntries();
300
            $rows = $report->getData()->getRows();
301
302
            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...
303
304
                $row = $rows[$row_index];
305
                $dimensions = $row->getDimensions();
306
                $metrics = $row->getMetrics();
307
308
                for ($i = 0; $i < count($dimension_headers) && $i < count($dimensions); $i++) {
309
                    $results['rows'][$row_index][$dimension_headers[$i]] = $dimensions[$i];
310
                }
311
312
                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...
313
                    $values = $metrics[$j]->getValues();
314
                    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...
315
                        $entry = $metric_headers[$k];
316
                        $results['rows'][$row_index][$entry->getName()] = $values[$k];
317
                    }
318
                }
319
            }
320
        }
321
322
        return $results;
323
    }
324
325
    /**
326
     * Returns Google Client class instance
327
     * @param array $settings
328
     * @return \Google_Client
329
     * @throws OutOfRangeException
330
     */
331
    protected function getClient(array $settings)
332
    {
333
        if (empty($settings['credential_id'])) {
334
            throw new OutOfRangeException('Credential ID is empty in Google client settings');
335
        }
336
337
        $client = $this->getApiModule()->getGoogleClient($settings['credential_id']);
338
        $client->setApplicationName('Analytics Reporting');
339
        $client->setScopes(array('https://www.googleapis.com/auth/analytics.readonly'));
340
341
        return $client;
342
    }
343
344
    /**
345
     * Returns Google Api module instance
346
     * @return \gplcart\modules\gapi\Main
347
     */
348
    protected function getApiModule()
349
    {
350
        /** @var \gplcart\modules\gapi\Main $module */
351
        $module = $this->module->getInstance('gapi');
352
        return $module;
353
    }
354
355
356
}
357