Completed
Push — master ( 384847...650a76 )
by Ben
01:08
created

HasMagicAttributes::isMultidimensionalArray()   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
        $value = $this->retrieveAttributeValue($key);
14
15
        if (is_null($value)) {
16
            return $default;
17
        }
18
19
        return is_callable($closure)
20
            ? call_user_func_array($closure, [$value, $this])
21
            : $value;
22
    }
23
24
    private function retrieveAttributeValue($key)
25
    {
26
        $key = $this->camelCaseToDotSyntax($key);
27
28
        $keys = explode('.', $key);
29
        $parent = $this;
30
        $value = null;
31
32
        foreach ($keys as $k) {
33
            $value = $this->retrieveValue($k, $parent);
34
35
            if (is_null($value)) {
36
                return null;
37
            }
38
39
            $parent = $value;
40
        }
41
42
        return $value;
43
    }
44
45
    private function retrieveValue($key, $parent)
46
    {
47
        if(null !== ($value = $this->retrieveProperty($key, $parent))) return $value;
48
49
        // At this point if the value is not a property, Check if array that consists of arrays / objects and try to pluck the key
50
        if( ! $this->isMultidimensionalArray($parent)) return null;
51
52
        return $this->pluck($key, $parent);
53
    }
54
55
    private function isMultidimensionalArray($array): bool
56
    {
57
        if( !is_array($array)) return false;
58
59
        if(count($array) != count($array, COUNT_RECURSIVE )) return true;
60
61
        // If count is the same, it still could be a list of objects
62
        // which we will treat the same as a multidim. array
63
        return is_object(reset($array));
64
    }
65
66
    private function pluck($key, $list)
67
    {
68
        if(!is_array($list)) return null;
69
70
        $values = [];
71
72
        foreach($list as $item) {
73
            if($value = $this->retrieveProperty($key, $item)) {
74
                $values[] = $value;
75
            }
76
        }
77
78
        return count($values) > 0 ? $values : null;
79
    }
80
81
    private function retrieveProperty($key, $parent)
82
    {
83
        if (is_object($parent) && isset($parent->$key)) {
84
            return $parent->$key;
85
        }
86
87
        if (is_array($parent) && isset($parent[$key])) {
88
            return $parent[$key];
89
        }
90
91
        return null;
92
    }
93
94
    /**
95
     * @param $key
96
     * @return string
97
     */
98
    private function camelCaseToDotSyntax($key): string
99
    {
100
        return strtolower(preg_replace('/(?<!^)[A-Z]/', '.$0', $key));
101
    }
102
}
103