Completed
Push — master ( cdc390...f7e8b3 )
by Max
01:06
created

GetterHelper::getIterator()   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
/*
4
 *  @copyright (c) 2019 Mendel <[email protected]>
5
 *  @license see license.txt
6
 */
7
8
namespace drycart\data;
9
10
/**
11
 * Wrapper for pretty access to field
12
 * Used for deep access to some data at some unknown data
13
 *
14
 * fieldName for example forum.moderators.first().name work correct for any of this sence:
15
 * $data->forum->moderators->first()->name
16
 * $data['forum']['moderators']->first()['name']
17
 * $data['forum']->moderators->first()['name']
18
 * etc...
19
 *
20
 * Object field is priority option, second is array, after this we try method,
21
 * so if exist something like this, it will be used
22
 * $data['forum']->moderators['first()']['name']
23
 *
24
 * methods parameters not supports at any format
25
 */
26
class GetterHelper
27
{
28
    /**
29
     * Get some data by pretty name
30
     * 
31
     * @param array|object $data data for pretty access
32
     * @param string $name name for access
33
     * @param bool $safe if true - Exception for not exist fields
34
     * @return mixed
35
     * @throws \UnexpectedValueException
36
     */
37
    public static function get($data, string $name, bool $safe = true)
38
    {
39
        $fields = explode('.', $name);
40
        foreach ($fields as $key) {
41
            $data = static::subGet($data, $key, $safe);
42
        }
43
        return $data;
44
    }
45
46
    /**
47
     * Get iterator for data
48
     * 
49
     * @param mixed $data
50
     * @return \Traversable
51
     */
52
    public static function getIterator($data): \Traversable
53
    {
54
        if(is_a($data, \Traversable::class)) {
55
            return $data;
56
        } elseif(is_array($data)) {
57
            return new \ArrayIterator($data);
58
        } else {
59
            return new \ArrayIterator((array) $data);
60
        }
61
    }
62
63
    /**
64
     * Get keys list for data
65
     * 
66
     * @param mixed $data
67
     * @return array
68
     */
69
    public static function getKeys($data) : array
70
    {
71
        if(is_object($data) and is_a($data, ModelInterface::class)) {
72
            return $data->keys();
73
        } elseif(is_array($data)) {
74
            return array_keys($data);
75
        } elseif(is_a($data, \ArrayObject::class)) {
76
            $arr = $data->getArrayCopy();
77
            return array_keys($arr);
78
        } elseif(is_a($data, \Traversable::class)) {
79
            $arr = iterator_to_array($data);
80
            return array_keys($arr);
81
        } else {
82
            $arr = (array) $data;
83
            return array_keys($arr);
84
        }
85
    }
86
87
    /**
88
     * One level get
89
     * 
90
     * @param type $data
91
     * @param string $key
92
     * @param bool $safe
93
     * @return mixed
94
     * @throws \UnexpectedValueException
95
     */
96
    protected static function subGet($data, string $key, bool $safe = true)
97
    {
98
        if (static::isArrayable($data) and isset($data[$key])) {
99
            return $data[$key];
100
        }
101
        
102
        if (is_object($data) AND isset($data->{$key})) {
103
            return $data->{$key};
104
        }
105
        
106
        // Methods magic...
107
        $method = static::tryGetMethodName($key);
108
        if (!is_null($method) and method_exists($data, $method)) {
109
            return call_user_func_array([$data, $method], []);
110
        }
111
        
112
        if ($safe) {
113
            throw new \UnexpectedValueException("Bad field name $key");
114
        }
115
        return null;
116
    }
117
    
118
    /**
119
     * Check if data is array or ArrayAccess
120
     * @param type $data
121
     * @return bool
122
     */
123
    protected static function isArrayable($data) : bool
124
    {
125
        return is_array($data) OR is_a($data, \ArrayAccess::class);
126
    }
127
    
128
    /**
129
     * Check if key is methods name (i.e. finished to "()")
130
     * and return methods name
131
     *  
132
     * @param string $key
133
     * @return string|null
134
     */
135
    protected static function tryGetMethodName(string $key) : ?string
136
    {
137
        if(substr($key, -2) == '()') {
138
            return substr($key, 0, -2);
139
        }
140
        return null;
141
    }
142
}
143