Completed
Push — master ( 650a76...acb468 )
by Ben
01:07
created

HasMagicAttributes::isMultiDimensional()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.9332
c 0
b 0
f 0
cc 3
nc 3
nop 1
1
<?php
2
3
namespace Thinktomorrow\MagicAttributes;
4
5
trait HasMagicAttributes
6
{
7
    public function attr($key, $default = null, $closure = null)
8
    {
9
        if (method_exists($this, $key)) {
10
            return $this->{$key}();
11
        }
12
13
        /**
14
         * We first try to fetch the key as is, and then we try to fetch
15
         * with converting camelcase to dot syntax as well.
16
         */
17
        $value = null;
18
19
        foreach([$key, $this->camelCaseToDotSyntax($key)] as $k) {
20
            if(null !== ($value = $this->retrieveAttributeValue($k))) {
21
                break;
22
            }
23
        }
24
25
        if (is_null($value)) {
26
            return $default;
27
        }
28
29
        return is_callable($closure)
30
            ? call_user_func_array($closure, [$value, $this])
31
            : $value;
32
    }
33
34
    private function retrieveAttributeValue($key)
35
    {
36
        $keys = explode('.', $key);
37
        $parent = $this;
38
        $value = null;
39
40
        foreach ($keys as $k) {
41
            $value = $this->retrieveValue($k, $parent);
42
43
            if (is_null($value)) {
44
                return null;
45
            }
46
47
            $parent = $value;
48
        }
49
50
        return $value;
51
    }
52
53
    private function retrieveValue($key, $parent)
54
    {
55
        if(null !== ($value = $this->retrieveProperty($key, $parent))) return $value;
56
57
        /**
58
         * At this point, we know that the key isn't present as property.
59
         * We now check if its an array consisting itself of nested items
60
         * so we can try to pluck the values by key from those arrays / objects.
61
         */
62
        if( ! $this->isMultiDimensional($parent)) return null;
63
64
        return $this->pluck($key, $parent);
65
    }
66
67
    private function isMultiDimensional($array): bool
68
    {
69
        if( !is_array($array)) return false;
70
71
        if(count($array) != count($array, COUNT_RECURSIVE )) return true;
72
73
        // If count is the same, it still could be a list of objects
74
        // which we will treat the same as a multidim. array
75
        return is_object(reset($array));
76
    }
77
78
    private function pluck($key, $list)
79
    {
80
        if(!is_array($list)) return null;
81
82
        $values = [];
83
84
        foreach($list as $item) {
85
            if($value = $this->retrieveProperty($key, $item)) {
86
                $values[] = $value;
87
            }
88
        }
89
90
        return count($values) > 0 ? $values : null;
91
    }
92
93
    private function retrieveProperty($key, $parent)
94
    {
95
        if (is_object($parent) && isset($parent->$key)) {
96
            return $parent->$key;
97
        }
98
99
        if (is_array($parent) && isset($parent[$key])) {
100
            return $parent[$key];
101
        }
102
103
        return null;
104
    }
105
106
    /**
107
     * @param $key
108
     * @return string
109
     */
110
    private function camelCaseToDotSyntax($key): string
111
    {
112
        return strtolower(preg_replace('/(?<!^)[A-Z]/', '.$0', $key));
113
    }
114
}
115