Passed
Push — ft/dynamic-attributes ( 48373f )
by Ben
11:13
created

HasDynamicAttributes::fill()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 3
c 1
b 0
f 0
dl 0
loc 12
rs 10
cc 2
nc 2
nop 1
1
<?php
2
declare(strict_types=1);
3
4
namespace Thinktomorrow\Chief\DynamicAttributes;
5
6
trait HasDynamicAttributes
7
{
8
    /**
9
     * Method used by the save logic on eloquent. This way we can inject an json version of the
10
     *dynamic attributes for saving into the database.
11
     * @return mixed
12
     */
13
    public function getAttributes()
14
    {
15
        $attributes = $this->attributes;
16
17
        $attributes[$this->getDynamicAttributesKey()] = json_encode($attributes[$this->getDynamicAttributesKey()]->all());
18
19
        return $attributes;
20
    }
21
22
    public function setRawAttributes(array $attributes, $sync = false)
23
    {
24
        if (isset($attributes[$this->getDynamicAttributesKey()])) {
25
            /*
26
             * fill the dynamic attributes in a custom key, so this will not conflict with the original values.
27
             * A custom key other than the column key is required because the trait is initialized before
28
             * the original attributes of the model are filled in.
29
            */
30
            $attributes[$this->getDynamicAttributesKey()] = $this->convertToDynamicAttributes($attributes[$this->getDynamicAttributesKey()]);
31
        }
32
33
        return parent::setRawAttributes($attributes, $sync);
34
    }
35
36
    public function fill(array $attributes)
37
    {
38
        if (isset($attributes[$this->getDynamicAttributesKey()])) {
39
            /*
40
             * fill the dynamic attributes in a custom key, so this will not conflict with the original values.
41
             * A custom key other than the column key is required because the trait is initialized before
42
             * the original attributes of the model are filled in.
43
            */
44
            $attributes[$this->getDynamicAttributesKey()] = $this->convertToDynamicAttributes($attributes[$this->getDynamicAttributesKey()]);
45
        }
46
47
        return parent::fill($attributes);
48
    }
49
50
    private function convertToDynamicAttributes($value): DynamicAttributes
51
    {
52
        $value = is_array($value) ? $value : json_decode($value, true);
53
54
        /*
55
         * fill the dynamic attributes in a custom key, so this will not conflict with the original values.
56
         * A custom key other than the column key is required because the trait is initialized before
57
         * the original attributes of the model are filled in.
58
        */
59
        return new DynamicAttributes((array) $value);
60
    }
61
62
    public function getAttribute($key)
63
    {
64
        // Fetching a native models' attribute has precedence over a dynamic attribute.
65
        if (array_key_exists($key, $this->attributes)){
66
            return parent::getAttribute($key);
67
        }
68
69
        $locale = app()->getLocale();
0 ignored issues
show
introduced by
The method getLocale() does not exist on Illuminate\Container\Container. Are you sure you never get this type here, but always one of the subclasses? ( Ignorable by Annotation )

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

69
        $locale = app()->/** @scrutinizer ignore-call */ getLocale();
Loading history...
70
71
        // If the dynamic attributes contain a localized value, this has preference over any non-localized.
72
        foreach(["{$locale}.$key", $key] as $k){
73
            if($this->dynamicAttributesInstance()->has($k)){
74
                return $this->dynamic($k);
75
            }
76
        }
77
78
        return parent::getAttribute($key);
79
    }
80
81
    public function setAttribute($key, $value)
82
    {
83
        if ($this->shouldBeSetAsDynamicAttribute($key)){
84
            return $this->dynamicAttributesInstance()->set($key, $value);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->dynamicAttributes...ce()->set($key, $value) targeting Thinktomorrow\Chief\Dyna...ynamicAttributes::set() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
85
        }
86
87
        return parent::setAttribute($key, $value);
88
    }
89
90
    protected function shouldBeSetAsDynamicAttribute($key): bool
91
    {
92
        if(array_key_exists($key, $this->attributes) || !array_key_exists($this->getDynamicAttributesKey(), $this->attributes)) {
93
            return false;
94
        }
95
96
        return in_array($key, $this->getDynamicAttributes());
97
    }
98
99
    public function dynamic(string $key, string $index = null)
100
    {
101
        return $this->dynamicAttributesInstance()->get($index ? "$index.$key" : $key);
102
    }
103
104
    protected function dynamicAttributesInstance(): DynamicAttributes
105
    {
106
        return $this->attributes[$this->getDynamicAttributesKey()];
107
    }
108
109
    protected function getDynamicAttributesKey()
110
    {
111
        return defined('static::DYNAMIC_ATTRIBUTES_KEY') ? static::DYNAMIC_ATTRIBUTES_KEY : 'values';
0 ignored issues
show
Bug introduced by
The constant Thinktomorrow\Chief\Dyna...:DYNAMIC_ATTRIBUTES_KEY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
112
    }
113
114
    protected function getDynamicAttributes(): array
115
    {
116
        return property_exists($this, 'dynamicAttributes') ? $this->dynamicAttributes : [];
117
    }
118
}
119