Passed
Push — main ( 7e0081...d3da7f )
by Gabriel
01:42
created

TrackOriginalTrait::getDirty()   A

Complexity

Conditions 5
Paths 12

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 5
eloc 7
c 1
b 0
f 1
nc 12
nop 1
dl 0
loc 12
rs 9.6111
ccs 0
cts 5
cp 0
crap 30
1
<?php
2
3
namespace ByTIC\DataObjects\Behaviors\TrackOriginal;
4
5
use InvalidArgumentException;
6
use Nip\Utility\Arr;
7
8
/**
9
 * Trait TrackOriginalTrait
10
 * @package ByTIC\DataObjects\Behaviors\TrackOriginal
11
 */
12
trait TrackOriginalTrait
13
{
14
    use \ByTIC\DataObjects\Legacy\Behaviors\OldDBDataTrait;
15
16
    /**
17
     * The Object original state.
18
     *
19
     * @var array
20
     */
21
    protected $original = [];
22
23
    /**
24
     * @param $data
25
     */
26
    public function fillOriginal($data)
27
    {
28
        foreach ($data as $key => $value) {
29
            $this->original[$key] = $value;
30
        }
31
    }
32
33
    public function getOriginalData(): array
34
    {
35
        return $this->original;
36
    }
37
38
    /**
39
     * Returns the value of an original field by name
40
     *
41
     * @param string $field the name of the field for which original value is retrieved.
42
     * @param null $default
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $default is correct as it would always require null to be passed?
Loading history...
43
     * @return mixed
44
     */
45
    public function getOriginal(string $field, $default = null)
46
    {
47
        if (!strlen($field)) {
48
            throw new InvalidArgumentException('Cannot get an empty field');
49
        }
50
51
        if (array_key_exists($field, $this->original)) {
52
            return $this->original[$field];
53
        }
54
55
        return $this->get($field, $default);
0 ignored issues
show
Bug introduced by
It seems like get() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

55
        return $this->/** @scrutinizer ignore-call */ get($field, $default);
Loading history...
56
    }
57
58 15
    /**
59
     * Get the model's raw original attribute values.
60 15
     *
61 15
     * @param string|null $key
62
     * @param mixed $default
63
     * @return mixed|array
64
     */
65
    public function getRawOriginal($key = null, $default = null)
66
    {
67
        return Arr::get($this->original, $key, $default);
68
    }
69
70
    /**
71
     * Sync the original attributes with the current.
72
     *
73
     * @return $this
74
     */
75
    public function syncOriginal(): self
76
    {
77
        $keys = array_merge(array_keys($this->original), array_keys($this->getAttributes()));
0 ignored issues
show
Bug introduced by
It seems like getAttributes() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

77
        $keys = array_merge(array_keys($this->original), array_keys($this->/** @scrutinizer ignore-call */ getAttributes()));
Loading history...
78
        $keys =  array_unique(array_filter($keys));
79
        $data = [];
80
        foreach ($keys as $key) {
81
            $data[$key] = $this->getPropertyRaw($key);
0 ignored issues
show
Bug introduced by
It seems like getPropertyRaw() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

81
            /** @scrutinizer ignore-call */ 
82
            $data[$key] = $this->getPropertyRaw($key);
Loading history...
82
        }
83
        $this->original = $data;
84
        return $this;
85
    }
86
87
    /**
88
     * Determine if the model or any of the given attribute(s) have been modified.
89
     *
90
     * @param array|string|null $attributes
91
     * @return bool
92
     */
93
    public function isDirty($attributes = null)
94
    {
95
        return $this->hasChanges(
96
            $this->getDirty(),
97
            is_array($attributes) ? $attributes : func_get_args()
98
        );
99
    }
100
101
    /**
102
     * Determine if the model and all the given attribute(s) have remained the same.
103
     *
104
     * @param array|string|null $attributes
105
     * @return bool
106
     */
107
    public function isClean($attributes = null)
108
    {
109
        return !$this->isDirty(...func_get_args());
110
    }
111
112
    /**
113
     * Determine if the model or any of the given attribute(s) have been modified.
114
     *
115
     * @param array|string|null $attributes
116
     * @return bool
117
     */
118
    public function wasChanged($attributes = null)
119
    {
120
        return $this->hasChanges(
121
            $this->getChanges(),
0 ignored issues
show
Bug introduced by
It seems like getChanges() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

121
            $this->/** @scrutinizer ignore-call */ 
122
                   getChanges(),
Loading history...
122
            is_array($attributes) ? $attributes : func_get_args()
123
        );
124
    }
125
126
    /**
127
     * Get the attributes that have been changed since last sync.
128
     *
129
     * @param null $fields
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $fields is correct as it would always require null to be passed?
Loading history...
130
     * @return array
131
     */
132
    public function getDirty($fields = null): array
133
    {
134
        $dirty = [];
135
        $fields = is_array($fields) && count($fields) > 0 ? $fields : array_keys($this->getAttributes());
0 ignored issues
show
introduced by
The condition is_array($fields) is always false.
Loading history...
136
        foreach ($fields as $field) {
137
            $value = $this->getPropertyRaw($field);
138
            if (!$this->originalIsEquivalent($field, $value)) {
139
                $dirty[$field] = $value;
140
            }
141
        }
142
143
        return $dirty;
144
    }
145
146
    /**
147
     * Determine if any of the given attributes were changed.
148
     *
149
     * @param array $changes
150
     * @param array|string|null $attributes
151
     * @return bool
152
     */
153
    protected function hasChanges($changes, $attributes = null)
154
    {
155
        // If no specific attributes were provided, we will just see if the dirty array
156
        // already contains any attributes. If it does we will just return that this
157
        // count is greater than zero. Else, we need to check specific attributes.
158
        if (empty($attributes)) {
159
            return count($changes) > 0;
160
        }
161
162
        // Here we will spin through every attribute and see if this is in the array of
163
        // dirty attributes. If it is, we will return true and if we make it through
164
        // all of the attributes for the entire array we will return false at end.
165
        foreach (Arr::wrap($attributes) as $attribute) {
166
            if (array_key_exists($attribute, $changes)) {
167
                return true;
168
            }
169
        }
170
171
        return false;
172
    }
173
174
    /**
175
     * @param string $key
176
     * @param null $value
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $value is correct as it would always require null to be passed?
Loading history...
177
     * @return bool
178
     */
179
    protected function originalIsEquivalent(string $key, $value = null): bool
180
    {
181
        if (!array_key_exists($key, $this->original)) {
182
            return false;
183
        }
184
        $attribute = $value ?? $this->getPropertyRaw($key);
185
        $original = Arr::get($this->original, $key);
186
187
        if ($attribute === $original) {
188
            return true;
189
        }
190
191
        return is_numeric($attribute) && is_numeric($original)
192
            && strcmp((string)$attribute, (string)$original) === 0;
193
    }
194
}
195