Passed
Pull Request — master (#10)
by
unknown
02:22
created

ExporterService   A

Complexity

Total Complexity 33

Size/Duplication

Total Lines 138
Duplicated Lines 0 %

Test Coverage

Coverage 98.39%

Importance

Changes 3
Bugs 0 Features 0
Metric Value
wmc 33
eloc 49
c 3
b 0
f 0
dl 0
loc 138
ccs 61
cts 62
cp 0.9839
rs 9.76

15 Methods

Rating   Name   Duplication   Size   Complexity  
A exportFrom() 0 3 1
A createCollection() 0 3 1
A hasWildcard() 0 3 1
A exportNestedAttributes() 0 3 1
A collect() 0 3 1
A export() 0 12 3
A getAttributeValueWithWildcard() 0 9 3
B getNewTarget() 0 15 7
A getAttributeValue() 0 18 5
A exportWildcard() 0 4 1
A exportArray() 0 7 2
A __construct() 0 3 1
A exportNestedAttribute() 0 3 1
A exportAttribute() 0 11 3
A attributeIsAFunction() 0 7 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 13
    public function __construct($exportable)
13
    {
14 13
        $this->exportable = $exportable;
15 13
    }
16
17 3
    public static function exportFrom($exportable, array $attributes): Collection
18
    {
19 3
        return (new self($exportable))->export($attributes);
20
    }
21
22 13
    public function export(array $attributes): Collection
23
    {
24
        return $this->createCollection($attributes, function ($attribute, $key) {
25 13
            if (is_array($attribute)) {
26 3
                return $this->exportArray($key, $attribute);
27
            }
28
29 13
            if (!is_int($key)) {
30 2
                return $this->exportNestedAttribute($key, $attribute);
31
            }
32
33 13
            return $this->exportAttribute($attribute);
34 13
        });
35
    }
36
37 13
    protected function createCollection(array $attributes, callable $callback): Collection
38
    {
39 13
        return $this->collect($attributes)->mapWithKeys($callback);
40
    }
41
42 13
    protected function collect($items): Collection
43
    {
44 13
        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 2
    protected function exportWildcard(string $key, array $array): array
62
    {
63
        return [$key => $this->collect($this->getAttributeValue($key))->map(function ($exportable) use ($array) {
64 2
            return self::exportFrom($exportable, $array['*']);
65 2
        })];
66
    }
67
68 12
    protected function getAttributeValue($attributes)
69
    {
70 12
        $attributes = is_array($attributes) ? $attributes : explode('.', $attributes);
71
72 12
        $target = $this->exportable;
73 12
        while (($segment = array_shift($attributes)) !== null) {
74 12
            if ($segment === '*') {
75 1
                return $this->getAttributeValueWithWildcard($target, $attributes);
76
            }
77
78
            try {
79 12
                $target = $this->getNewTarget($target, $segment);
80 2
            } catch (NotFoundException $e) {
81 2
                return null;
82
            }
83
        }
84
85 11
        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 12
    protected function getNewTarget($target, $segment)
100
    {
101 12
        if (Arr::accessible($target) && Arr::exists($target, $segment)) {
102 8
            return $target[$segment];
103
        }
104
105 5
        if (is_object($target) && isset($target->{$segment})) {
106 5
            return $target->{$segment};
107
        }
108
109 4
        if (is_object($target) && method_exists($target, $getter = 'get' . ucfirst($segment))) {
110 2
            return call_user_func([$target, $getter]);
111
        }
112
113 2
        throw new NotFoundException($segment, $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 13
    protected function exportAttribute(string $attribute)
127
    {
128 13
        if ($export = $this->attributeIsAFunction($attribute)) {
129 2
            return $export;
130
        }
131
132 12
        if (preg_match('/^(.*) as (.*)$/', $attribute, $matches)) {
133
            return [$matches[2] => $this->getAttributeValue($matches[1])];
134
        }
135
136 12
        return [$attribute => $this->getAttributeValue($attribute)];
137
    }
138
139 13
    protected function attributeIsAFunction($attribute)
140
    {
141 13
        if (preg_match("/(.*)\((.*)\)$/", $attribute, $matches)) {
142 2
            return [$matches[1] => call_user_func_array([$this->exportable, $matches[1]], array_map('trim', explode(',', $matches[2])))];
143
        }
144
145 12
        return null;
146
    }
147
}
148