Passed
Push — master ( 1f886f...7762f8 )
by Mathieu
01:31
created

ExporterService::getNewTarget()   B

Complexity

Conditions 7
Paths 4

Size

Total Lines 15
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 7

Importance

Changes 0
Metric Value
dl 0
loc 15
ccs 8
cts 8
cp 1
rs 8.2222
c 0
b 0
f 0
cc 7
eloc 7
nc 4
nop 2
crap 7
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 11
    protected function getAttributeValue($attributes)
69
    {
70 11
        $attributes = is_array($attributes) ? $attributes : explode('.', $attributes);
71
72 11
        $target = $this->exportable;
73 11
        while (($segment = array_shift($attributes)) !== null) {
74 11
            if ($segment === '*') {
75 1
                return $this->getAttributeValueWithWildcard($target, $attributes);
76
            }
77
78
            try {
79 11
                $target = $this->getNewTarget($target, $segment);
80 1
            } catch (\Exception $e) {
81 1
                return null;
82
            }
83
        }
84
85 10
        return $target;
86
    }
87
88 1
    protected function getAttributeValueWithWildcard($target, $attribute)
89
    {
90 1
        if (!is_iterable($target)) {
91 1
            return null;
92
        }
93
94 1
        $result = Arr::pluck($target, $attribute);
95
96 1
        return in_array('*', $attribute) ? Arr::collapse($result) : $result;
97
    }
98
99 11
    protected function getNewTarget($target, $segment)
100
    {
101 11
        if (Arr::accessible($target) && Arr::exists($target, $segment)) {
102 8
            return $target[$segment];
103
        }
104
105 4
        if (is_object($target) && isset($target->{$segment})) {
106 4
            return $target->{$segment};
107
        }
108
109 3
        if (is_object($target) && method_exists($target, $getter = 'get' . ucfirst($segment))) {
110 2
            return call_user_func([$target, $getter]);
111
        }
112
113 1
        throw new \RuntimeException("$segment can't be found in $target");
114
    }
115
116 2
    protected function exportNestedAttributes(string $key, array $array): array
117
    {
118 2
        return [$key => self::exportFrom($this->getAttributeValue($key), $array)];
119
    }
120
121 2
    protected function exportNestedAttribute($key, $attribute): array
122
    {
123 2
        return [$key => $this->getAttributeValue("$key.$attribute")];
124
    }
125
126 12
    protected function exportAttribute(string $attribute)
127
    {
128 12
        if ($export = $this->attributeIsAFunction($attribute)) {
129 2
            return $export;
130
        }
131
132 11
        return [$attribute => $this->getAttributeValue($attribute)];
133
    }
134
135 12
    protected function attributeIsAFunction($attribute)
136
    {
137 12
        if (preg_match("/(.*)\((.*)\)$/", $attribute, $groups)) {
138 2
            return [$groups[1] => call_user_func_array([$this->exportable, $groups[1]], array_map('trim', explode(',', $groups[2])))];
139
        }
140
141 11
        return null;
142
    }
143
}
144