Passed
Push — develop ( 0437e2...b0b0d8 )
by Benjamin
04:07
created

Metadata::getSelectDimensionOptions()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 5
nc 4
nop 1
dl 0
loc 11
rs 10
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(): bool
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(): array
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(): array
100
    {
101
        return [
102
            'string',
103
            'integer',
104
            'percent',
105
            'time',
106
            'currency',
107
            'float',
108
            'date'
109
        ];
110
    }
111
112
    /**
113
     * Get continents.
114
     *
115
     * @return array
116
     */
117
    public function getContinents(): array
118
    {
119
        return $this->_getData('continents');
120
    }
121
122
    /**
123
     * Get subcontinents.
124
     *
125
     * @return array
126
     */
127
    public function getSubContinents(): array
128
    {
129
        return $this->_getData('subContinents');
130
    }
131
132
    /**
133
     * Get Continent Code
134
     *
135
     * @param string $label
136
     *
137
     * @return mixed
138
     */
139
    public function getContinentCode($label)
140
    {
141
        foreach ($this->_getData('continents') as $continent) {
142
            if ($continent['label'] === $label) {
143
                return $continent['code'];
144
            }
145
        }
146
147
        return null;
148
    }
149
150
    /**
151
     * Get Sub-Continent Code
152
     *
153
     * @param string $label
154
     *
155
     * @return mixed
156
     */
157
    public function getSubContinentCode($label)
158
    {
159
        foreach ($this->_getData('subContinents') as $subContinent) {
160
            if ($subContinent['label'] === $label) {
161
                return $subContinent['code'];
162
            }
163
        }
164
165
        return null;
166
    }
167
168
    /**
169
     * Get a dimension or a metric label from its id
170
     *
171
     * @param string $id
172
     *
173
     * @return mixed
174
     */
175
    public function getDimMet($id)
176
    {
177
        $columns = $this->getColumns();
178
179
        if (isset($columns[$id])) {
180
            return $columns[$id]->uiName;
181
        }
182
183
        return null;
184
    }
185
186
    /**
187
     * Returns columns based on a search string `$q`
188
     *
189
     * @param string $q
190
     *
191
     * @return array
192
     */
193
    public function searchColumns($q): array
194
    {
195
        $columns = $this->getColumns();
196
        $results = [];
197
198
        foreach ($columns as $column) {
199
            if (stripos($column->id, $q) !== false || stripos($column->uiName, $q) !== false) {
200
                $results[] = $column;
201
            }
202
        }
203
204
        return $results;
205
    }
206
207
    /**
208
     * Returns columns
209
     *
210
     * @param string $type
211
     *
212
     * @return array
213
     */
214
    public function getColumns(string $type = null): array
215
    {
216
        if (!$this->columns) {
217
            $this->columns = $this->_loadColumns();
218
        }
219
220
        if (!$type) {
221
            return $this->columns;
222
        }
223
224
        return $this->getColumnsByType($type);
225
    }
226
227
    /**
228
     * Returns dimension columns
229
     *
230
     * @return array
231
     */
232
    public function getDimensions(): array
233
    {
234
        if (!$this->dimensions) {
235
            $this->dimensions = $this->getColumns('DIMENSION');
236
        }
237
238
        return $this->dimensions;
239
    }
240
241
    /**
242
     * Returns column groups
243
     *
244
     * @param string|null $type
245
     *
246
     * @return array
247
     */
248
    public function getColumnGroups(string $type = null): array
249
    {
250
        if ($type && isset($this->groups[$type])) {
251
            return $this->groups[$type];
252
        }
253
254
        $groups = $this->_getColumnGroups($type);
255
256
        if ($type) {
257
            $this->groups[$type] = $groups;
258
        }
259
260
        return $groups;
261
    }
262
263
    /**
264
     * Returns select dimension options
265
     *
266
     * @param array $filters
267
     *
268
     * @return array
269
     */
270
    public function getSelectDimensionOptions(array $filters = null): array
271
    {
272
        if (!$this->selectDimensionOptions) {
273
            $this->selectDimensionOptions = $this->getSelectOptions('DIMENSION');
274
        }
275
276
        if ($filters) {
277
            $this->selectDimensionOptions = $this->filterOptions($this->selectDimensionOptions, $filters);
278
        }
279
280
        return $this->selectDimensionOptions;
281
    }
282
283
    /**
284
     * Returns select metric options
285
     *
286
     * @param array $filters
287
     *
288
     * @return array
289
     */
290
    public function getSelectMetricOptions(array $filters = null): array
291
    {
292
        if (!$this->selectMetricOptions) {
293
            $this->selectMetricOptions = $this->getSelectOptions('METRIC');
294
        }
295
296
        if ($filters) {
297
            $this->selectMetricOptions = $this->filterOptions($this->selectMetricOptions, $filters);
298
        }
299
300
        return $this->selectMetricOptions;
301
    }
302
303
    /**
304
     * Returns select options
305
     *
306
     * @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...
307
     * @param array $filters
308
     *
309
     * @return array
310
     */
311
    public function getSelectOptions($type = null, array $filters = null): array
312
    {
313
        $options = [];
314
315
        foreach ($this->getColumnGroups($type) as $group) {
316
            $options[]['optgroup'] = Craft::t('analytics', $group);
317
318
            foreach ($this->getColumns($type) as $column) {
319
                if ($column->group === $group) {
320
                    $options[$column->id] = Craft::t('analytics', $column->uiName);
321
                }
322
            }
323
        }
324
325
        if ($filters) {
326
            $options = $this->filterOptions($options, $filters);
327
        }
328
329
        return $options;
330
    }
331
332
    /**
333
     * Returns the metrics
334
     *
335
     * @return array
336
     */
337
    public function getMetrics(): array
338
    {
339
        if (!$this->metrics) {
340
            $this->metrics = $this->getColumns('METRIC');
341
        }
342
343
        return $this->metrics;
344
    }
345
346
    /**
347
     * Returns the file path of the dimensions-metrics.json file
348
     *
349
     * @return string|bool
350
     */
351
    public function getDimmetsFilePath()
352
    {
353
        return Craft::getAlias('@dukt/analytics/etc/data/dimensions-metrics.json');
354
    }
355
356
    // Private Methods
357
    // =========================================================================
358
359
    /**
360
     * Loads the columns from the dimensions-metrics.json file
361
     *
362
     * @return array
363
     */
364
    private function _loadColumns(): array
365
    {
366
        $cols = [];
367
        $path = Analytics::$plugin->metadata->getDimmetsFilePath();
368
        $contents = file_get_contents($path);
369
        $columnsResponse = Json::decode($contents);
370
371
        if ($columnsResponse) {
372
            foreach ($columnsResponse as $columnResponse) {
373
                $cols[$columnResponse['id']] = new Column($columnResponse);
374
375
                if ($columnResponse['id'] === 'ga:countryIsoCode') {
376
                    $cols[$columnResponse['id']]->uiName = 'Country';
377
                }
378
            }
379
        }
380
381
        return $cols;
382
    }
383
384
    /**
385
     * Get Data
386
     *
387
     * @param $name
388
     *
389
     * @return array
390
     * @internal param string $label
391
     *
392
     */
393
    private function _getData($name): array
394
    {
395
        $jsonData = file_get_contents(Craft::getAlias('@dukt/analytics/etc/data/'.$name.'.json'));
396
397
        return json_decode($jsonData, true);
398
    }
399
400
    /**
401
     * @param array $options
402
     * @param array $filters
403
     *
404
     * @return array
405
     */
406
    private function filterOptions(array $options, array $filters): array
407
    {
408
        if (\count($filters) === 0) {
409
            return $options;
410
        }
411
412
        return $this->getFilteredOptions($options, $filters);
413
    }
414
415
    /**
416
     * Get filtered options.
417
     *
418
     * @param array $options
419
     * @param array $filters
420
     *
421
     * @return array
422
     */
423
    private function getFilteredOptions(array $options, array $filters): array
424
    {
425
        $filteredOptions = [];
426
        $optgroup = null;
427
        $lastOptgroup = null;
428
429
        foreach ($options as $id => $option) {
430
            if (isset($option['optgroup'])) {
431
                $optgroup = null;
432
                $lastOptgroup = $option['optgroup'];
433
                continue;
434
            }
435
436
            foreach ($filters as $filter) {
437
                if ($id !== $filter) {
438
                    continue;
439
                }
440
441
                if (!$optgroup) {
442
                    $optgroup = $lastOptgroup;
443
                    $filteredOptions[]['optgroup'] = $optgroup;
444
                }
445
446
                $filteredOptions[$id] = $option;
447
            }
448
        }
449
450
        return $filteredOptions;
451
    }
452
453
    /**
454
     * Get column groups.
455
     *
456
     * @param string|null $type
457
     * @return array
458
     */
459
    private function _getColumnGroups(string $type = null): array
460
    {
461
        $groups = [];
462
463
        foreach ($this->getColumns() as $column) {
464
            if (!$type || ($type && $column->type === $type)) {
465
                $groups[$column->group] = $column->group;
466
            }
467
        }
468
469
        return $groups;
470
    }
471
472
    /**
473
     * Get columns by type.
474
     *
475
     * @param string $type
476
     * @return array
477
     */
478
    private function getColumnsByType(string $type): array
479
    {
480
        $columns = [];
481
482
        foreach ($this->columns as $column) {
483
            if ($column->type === $type) {
484
                $columns[] = $column;
485
            }
486
        }
487
488
        return $columns;
489
    }
490
}
491