Passed
Push — v4 ( 118ebd...a87f10 )
by Benjamin
04:01
created

Metadata::dimmetsFileExists()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 0
dl 0
loc 9
rs 9.6666
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 yii\base\Component;
12
use craft\helpers\Json;
13
use dukt\analytics\models\Column;
14
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...
15
16
class Metadata extends Component
17
{
18
    // Properties
19
    // =========================================================================
20
21
    /**
22
     * @var array|null
23
     */
24
    private $groups;
25
26
    /**
27
     * @var array|null
28
     */
29
    private $dimensions;
30
31
    /**
32
     * @var array|null
33
     */
34
    private $metrics;
35
36
    /**
37
     * @var array|null
38
     */
39
    private $columns;
40
41
    /**
42
     * @var array|null
43
     */
44
    private $selectDimensionOptions;
45
46
    /**
47
     * @var array|null
48
     */
49
    private $selectMetricOptions;
50
51
    // Public Methods
52
    // =========================================================================
53
54
    /**
55
     * Checks whether the dimensions & metrics file exists
56
     *
57
     * @return bool
58
     */
59
    public function dimmetsFileExists()
60
    {
61
        $path = Analytics::$plugin->metadata->getDimmetsFilePath();
62
63
        if (file_exists($path)) {
64
            return true;
65
        }
66
67
        return false;
68
    }
69
70
    /**
71
     * Returns available data types for Google Analytics
72
     *
73
     * @param mixed
74
     *
75
     * @return array
76
     */
77
    public function getGoogleAnalyticsDataTypes()
78
    {
79
        $columns = $this->getColumns();
80
81
        $dataTypes = [];
82
83
        foreach ($columns as $column) {
84
            if (!isset($dataTypes[$column->dataType]) && !empty($column->dataType)) {
85
                $dataTypes[$column->dataType] = $column->dataType;
86
            }
87
        }
88
89
        return $dataTypes;
90
    }
91
92
    /**
93
     * Returns available data types
94
     *
95
     * @param mixed
96
     *
97
     * @return array
98
     */
99
    public function getDataTypes()
100
    {
101
        return [
102
            'string',
103
            'integer',
104
            'percent',
105
            'time',
106
            'currency',
107
            'float',
108
            'date'
109
        ];
110
    }
111
112
    public function getContinents()
113
    {
114
        return $this->_getData('continents');
115
    }
116
117
    public function getSubContinents()
118
    {
119
        return $this->_getData('subContinents');
120
    }
121
122
    /**
123
     * Get Continent Code
124
     *
125
     * @param string $label
126
     *
127
     * @return mixed
128
     */
129
    public function getContinentCode($label)
130
    {
131
        $continents = $this->_getData('continents');
132
133
        foreach ($continents as $continent) {
134
            if ($continent['label'] == $label) {
135
                return $continent['code'];
136
            }
137
        }
138
139
        return null;
140
    }
141
142
    /**
143
     * Get Sub-Continent Code
144
     *
145
     * @param string $label
146
     *
147
     * @return mixed
148
     */
149
    public function getSubContinentCode($label)
150
    {
151
        $subContinents = $this->_getData('subContinents');
152
153
        foreach ($subContinents as $subContinent) {
154
            if ($subContinent['label'] == $label) {
155
                return $subContinent['code'];
156
            }
157
        }
158
159
        return null;
160
    }
161
162
    /**
163
     * Get a dimension or a metric label from its id
164
     *
165
     * @param string $id
166
     *
167
     * @return mixed
168
     */
169
    public function getDimMet($id)
170
    {
171
        $columns = $this->getColumns();
172
173
        if (isset($columns[$id])) {
174
            return $columns[$id]->uiName;
175
        }
176
177
        return null;
178
    }
179
180
    /**
181
     * Returns columns based on a search string `$q`
182
     *
183
     * @param string $q
184
     *
185
     * @return array
186
     */
187
    public function searchColumns($q)
188
    {
189
        $columns = $this->getColumns();
190
        $results = [];
191
192
        foreach ($columns as $column) {
193
            if (stripos($column->id, $q) !== false || stripos($column->uiName, $q) !== false) {
194
                $results[] = $column;
195
            }
196
        }
197
198
        return $results;
199
    }
200
201
    /**
202
     * Returns columns
203
     *
204
     * @param null $type
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $type is correct as it would always require null to be passed?
Loading history...
205
     *
206
     * @return array
207
     */
208
    public function getColumns($type = null)
209
    {
210
        if (!$this->columns) {
211
            $this->columns = $this->_loadColumns();
212
        }
213
214
        if ($type) {
215
            $columns = [];
216
217
            foreach ($this->columns as $column) {
218
                if ($column->type == $type) {
219
                    $columns[] = $column;
220
                }
221
            }
222
223
            return $columns;
224
        }
225
226
        return $this->columns;
227
    }
228
229
    /**
230
     * Returns dimension columns
231
     *
232
     * @return array
233
     */
234
    public function getDimensions()
235
    {
236
        if (!$this->dimensions) {
237
            $this->dimensions = $this->getColumns('DIMENSION');
238
        }
239
240
        return $this->dimensions;
241
    }
242
243
    /**
244
     * Returns column groups
245
     *
246
     * @param null $type
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $type is correct as it would always require null to be passed?
Loading history...
247
     *
248
     * @return array
249
     */
250
    public function getColumnGroups($type = null)
251
    {
252
        if ($type && isset($this->groups[$type])) {
253
            return $this->groups[$type];
254
        }
255
256
        $groups = [];
257
258
        foreach ($this->getColumns() as $column) {
259
            if (!$type || ($type && $column->type == $type)) {
260
                $groups[$column->group] = $column->group;
261
            }
262
        }
263
264
        // ksort($groups);
265
266
        if ($type) {
267
            $this->groups[$type] = $groups;
268
        }
269
270
        return $groups;
271
    }
272
273
    /**
274
     * Returns select dimension options
275
     *
276
     * @param array $filters
277
     *
278
     * @return array
279
     */
280
    public function getSelectDimensionOptions(array $filters = null): array
281
    {
282
        if (!$this->selectDimensionOptions) {
283
            $this->selectDimensionOptions = $this->getSelectOptions('DIMENSION');
284
        }
285
286
        if($filters) {
287
            $this->selectDimensionOptions = $this->filterOptions($this->selectDimensionOptions, $filters);
288
        }
289
290
        return $this->selectDimensionOptions;
291
    }
292
293
    /**
294
     * Returns select metric options
295
     *
296
     * @param array $filters
297
     *
298
     * @return array
299
     */
300
    public function getSelectMetricOptions(array $filters = null): array
301
    {
302
        if (!$this->selectMetricOptions) {
303
            $this->selectMetricOptions = $this->getSelectOptions('METRIC');
304
        }
305
306
        if($filters) {
307
            $this->selectMetricOptions = $this->filterOptions($this->selectMetricOptions, $filters);
308
        }
309
310
        return $this->selectMetricOptions;
311
    }
312
313
    /**
314
     * Returns select options
315
     *
316
     * @param null  $type
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $type is correct as it would always require null to be passed?
Loading history...
317
     * @param array $filters
318
     *
319
     * @return array
320
     */
321
    public function getSelectOptions($type = null, array $filters = null)
322
    {
323
        $options = [];
324
325
        foreach ($this->getColumnGroups($type) as $group) {
326
            $options[]['optgroup'] = Craft::t('analytics', $group);
327
328
            foreach ($this->getColumns($type) as $column) {
329
                if ($column->group == $group) {
330
                    $options[$column->id] = Craft::t('analytics', $column->uiName);
331
                }
332
            }
333
        }
334
335
336
        // filters
337
338
        if($filters) {
339
            $options = $this->filterOptions($options, $filters);
340
        }
341
342
        return $options;
343
    }
344
345
    /**
346
     * Returns the metrics
347
     *
348
     * @return array
349
     */
350
    public function getMetrics()
351
    {
352
        if (!$this->metrics) {
353
            $this->metrics = $this->getColumns('METRIC');
354
        }
355
356
        return $this->metrics;
357
    }
358
359
    /**
360
     * Returns the file path of the dimensions-metrics.json file
361
     *
362
     * @return string
363
     */
364
    public function getDimmetsFilePath()
365
    {
366
        return Craft::getAlias('@dukt/analytics/etc/data/dimensions-metrics.json');
0 ignored issues
show
Bug Best Practice introduced by
The expression return Craft::getAlias('...mensions-metrics.json') also could return the type boolean which is incompatible with the documented return type string.
Loading history...
367
    }
368
369
    // Private Methods
370
    // =========================================================================
371
372
    /**
373
     * Loads the columns from the dimensions-metrics.json file
374
     *
375
     * @return array
376
     */
377
    private function _loadColumns()
378
    {
379
        $cols = [];
380
381
        $path = Analytics::$plugin->metadata->getDimmetsFilePath();
382
383
384
        $contents = file_get_contents($path);
385
386
        $columnsResponse = Json::decode($contents);
387
388
        if ($columnsResponse) {
389
            foreach ($columnsResponse as $columnResponse) {
390
                $cols[$columnResponse['id']] = new Column($columnResponse);
391
392
                if ($columnResponse['id'] == 'ga:countryIsoCode') {
393
                    $cols[$columnResponse['id']]->uiName = 'Country';
394
                }
395
            }
396
        }
397
398
        return $cols;
399
    }
400
401
    /**
402
     * Get Data
403
     *
404
     * @param $name
405
     *
406
     * @return mixed
407
     * @internal param string $label
408
     *
409
     */
410
    private function _getData($name)
411
    {
412
        $jsonData = file_get_contents(Craft::getAlias('@dukt/analytics/etc/data/'.$name.'.json'));
413
        $data = json_decode($jsonData, true);
414
415
        return $data;
416
    }
417
418
    /**
419
     * @param array      $options
420
     * @param array $filters
421
     *
422
     * @return array
423
     */
424
    private function filterOptions(array $options, array $filters): array
425
    {
426
        if(!$filters) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $filters 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...
427
            return $options;
428
        }
429
430
        $filteredOptions = [];
431
        $optgroup = null;
432
        $lastOptgroup = null;
433
434
        foreach ($options as $id => $option) {
435
            if (isset($option['optgroup'])) {
436
                $optgroup = null;
437
                $lastOptgroup = $option['optgroup'];
438
                continue;
439
            }
440
441
            foreach ($filters as $filter) {
442
                if ($id !== $filter) {
443
                    continue;
444
                }
445
446
                if (!$optgroup) {
447
                    $optgroup = $lastOptgroup;
448
                    $filteredOptions[]['optgroup'] = $optgroup;
449
                }
450
451
                $filteredOptions[$id] = $option;
452
            }
453
        }
454
455
        return $filteredOptions;
456
    }
457
}
458