Passed
Push — master ( c9a540...1f886f )
by Mathieu
02:20
created

ExporterService::exportAttribute()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 7
rs 9.4285
c 0
b 0
f 0
ccs 4
cts 4
cp 1
cc 2
eloc 3
nc 2
nop 1
crap 2
1
<?php
2
3
namespace MathieuTu\Exporter;
4
5
use Tightenco\Collect\Support\Arr;
6
use Tightenco\Collect\Support\Collection;
7
8
class ExporterService
9
{
10
    protected $exportable;
11
12 12
    public function __construct($exportable)
13
    {
14 12
        $this->exportable = $exportable;
15 12
    }
16
17 3
    public static function exportFrom($exportable, array $attributes): Collection
18
    {
19 3
        return (new self($exportable))->export($attributes);
20
    }
21
22
    public function export(array $attributes): Collection
23
    {
24 12
        return $this->createCollection($attributes, function ($attribute, $key) {
25 12
            if (is_array($attribute)) {
26 3
                return $this->exportArray($key, $attribute);
27
            }
28
29 12
            if (!is_int($key)) {
30 2
                return $this->exportNestedAttribute($key, $attribute);
31
            }
32
33 12
            return $this->exportAttribute($attribute);
34 12
        });
35
    }
36
37 12
    protected function createCollection(array $attributes, callable $callback): Collection
38
    {
39 12
        return $this->collect($attributes)->mapWithKeys($callback);
40
    }
41
42 12
    protected function collect($items): Collection
43
    {
44 12
        return Collection::make($items);
45
    }
46
47 3
    protected function exportArray(string $key, array $attribute): array
48
    {
49 3
        if ($this->hasWildcard($attribute)) {
50 2
            return $this->exportWildcard($key, $attribute);
51
        }
52
53 2
        return $this->exportNestedAttributes($key, $attribute);
54
    }
55
56 3
    protected function hasWildcard(array $array): bool
57
    {
58 3
        return array_keys($array) === ['*'];
59
    }
60
61
    protected function exportWildcard(string $key, array $array): array
62
    {
63 2
        return [$key => $this->collect($this->getAttributeValue($key))->map(function ($exportable) use ($array) {
64 2
            return self::exportFrom($exportable, $array['*']);
65 2
        })];
66
    }
67
68 2
    protected function exportNestedAttributes(string $key, array $array): array
69
    {
70 2
        return [$key => self::exportFrom($this->getAttributeValue($key), $array)];
71
    }
72
73 2
    protected function exportNestedAttribute($key, $attribute): array
74
    {
75 2
        return [$key => $this->getAttributeValue("$key.$attribute")];
76
    }
77
78 12
    protected function exportAttribute(string $attribute)
79
    {
80 12
        if ($export = $this->attributeIsAFunction($attribute)) {
81 2
            return $export;
82
        }
83
84 11
        return [$attribute => $this->getAttributeValue($attribute)];
85
    }
86
87 12
    protected function attributeIsAFunction($attribute)
88
    {
89 12
        if (preg_match("/(.*)\((.*)\)$/", $attribute, $groups)) {
90 2
            return [$groups[1] => call_user_func_array([$this->exportable, $groups[1]], array_map('trim', explode(',', $groups[2])))];
91
        }
92
93 11
        return null;
94
    }
95
96 11
    protected function getAttributeValue($attribute, $default = null)
97
    {
98
        // inspired by Laravel's data_get method.
99 11
        $target = $this->exportable;
100
101 11
        $attribute = is_array($attribute) ? $attribute : explode('.', $attribute);
102
103 11
        while (($segment = array_shift($attribute)) !== null) {
104 11
            if ($segment === '*') {
105 1
                if ($target instanceof Collection) {
106 1
                    $target = $target->all();
107 1
                } elseif (!is_array($target)) {
108 1
                    return value($default);
109
                }
110
111 1
                $result = Arr::pluck($target, $attribute);
112
113 1
                return in_array('*', $attribute) ? Arr::collapse($result) : $result;
114
            }
115
116 11
            if (Arr::accessible($target) && Arr::exists($target, $segment)) {
117 8
                $target = $target[$segment];
118 4
            } elseif (is_object($target) && isset($target->{$segment})) {
119 4
                $target = $target->{$segment};
120 3
            } elseif (is_object($target) && method_exists($target, $getter = 'get' . ucfirst($segment))) {
121 2
                $target = call_user_func([$target, $getter]);
122
            } else {
123 1
                return value($default);
124
            }
125
        }
126
127 10
        return $target;
128
    }
129
}
130