ObjectPath::getPathParts()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 1
dl 0
loc 9
rs 9.6666
c 0
b 0
f 0
1
<?php
2
3
namespace Peridot\Leo\ObjectPath;
4
5
/**
6
 * ObjectPath is a utility for parsing object and array strings into
7
 * ObjectPathValues.
8
 *
9
 * @package Peridot\Leo\Utility
10
 */
11
class ObjectPath
12
{
13
    /**
14
     * The subject to match path expressions against.
15
     *
16
     * @var array|object
17
     */
18
    protected $subject;
19
20
    /**
21
     * A pattern for matching array keys.
22
     *
23
     * @var string
24
     */
25
    private static $arrayKey = '/\[([^\]]+)\]/';
26
27
    /**
28
     * @param array|object $subject
29
     */
30
    public function __construct($subject)
31
    {
32
        $this->subject = $subject;
33
    }
34
35
    /**
36
     * Returns an ObjectPathValue if the property described by $path
37
     * can be located in the subject.
38
     *
39
     * A path expression uses object and array syntax.
40
     *
41
     * @code
42
     *
43
     * $person = new stdClass();
44
     * $person->name = new stdClass();
45
     * $person->name->first = 'brian';
46
     * $person->name->last = 'scaturro';
47
     * $person->hobbies = ['programming', 'reading', 'board games'];
48
     *
49
     * $path = new ObjectPath($person);
50
     * $first = $path->get('name->first');
51
     * $reading = $path->get('hobbies[0]');
52
     *
53
     * @endcode
54
     *
55
     * @param  string          $path
56
     * @return ObjectPathValue
57
     */
58
    public function get($path)
59
    {
60
        $parts = $this->getPathParts($path);
61
        $properties = $this->getPropertyCollection($this->subject);
62
        $pathValue = null;
63
        while (!empty($properties) && !empty($parts)) {
64
            $key = array_shift($parts);
65
            $key = $this->normalizeKey($key);
66
            $pathValue = $this->getPathValue($key, $properties);
67
68
            if (!array_key_exists($key, $properties)) {
69
                break;
70
            }
71
72
            $properties = $this->getPropertyCollection($properties[$key]);
73
        }
74
75
        return $pathValue;
76
    }
77
78
    /**
79
     * Breaks a path expression into an array used
80
     * for navigating a path.
81
     *
82
     * @param $path
83
     * @return array
84
     */
85
    public function getPathParts($path)
86
    {
87
        $path = preg_replace('/\[/', '->[', $path);
88
        if (preg_match('/^->/', $path)) {
89
            $path = substr($path, 2);
90
        }
91
92
        return explode('->', $path);
93
    }
94
95
    /**
96
     * Returns a property as an array.
97
     *
98
     * @param $subject
99
     * @return array
100
     */
101
    protected function getPropertyCollection($subject)
102
    {
103
        if (is_object($subject)) {
104
            return get_object_vars($subject);
105
        }
106
107
        return $subject;
108
    }
109
110
    /**
111
     * Return a key that can be used on the current subject.
112
     *
113
     * @param $key
114
     * @param $matches
115
     * @return mixed
116
     */
117
    protected function normalizeKey($key)
118
    {
119
        if (preg_match(self::$arrayKey, $key, $matches)) {
120
            $key = $matches[1];
121
122
            return $key;
123
        }
124
125
        return $key;
126
    }
127
128
    /**
129
     * Given a key and a collection of properties, this method
130
     * will return an ObjectPathValue if possible.
131
     *
132
     * @param $key
133
     * @param $properties
134
     * @return null|ObjectPathValue
135
     */
136
    protected function getPathValue($key, $properties)
137
    {
138
        if (!array_key_exists($key, $properties)) {
139
            return null;
140
        }
141
142
        return new ObjectPathValue($key, $properties[$key]);
143
    }
144
}
145