Test Setup Failed
Push — master ( f2414a...409ef1 )
by Carlos
17:39 queued 15:16
created

src/Traits/HasRevaluableAttributes.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
/*
4
 * This file is part of the overtrue/laravel-revaluation.
5
 *
6
 * (c) overtrue <[email protected]>
7
 *
8
 * This source file is subject to the MIT license that is bundled
9
 * with this source code in the file LICENSE.
10
 */
11
12
namespace Overtrue\LaravelRevaluation\Traits;
13
14
/**
15
 * Trait HasRevaluableAttributes.
16
 */
17
trait HasRevaluableAttributes
18
{
19
    /**
20
     * Revaluated attributes append to array.
21
     *
22
     * @var bool
23
     */
24
    //protected $appendRevaluatedAttributesToArray = true;
25
26
    /**
27
     * @var bool
28
     */
29
    //protected $replaceRawAttributesToArray = false;
30
31
    /**
32
     * Prefix of revaluated attribute getter.
33
     *
34
     * <pre>
35
     *      $model->revaluated_price;
36
     * </pre>
37
     *
38
     * @var string
39
     */
40
    //protected $revaluatedAttributePrefix = 'revaluated';
41
42
    /**
43
     * Return valuator instance of attribute.
44
     *
45
     * @param string $attribute
46
     *
47
     * @return \Overtrue\LaravelRevaluation\Revaluable
48
     */
49
    public function getRevaluatedAttribute($attribute)
50
    {
51
        $attribute = \Illuminate\Support\Str::snake($attribute);
52
53
        if ($valuator = $this->getAttributeValuator($attribute)) {
54
            return new $valuator(parent::getAttribute($attribute), $attribute, $this);
55
        }
56
57
        return false;
58
    }
59
60
    /**
61
     * Return revaluable attributes.
62
     *
63
     * @example
64
     *
65
     * <pre>
66
     * // 1. Using default valuator:
67
     * protected $revaluable = [
68
     *     'foo', 'bar', 'baz'
69
     * ];
70
     *
71
     * // 2. Use the specified valuator:
72
     * protected $revaluable = [
73
     *     'foo' => '\Foo\Support\Valuator\Foo',
74
     *     'bar' => '\Foo\Support\Valuator\Bar',
75
     *     'baz',
76
     * ];
77
     * </pre>
78
     *
79
     * @return array
80
     */
81
    public function getRevaluableAttributes()
82
    {
83
        if (!property_exists($this, 'revaluable') || !is_array($this->revaluable)) {
84
            return [];
85
        }
86
87
        $revaluable = [];
88
89
        foreach ($this->revaluable as $key => $valuator) {
90
            if (is_int($key)) {
91
                $revaluable[$valuator] = config('revaluation.default_valuator');
92
            } else {
93
                $revaluable[$key] = $valuator;
94
            }
95
        }
96
97
        return $revaluable;
98
    }
99
100
    /**
101
     * @return string
102
     */
103
    public function getRevaluableAttributePrefix()
104
    {
105
        return rtrim($this->revaluatedAttributePrefix ?? 'revaluated', '_');
106
    }
107
108
    /**
109
     * @example
110
     * <pre>
111
     * $object->revaluated_price;
112
     * $object->raw_price;
113
     * </pre>
114
     *
115
     * @param string $attribute
116
     *
117
     * @return mixed
118
     *
119
     * @throws \Exception
120
     */
121
    public function getAttribute($attribute)
122
    {
123
        if ($this->hasGetMutator($attribute)) {
124
            return parent::getAttribute($attribute);
125
        }
126
127
        if (\Illuminate\Support\Str::startsWith($attribute, 'raw_')) {
128
            return $this->getRevaluatedAttribute(substr($attribute, strlen('raw_')))->getRaw();
129
        }
130
131
        $prefix = $this->getRevaluableAttributePrefix();
132
        if (\Illuminate\Support\Str::startsWith($attribute, $prefix)) {
133
            return $this->getRevaluatedAttribute(substr($attribute, strlen($prefix) + 1));
134
        }
135
136
        if ($valuator = $this->getRevaluatedAttribute($attribute)) {
137
            return $valuator->toDefaultFormat();
138
        }
139
140
        return parent::getAttribute($attribute);
141
    }
142
143
    /**
144
     * Set attribute.
145
     *
146
     * @param string $attribute
147
     * @param mixed  $value
148
     *
149
     * @return $this
150
     */
151
    public function setAttribute($attribute, $value)
152
    {
153
        if ($valuator = $this->getAttributeValuator($attribute)) {
154
            $value = forward_static_call([$valuator, 'toStorableValue'], $value);
155
        }
156
157
        return parent::setAttribute($attribute, $value);
158
    }
159
160
    /**
161
     * Run the increment or decrement method on the model.
162
     *
163
     * @param string $column
164
     * @param int    $amount
165
     * @param array  $extra
166
     * @param string $method
167
     *
168
     * @return int
169
     */
170
    protected function incrementOrDecrement($column, $amount, $extra, $method)
171
    {
172
        $query = $this->newQuery();
173
174
        if (!$this->exists) {
175
            return $query->{$method}($column, $amount, $extra);
176
        }
177
178
        $this->incrementOrDecrementAttributeValue($column, $amount, $extra, $method);
179
180
        // ***[ fix increment/decrement bug]***
181
        if ($valuator = $this->getAttributeValuator($column)) {
182
            $amount = forward_static_call([$valuator, 'toStorableValue'], $amount);
183
        }
184
185
        return $query->where(
186
            $this->getKeyName(), $this->getKey()
0 ignored issues
show
Documentation Bug introduced by
The method getKeyName does not exist on object<Overtrue\LaravelR...asRevaluableAttributes>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
Documentation Bug introduced by
The method getKey does not exist on object<Overtrue\LaravelR...asRevaluableAttributes>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
187
        )->{$method}($column, $amount, $extra);
188
    }
189
190
    /**
191
     * Override HasAttributes::attributesToArray.
192
     *
193
     * @return array
194
     */
195
    public function attributesToArray()
196
    {
197
        $attributes = parent::attributesToArray();
198
199
        if ($this->shouldAppendRevaluatedAttributesToArray()) {
200
            foreach (array_keys($this->getRevaluableAttributes()) as $attribute) {
201
                if ($valuator = $this->getRevaluatedAttribute($attribute)) {
202
                    $attribute = $this->shouldReplaceRawAttributesToArray() ? $attribute : $this->getRevaluablePrefixedAttributeName($attribute);
203
                    $attributes[$attribute] = $valuator->toDefaultFormat();
204
                }
205
            }
206
        }
207
208
        return $attributes;
209
    }
210
211
    /**
212
     * @param string $attribute
213
     *
214
     * @return string
215
     */
216
    public function getRevaluablePrefixedAttributeName($attribute)
217
    {
218
        return $this->getRevaluableAttributePrefix().'_'.$attribute;
219
    }
220
221
    /**
222
     * Fetch attribute.
223
     *
224
     * @example
225
     * <pre>
226
     * $object->getRevaluatedPriceAttribute();
227
     * $object->getRevaluatedXXXAttribute();
228
     * </pre>
229
     *
230
     * @param string $method
231
     *
232
     * @return mixed
233
     */
234
    public function __call($method, $args)
235
    {
236
        $prefix = \Illuminate\Support\Str::studly($this->getRevaluableAttributePrefix());
237
        if (preg_match("/get{$prefix}(?<attribute>\\w+)Attribute/i", $method, $matches)) {
238
            return $this->getRevaluatedAttribute($matches['attribute']);
239
        }
240
241
        return parent::__call($method, $args);
242
    }
243
244
    /**
245
     * @return bool
246
     */
247
    protected function shouldAppendRevaluatedAttributesToArray()
248
    {
249
        return property_exists($this, 'appendRevaluatedAttributesToArray') ? $this->appendRevaluatedAttributesToArray : true;
250
    }
251
252
    /**
253
     * @return bool
254
     */
255
    protected function shouldReplaceRawAttributesToArray()
256
    {
257
        return property_exists($this, 'replaceRawAttributesToArray') ? $this->replaceRawAttributesToArray : true;
258
    }
259
260
    /**
261
     * Return revaluated value of attribute.
262
     *
263
     * @param string $attribute
264
     *
265
     * @return mixed
266
     */
267
    protected function getStorableValue($attribute)
268
    {
269
        if ($valuator = $this->getAttributeValuator($attribute)) {
270
            if (is_callable($valuator, 'toStorableValue')) {
271
                $value = forward_static_call([$valuator, 'toStorableValue'], $this->attributes[$attribute]);
272
            }
273
        }
274
275
        return $value;
276
    }
277
278
    /**
279
     * Get attribute valuator.
280
     *
281
     * @param string $attribute
282
     *
283
     * @return string
284
     */
285
    protected function getAttributeValuator($attribute)
286
    {
287
        return \Illuminate\Support\Arr::get($this->getRevaluableAttributes(), $attribute);
288
    }
289
}
290