Passed
Push — master ( 9d7ef7...af08db )
by Andrea Marco
01:42 queued 11s
created

ArrayConverter::addConversion()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 2
c 1
b 0
f 1
nc 1
nop 2
dl 0
loc 5
ccs 3
cts 3
cp 1
crap 1
rs 10
1
<?php
2
3
namespace Cerbero\Dto\Manipulators;
4
5
/**
6
 * The array converter.
7
 *
8
 */
9
class ArrayConverter
10
{
11
    /**
12
     * The snake case pattern
13
     *
14
     * - Look behind for lower case letters or digits
15
     * - Look ahead for upper case letters
16
     */
17
    public const RE_SNAKE_CASE = '/(?<=[a-z\d])(?=[A-Z])/';
18
19
    /**
20
     * The class instance.
21
     *
22
     * @var self
23
     */
24
    protected static $instance;
25
26
    /**
27
     * The registered conversions.
28
     *
29
     * @var array
30
     */
31
    protected $conversions = [];
32
33
    /**
34
     * The cached value converters.
35
     *
36
     * @var ValueConverter[]
37
     */
38
    protected $cachedConverters = [];
39
40
    /**
41
     * Instantiate the class
42
     *
43
     */
44 18
    protected function __construct()
45
    {
46
        //
47 18
    }
48
49
    /**
50
     * Retrieve the class instance
51
     *
52
     * @return self
53
     */
54 336
    public static function instance(): self
55
    {
56 336
        return static::$instance = static::$instance ?: new static();
57
    }
58
59
    /**
60
     * Set the given value conversions
61
     *
62
     * @param array $conversions
63
     * @return self
64
     */
65 21
    public function setConversions(array $conversions): self
66
    {
67 21
        $this->conversions = $conversions;
68
69 21
        return $this;
70
    }
71
72
    /**
73
     * Retrieve the value conversions
74
     *
75
     * @return array
76
     */
77 27
    public function getConversions(): array
78
    {
79 27
        return $this->conversions;
80
    }
81
82
    /**
83
     * Add a conversion
84
     *
85
     * @param string $class
86
     * @param string $converter
87
     * @return self
88
     */
89 3
    public function addConversion(string $class, string $converter): self
90
    {
91 3
        $this->conversions[$class] = $converter;
92
93 3
        return $this;
94
    }
95
96
    /**
97
     * Remove a conversion
98
     *
99
     * @param string $class
100
     * @return self
101
     */
102 3
    public function removeConversion(string $class): self
103
    {
104 3
        unset($this->conversions[$class]);
105
106 3
        return $this;
107
    }
108
109
    /**
110
     * Convert the given item into an array
111
     *
112
     * @param mixed $item
113
     * @param bool $snakeCase
114
     * @return mixed
115
     */
116 63
    public function convert($item, $snakeCase = false)
117
    {
118 63
        if (is_object($item) && $converter = $this->getConverterByInstance($item)) {
119 3
            return $converter->fromDto($item);
120
        }
121
122 63
        if (is_iterable($item)) {
123 24
            $result = [];
124
125 24
            foreach ($item as $key => $value) {
126 24
                $formattedKey = $this->formatArrayKey($key, $snakeCase);
127 24
                $result[$formattedKey] = $this->convert($value);
128
            }
129
130 24
            return $result;
131
        }
132
133 63
        return $item;
134
    }
135
136
    /**
137
     * Retrieve the converter for the given object instance
138
     *
139
     * @param object $instance
140
     * @return ValueConverter|null
141
     */
142 21
    public function getConverterByInstance($instance): ?ValueConverter
143
    {
144 21
        $class = get_class($instance);
145
146 21
        if (isset($this->cachedConverters[$class])) {
147 3
            return $this->cachedConverters[$class];
148
        }
149
150 21
        foreach ($this->getConversions() as $type => $class) {
151 6
            if (is_a($instance, $type)) {
152 6
                $converter = $this->resolveConverter($class);
153 6
                return $this->cachedConverters[$class] = $this->cachedConverters[$type] = $converter;
154
            }
155
        }
156
157 18
        return null;
158
    }
159
160
    /**
161
     * Retrieve the instance of the given converter
162
     *
163
     * @param string $converter
164
     * @return ValueConverter
165
     */
166 9
    protected function resolveConverter(string $converter): ValueConverter
167
    {
168 9
        return new $converter();
169
    }
170
171
    /**
172
     * Retrieve the formatted array key
173
     *
174
     * @param string $key
175
     * @param bool $snakeCase
176
     * @return string
177
     */
178 24
    protected function formatArrayKey(string $key, bool $snakeCase): string
179
    {
180 24
        if (!$snakeCase) {
181 15
            return $key;
182
        }
183
184 15
        return strtolower(preg_replace(static::RE_SNAKE_CASE, '_', $key));
185
    }
186
187
    /**
188
     * Retrieve the converter for the given class
189
     *
190
     * @param string $class
191
     * @return ValueConverter|null
192
     */
193 321
    public function getConverterByClass(string $class): ?ValueConverter
194
    {
195 321
        if (isset($this->cachedConverters[$class])) {
196 12
            return $this->cachedConverters[$class];
197
        }
198
199 315
        if ($converter = $this->conversions[$class] ?? null) {
200 3
            return $this->cachedConverters[$class] = $this->resolveConverter($converter);
201
        }
202
203 315
        return null;
204
    }
205
}
206