1: <?php
2: namespace Azalea\Selenium\Toolkit;
3:
4: /**
5: * Wraps a multi-dimensional associated array object (nested hash map) and
6: * provides dot notation access to it along with a few other nicities, like
7: * default values and assertHas.
8: *
9: * Examples:
10: *
11: * $items = array(
12: * "foo" => array(
13: * "bar" => "baz"
14: * ));
15: *
16: * $arr = new NestedHashMap($items);
17: * $arr->get("foo.bar"); // "baz"
18: * $arr->has("foo.bar"); // true
19: *
20: * @author jtracy
21: */
22: class NestedHashMap
23: {
24: /** @var array $items */
25: protected $items = array();
26:
27: /**
28: * Create a new NestedHashMap object wrapping $items.
29: *
30: * @param array $items
31: */
32: public function __construct($items = array())
33: {
34: $this->items = $items;
35: }
36:
37: /**
38: * Returns the entire multi-array.
39: *
40: * @return array
41: */
42: public function getAll()
43: {
44: return $this->items;
45: }
46:
47: /**
48: * Get a key's value.
49: *
50: * @param string $key
51: * @param mixed $default
52: * @throws \InvalidArgumentException
53: * @return mixed
54: */
55: public function get($key, $default = null)
56: {
57: $items = $this->items;
58: $pieces = explode(".", $key);
59: $count = count($pieces);
60:
61: foreach($pieces as $i => $piece) {
62: $value = $this->lookup($items, $piece);
63: if ($value === null) {
64: // value is empty or key doesn't exist, so return the default
65: return $default;
66: }
67: if (is_array($value)) {
68: $items = $value;
69: continue;
70: }
71: // value is not an array, so we cannot go any further
72: if ($i === ($count - 1)) {
73: // we have reached the end, so return the value
74: return $value;
75: }
76: // the provided key is invalid
77: throw new \InvalidArgumentException("Invalid key: ".$key);
78: }
79:
80: // the final value is an array stored in $items
81: return $items;
82: }
83:
84: /**
85: * Check if an item exists in the multi-array.
86: *
87: * @param string $key
88: * @return bool
89: */
90: public function has($key)
91: {
92: $items = $this->items;
93: $pieces = explode(".", $key);
94: $count = count($pieces);
95:
96: foreach($pieces as $i => $piece) {
97: $value = $this->lookup($items, $piece);
98: if ($value === null) {
99: // value is empty or key doesn't exist
100: return false;
101: }
102: if (is_array($value)) {
103: $items = $value;
104: continue;
105: }
106: // value is not an array, so we cannot go any further
107: if ($i === ($count - 1)) {
108: // we have reached the end
109: return true;
110: }
111: // the provided key is invalid
112: return false;
113: }
114:
115: // the final value is an array stored in $items
116: return true;
117: }
118:
119: /**
120: * Set a key's value.
121: *
122: * @param string $key
123: * @param mixed $value
124: */
125: public function set($key, $value)
126: {
127: $items = &$this->items;
128: $pieces = explode(".", $key);
129: $count = count($pieces);
130:
131: foreach($pieces as $i => $piece) {
132: if (!is_array($items)) {
133: // can't do lookup in a non-array
134: throw new \InvalidArgumentException("Invalid key: ".$key);
135: }
136: if ($i === ($count - 1)) {
137: // we have reached the end
138: $items[$piece] = $value;
139: break;
140: }
141: if (isset($items[$piece])) {
142: $items = &$items[$piece];
143: continue;
144: }
145: // create an empty container
146: $items[$piece] = array();
147: $items = &$items[$piece];
148: }
149: }
150:
151: /**
152: * Throws an exception if one or more of the given keys
153: * do not exist in the multi-array.
154: *
155: * @param string $key One or more keys
156: * @throws \RuntimeException
157: * @return bool
158: */
159: public function assertHas()
160: {
161: $args = func_get_args();
162: foreach($args as $key) {
163: if (!$this->has($key)) {
164: throw new \RuntimeException("Expected array to contain: ".$key);
165: }
166: }
167: return true;
168: }
169:
170: /**
171: * Looks up the key ($piece) in the given array ($items)
172: *
173: * @param array $items
174: * @param string $piece
175: * @throws \InvalidArgumentException
176: * @return mixed
177: */
178: protected function lookup($items, $piece)
179: {
180: if (!is_array($items)) {
181: throw new \InvalidArgumentException("Items must be an array");
182: }
183: if (!isset($items[$piece])) {
184: return null;
185: }
186:
187: return $items[$piece];
188: }
189: }
190:
191: ?>