Base::toCleanArray()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 13
ccs 9
cts 9
cp 1
rs 9.4285
cc 3
eloc 7
nc 3
nop 0
crap 3
1
<?php
2
3
namespace GFG\DTOContext\DataWrapper;
4
5
abstract class Base implements \ArrayAccess, DataWrapperInterface
6
{
7
    /**
8
     * Base constructor - you may use an array to initialize the dataWrapper
9
     *
10
     * @param array $data
11
     */
12 12
    public function __construct(array $data = array())
13
    {
14 12
        if (!empty($data)) {
15 7
            $ref = new \ReflectionObject($this);
16 7
            foreach ($ref->getProperties() as $property) {
17
                try {
18 7
                    $value = $this->getValue($data, $property->getName());
19 7
                    if ($this->isDataWrapper($property)) {
20 1
                        $value = $this->toDataWrapper($value, $property);
21 1
                    }
22 7
                    $property->setAccessible(true);
23 7
                    $property->setValue($this, $value);
24 7
                } catch (\Exception $e) {
25
                    // does nothing when we don't have a certain property in
26
                    // the $data array
27
                }
28 7
            }
29 7
        }
30 12
    }
31
32
    /**
33
     * Getter and Setters
34
     *
35
     * @param string $name
36
     * @param array $args
37
     * @throws \InvalidArgumentException
38
     * @return mixed
39
     */
40 6
    public function __call($name, array $args)
41
    {
42 6
        $getSet = substr($name, 0, 3);
43 6
        if (in_array($getSet, array('get', 'set'))) {
44 5
            $property = lcfirst(substr($name, 3));
45 5
            $ref = new \ReflectionObject($this);
46
47 5
            if ($ref->hasProperty($property)) {
48 4
                $property = $ref->getProperty($property);
49 4
                $property->setAccessible(true);
50
51 4
                if ($getSet === 'get') {
52 4
                    $return = $property->getValue($this);
53
54 4
                    if (is_null($return) && $this->isDataWrapper($property)) {
55 1
                        $return = $this->toDataWrapper([], $property);
56 1
                    }
57
58 4
                } else {
59 2
                    $property->setValue($this, $args[0]);
60 2
                    $return = $this;
61
                }
62
63 4
                return $return;
64
            }
65
66 1
            throw new \InvalidArgumentException(
67 1
                sprintf('Property %s does not exists', $property)
68 1
            );
69
        }
70
71 1
        throw new \InvalidArgumentException('Method does not exists');
72
    }
73
74
    /**
75
     * Export dataWrapper values as an array
76
     *
77
     * @return array
78
     */
79 6
    public function toArray()
80
    {
81 6
        $ref = new \ReflectionObject($this);
82 6
        $export = array();
83
84 6
        foreach ($ref->getProperties() as $property) {
85 6
            $property->setAccessible(true);
86 6
            $name = strtolower(
87 6
                preg_replace('@([A-Z])@', '_\1', $property->getName())
88 6
            );
89 6
            $export[$name] = $property->getValue($this);
90
91 6
            if ($export[$name] instanceof DataWrapperInterface) {
92 2
                $export[$name] = $export[$name]->toArray();
93 6
            } elseif ($export[$name] instanceof \DateTime) {
94 1
                $export[$name] = $export[$name]->format('Y-m-d');
95 1
            }
96 6
        }
97
98 6
        return $export;
99
    }
100
101
    /**
102
     * ToArray with unset null fields
103
     *
104
     * @return array
105
     */
106 1
    public function toCleanArray()
107
    {
108 1
        $export = $this->toArray();
109
110 1
        $cleanExport = array();
111 1
        foreach ($export as $key => $value) {
112 1
            if ($value) {
113 1
                $cleanExport[$key] = $value;
114 1
            }
115 1
        }
116
117 1
        return $cleanExport;
118
    }
119
120
    /**
121
     * Extract dataWrapper $property value from $data
122
     *
123
     * @param array $data
124
     * @param string $property
125
     * @throws \OutOfBoundsException
126
     * @return mixed
127
     */
128 7
    private function getValue(array $data, $property)
129
    {
130 7
        if (isset($data[$property])) {
131 5
            return $data[$property];
132
        }
133
134 6
        $property = strtolower(preg_replace('@([A-Z])@', '_\1', $property));
135 6
        if (isset($data[$property])) {
136 3
            return $data[$property];
137
        }
138
139 4
        throw new \OutOfBoundsException('');
140
    }
141
142
    /**
143
     * Convert from underscore to camel case
144
     *
145
     * @param string $name
146
     * @return string
147
     */
148 9
    private function toCamelCase($name)
149
    {
150 9
        return lcfirst(
151 9
            str_replace(' ', '', ucwords(str_replace('_', ' ', $name)))
152 9
        );
153
    }
154
155
    /**
156
     * Convert from undescore to studly caps
157
     *
158
     * @param string $name
159
     * @return string
160
     */
161 9
    private function toStudlyCaps($name)
162
    {
163 9
        return ucfirst($this->toCamelCase($name));
164
    }
165
166
    /**
167
     * @param string $offset
168
     * @return mixed
169
     */
170 1
    public function offsetGet($offset)
171
    {
172 1
        $property = $this->toStudlyCaps($offset);
173 1
        return call_user_func(array($this, 'get' . $property));
174
    }
175
176
    /**
177
     * @param string $offset
178
     * @param mixed $value
179
     * @return mixed
180
     */
181 1
    public function offsetSet($offset, $value)
182
    {
183 1
        $property = $this->toStudlyCaps($offset);
184 1
        return call_user_func(array($this, 'set' . $property), $value);
185
    }
186
187
    /**
188
     * @param string $offset
189
     * @return boolean
190
     */
191 1
    public function offsetExists($offset)
192
    {
193 1
        $property = $this->toCamelCase($offset);
194 1
        return (new \ReflectionObject($this))->hasProperty($property);
195
    }
196
197
    /**
198
     * @param string $offset
199
     * @return void
200
     */
201 1
    public function offsetUnset($offset)
202
    {
203 1
        $this->offsetSet($offset, null);
204 1
    }
205
206
    /**
207
     * @param \ReflectionProperty $property
208
     * @return bool
209
     */
210 9
    public function isDataWrapper(\ReflectionProperty $property)
211
    {
212 9
        $class = $this->findType($property);
213
214 9
        if (!$class) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $class of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
215 4
            return false;
216
        }
217 7
        if (!class_exists($class)) {
218 5
            return false;
219
        }
220
221 2
        $ref = new \ReflectionClass($class);
222 2
        return $ref->implementsInterface(DataWrapperInterface::class);
223
    }
224
225
    /**
226
     * @param mixed $value
227
     * @param \ReflectionProperty $property
228
     * @return BaseCollection
229
     */
230 2
    public function toDataWrapper($value, \ReflectionProperty $property)
231
    {
232 2
        $type = $this->findType($property);
233 2
        return new $type($value);
234
    }
235
236
    /**
237
     * @param \ReflectionProperty $property
238
     * @return string
239
     */
240 9
    private function findType(\ReflectionProperty $property)
241
    {
242 9
        $class      = $property->getDeclaringClass();
243 9
        $doc        = $class->getDocComment();
244 9
        $getter     = 'get' . $this->toStudlyCaps($property->getName());
245 9
        $regex      = "#@method (.+?) #";
246
247 9
        foreach (explode(PHP_EOL, $doc) as $commentLine) {
248 9
            if (false !== strpos($commentLine, $getter)) {
249 8
                preg_match($regex, $commentLine, $matches);
250 8
                if (isset($matches[1])) {
251 7
                    return $matches[1];
252
                }
253 1
            }
254 9
        }
255 4
    }
256
}
257