Completed
Push — master ( 0789a9...c06330 )
by Michael
01:33
created

NullableFields::nullIfEmpty()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 12
ccs 7
cts 7
cp 1
rs 9.2
c 0
b 0
f 0
nc 6
cc 4
eloc 6
nop 2
crap 4
1
<?php
2
3
namespace Iatstuti\Database\Support;
4
5
/**
6
 * Nullable (database) fields trait.
7
 *
8
 * Include this trait in any Eloquent models you wish to automatically set
9
 * empty field values to null on. When saving, iterate over the model's
10
 * attributes and if their value is empty, make it null before save.
11
 *
12
 * @copyright  2015 IATSTUTI
13
 * @author     Michael Dyrynda <[email protected]>
14
 */
15
trait NullableFields
16
{
17
    /**
18
     * Get all of the current attributes on the model.
19
     *
20
     * @return array
21
     */
22
    abstract public function getAttributes();
23
24
25
    /**
26
     * Get an attribute from the model.
27
     *
28
     * @param  string  $key
29
     * @return mixed
30
     */
31
    abstract public function getAttribute($key);
32
33
34
    /**
35
     * Determine whether a value is JSON castable for inbound manipulation.
36
     *
37
     * @param  string  $key
38
     *
39
     * @return bool
40
     */
41
    abstract protected function isJsonCastable($key);
42
43
44
    /**
45
     * Determine if a set mutator exists for an attribute.
46
     *
47
     * @param  string  $key
48
     * @return bool
49
     */
50
    abstract public function hasSetMutator($key);
51
52
53
    /**
54
     * Get the attributes that should be converted to dates.
55
     *
56
     * @return array
57
     */
58
    abstract public function getDates();
59
60
61
    /**
62
     * Boot the trait, add a saving observer.
63
     *
64
     * When saving the model, we iterate over its attributes and for any attribute
65
     * marked as nullable whose value is empty, we then set its value to null.
66
     */
67
    protected static function bootNullableFields()
68
    {
69 11
        static::saving(function ($model) {
70 11
            $model->setNullableFields();
71 11
        });
72 3
    }
73
74
75
    /**
76
     * Set empty nullable fields to null.
77
     *
78
     * @since  1.1.0
79
     *
80
     * @return void
81
     */
82 11
    protected function setNullableFields()
83
    {
84 11
        foreach ($this->nullableFromArray($this->getAttributes()) as $key => $value) {
85 10
            $this->attributes[$key] = $this->nullIfEmpty($value, $key);
0 ignored issues
show
Bug introduced by
The property attributes does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
86
        }
87 11
    }
88
89
90
    /**
91
     * If value is empty, return null, otherwise return the original input.
92
     *
93
     * @param  string $value
94
     * @param  null $key
95
     *
96
     * @return null|string
97
     */
98 17
    public function nullIfEmpty($value, $key = null)
99
    {
100 17
        if (! is_null($key)) {
101 10
            $value = $this->fetchValueForKey($key, $value);
102
        }
103
104 17
        if (is_array($value)) {
105 6
            return $this->nullIfEmptyArray($key, $value);
106
        }
107
108 13
        return trim($value) === '' ? null : $value;
109 2
    }
110
111
112 12
    /**
113
     * Get the nullable attributes of a given array.
114
     *
115
     * @param  array $attributes
116
     *
117
     * @return array
118
     */
119
    protected function nullableFromArray(array $attributes = [])
120
    {
121
        if (is_array($this->nullable) && count($this->nullable) > 0) {
122
            return array_intersect_key($attributes, array_flip($this->nullable));
123 11
        }
124
125 11
        // Assume no fields are nullable
126 11
        return [];
127
    }
128
129
130
    /**
131
     * Return value of the native PHP type as a json-encoded value
132
     *
133
     * @param  mixed $value
134
     *
135
     * @return string
136
     */
137
    private function setJsonCastValue($value)
138
    {
139
        return method_exists($this, 'asJson') ? $this->asJson($value) : json_encode($value);
140
    }
141 2
142
143 2
    /**
144
     * Return value of the json-encoded value as a native PHP type
145
     *
146
     * @param  mixed $value
147
     *
148
     * @return string
149
     */
150
    private function getJsonCastValue($value)
151
    {
152
        return method_exists($this, 'fromJson') ? $this->fromJson($value) : json_decode($value, true);
153
    }
154 2
155
156 2
    /**
157
     * For the given key and value pair, determine the actual value,
158
     * depending on whether or not a mutator or cast is in use.
159
     *
160
     * @param  string  $key
161
     * @param  mixed  $value
162
     *
163
     * @return mixed
164
     */
165
    private function fetchValueForKey($key, $value)
166
    {
167
        if (in_array($key, $this->getDates())) {
168
            return trim($value) === '' ? null : $value;
169 10
        }
170
171 10
        if (! $this->hasSetMutator($key)) {
172 2
            $value = $this->getAttribute($key);
173
        }
174
175 8
        if ($this->isJsonCastable($key) && ! is_null($value)) {
176 5
            $value = is_string($value) ? $this->getJsonCastValue($value) : $value;
177
        }
178
179 8
        return $value;
180 4
    }
181
182
183 8
    /**
184
     * Determine whether an array value is empty, taking into account casting.
185
     *
186
     * @param  string  $key
187
     * @param  array  $value
188
     *
189
     * @return mixed
190
     */
191
    private function nullIfEmptyArray($key, $value)
192
    {
193
        if ($this->isJsonCastable($key) && ! empty($value)) {
194
            return $this->setJsonCastValue($value);
195 6
        }
196
197 6
        return empty($value) ? null : $value;
198 2
    }
199
}
200