Cleaner::setProperty()   B
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 28
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 28
rs 8.5806
c 0
b 0
f 0
cc 4
eloc 21
nc 4
nop 5
1
<?php
2
3
namespace LaravelLaundromat;
4
5
use Illuminate\Support\Collection;
6
use Illuminate\Database\Eloquent\Model;
7
8
class Cleaner
9
{
10
    /**
11
     * Properties allowed on the clean object.
12
     *
13
     * @var array
14
     */
15
    protected $allowed = [];
16
17
    /**
18
     * Methods to run. Returned value will be stored as a snake case property
19
     * on the clean object.
20
     *
21
     * @var array
22
     */
23
    protected $methods = [];
24
25
    /**
26
     * Clean the dirty object.
27
     *
28
     * @param object $dirty
29
     *
30
     * @return this
31
     */
32
    public function clean($dirty)
33
    {
34
        $this->setAllowed($dirty);
35
36
        $this->setMethods($dirty);
37
38
        return $this;
39
    }
40
41
    /**
42
     * Call snake_cased property names with studlyCased methods.
43
     *
44
     * @param string $name      [Name of method called]
45
     * @param array  $arguments
46
     *
47
     * @return mixed
48
     */
49
    public function __call($name, $arguments)
50
    {
51
        $name = snake_case($name);
52
53
        return $this->{$name};
54
    }
55
56
    /**
57
     * Set allowed properties on cleaner object.
58
     *
59
     * @param object $dirty
60
     */
61 View Code Duplication
    protected function setAllowed($dirty)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
62
    {
63
        collect($this->allowed)->each(function ($property) use ($dirty) {
64
            if ($this->isNested($property)) {
65
                return $this->setNestedProperty($property, $dirty, 'property');
66
            }
67
68
            $this->setProperty($dirty, $property, $this, 'property');
69
        });
70
    }
71
72
    /**
73
     * Set properties from methods on cleaner object.
74
     *
75
     * @param object $dirty
76
     */
77 View Code Duplication
    protected function setMethods($dirty)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
78
    {
79
        collect($this->methods)->each(function ($method) use ($dirty) {
80
            if ($this->isNested($method)) {
81
                return $this->setNestedProperty($method, $dirty, 'method');
82
            }
83
84
            $this->setProperty($dirty, $method, $this, 'method');
85
        });
86
    }
87
88
    /**
89
     * Property is a nested property.
90
     *
91
     * @param string $property
92
     *
93
     * @return bool
94
     */
95
    protected function isNested($property)
96
    {
97
        return strpos($property, '.') !== false;
98
    }
99
100
    /**
101
     * Set the nested property on the cleaner object.
102
     *
103
     * @param string $propString [Property string]
104
     * @param Model  $dirty      [Original dirty object]
105
     * @param string $type       [Type of nested property: 'property', 'method']
106
     * @param object $object     [Object to set property on]
107
     */
108
    protected function setNestedProperty($propString, Model $dirty, $type, $object = null)
109
    {
110
        $object = is_null($object) ? $this : $object;
111
112
        $relation = $this->setRelation($propString, $object);
113
114
        $property = $this->getProperty($propString);
115
116
        if ($this->isNested($property)) {
117
            $newDirty = $dirty->{$relation};
118
119
            $newObject = $this->{$relation};
120
121
            $this->setNestedProperty($property, $newDirty, $type, $newObject);
122
        } else {
123
            $this->setProperty($dirty, $property, $object, $type, $relation);
124
        }
125
    }
126
127
    /**
128
     * Create relation on object.
129
     *
130
     * @param string $property
131
     * @param object $object
132
     *
133
     * @return string
134
     */
135
    protected function setRelation($property, $object)
136
    {
137
        $relation = explode('.', $property)[0];
138
139
        $this->createRelation($relation, $object);
140
141
        return $relation;
142
    }
143
144
    /**
145
     * Get property name from nested property.
146
     *
147
     * @param string $property
148
     *
149
     * @return string
150
     */
151
    protected function getProperty($property)
152
    {
153
        return collect(explode('.', $property))->forget(0)->implode('.');
154
    }
155
156
    /**
157
     * If relation doesnt not exist on cleaner object, create it.
158
     *
159
     * @param string $relation
160
     * @param object $object   [Object to create relation on]
161
     */
162
    protected function createRelation($relation, $object)
163
    {
164
        if (!isset($object->{$relation})) {
165
            $class = new EmptyCleaner();
166
167
            $object->{$relation} = $class;
168
        }
169
    }
170
171
    /**
172
     * Set property value on clean object.
173
     *
174
     * @param Model   $dirty    [Original, dirty object]
175
     * @param string  $property [Property name]
176
     * @param Cleaner $object   [Clean object]
177
     * @param string  $type     [Type of property: 'property', 'method']
178
     * @param string  $relation [Relationship name]
179
     */
180
    protected function setProperty(
181
        Model $dirty,
182
        $property,
183
        Cleaner $object,
184
        $type,
185
        $relation = null
186
    ) {
187
        $key = snake_case($property);
188
189
        if (is_null($relation)) {
190
            return $this->{$key} = $this->getValue($dirty, $property, $type);
191
        } elseif (is_null($dirty->{$relation})) {
192
            return $object->{$relation} = null;
193
        } elseif (!$dirty->{$relation} instanceof Collection) {
194
            $value = $this->getValue($dirty->{$relation}, $property, $type);
195
196
            return $object->{$relation}->{$key} = $value;
197
        }
198
199
        $this->setPropertiesOnRelations(
200
            $dirty,
201
            $property,
202
            $object,
203
            $type,
204
            $relation,
205
            $key
206
        );
207
    }
208
209
    /**
210
     * Set property value on clean object.
211
     *
212
     * @param Model   $dirty    [Original, dirty object]
213
     * @param string  $property [Property name]
214
     * @param Cleaner $object   [Clean object]
215
     * @param string  $type     [Type of property: 'property', 'method']
216
     * @param string  $relation [Relationship name]
217
     * @param string  $key
218
     */
219
    protected function setPropertiesOnRelations(
220
        Model $dirty,
221
        $property,
222
        Cleaner $object,
223
        $type,
224
        $relation,
225
        $key
226
    ) {
227
        if ($object->{$relation} instanceof EmptyCleaner) {
228
            $object->{$relation} = [];
229
        }
230
231
        foreach ($dirty->{$relation} as $index => $dirtyObject) {
232
            if (!isset($object->{$relation}[$index])) {
233
                $object->{$relation}[$index] = new EmptyCleaner();
234
            }
235
236
            $value = $this->getValue($dirtyObject, $property, $type);
237
238
            $object->{$relation}[$index]->{$key} = $value;
239
        }
240
    }
241
242
    /**
243
     * Get the value from the named property/method off object.
244
     *
245
     * @param Model  $object [Object which contains property/method]
246
     * @param string $name   [Name of property/method]
247
     * @param string $type   ['method' or 'property']
248
     *
249
     * @return mixed
250
     */
251
    protected function getValue(Model $object, $name, $type)
252
    {
253
        if ($type === 'method') {
254
            if (method_exists($object, $name)) {
255
                return $object->{$name}();
256
            }
257
258
            return;
259
        }
260
261
        return $object->{$name};
262
    }
263
}
264