|
1
|
|
|
<?php namespace Chekote\NounStore; |
|
2
|
|
|
|
|
3
|
|
|
use InvalidArgumentException; |
|
4
|
|
|
use OutOfBoundsException; |
|
5
|
|
|
use RuntimeException; |
|
6
|
|
|
|
|
7
|
|
|
class Store |
|
8
|
|
|
{ |
|
9
|
|
|
/** @var array */ |
|
10
|
|
|
protected $nouns; |
|
11
|
|
|
|
|
12
|
|
|
/** @var Key */ |
|
13
|
|
|
protected $keyService; |
|
14
|
|
|
|
|
15
|
59 |
|
public function __construct(Key $keyService = null) |
|
16
|
|
|
{ |
|
17
|
59 |
|
$this->keyService = $keyService ?: Key::getInstance(); |
|
18
|
59 |
|
} |
|
19
|
|
|
|
|
20
|
|
|
/** |
|
21
|
|
|
* Asserts that a value has been stored for the specified key. |
|
22
|
|
|
* |
|
23
|
|
|
* @param string $key The key to check. @see self::get() for formatting options. |
|
24
|
|
|
* @param int $index [optional] The index of the key entry to check. If not specified, the |
|
25
|
|
|
* method will ensure that at least one item is stored for the key. |
|
26
|
|
|
* @throws OutOfBoundsException if a value has not been stored for the specified key. |
|
27
|
|
|
* @throws InvalidArgumentException if both an $index and $key are provided, but the $key contains an nth value |
|
28
|
|
|
* that does not match the index. |
|
29
|
|
|
* @return mixed The value. |
|
30
|
|
|
*/ |
|
31
|
23 |
View Code Duplication |
public function assertKeyExists($key, $index = null) |
|
|
|
|
|
|
32
|
|
|
{ |
|
33
|
23 |
|
list($key, $index) = $this->keyService->parse($key, $index); |
|
34
|
|
|
|
|
35
|
22 |
|
if (!$this->keyExists($key, $index)) { |
|
36
|
6 |
|
throw new OutOfBoundsException("Entry '{$this->buildKey($key, $index)}' was not found in the store."); |
|
37
|
|
|
} |
|
38
|
|
|
|
|
39
|
16 |
|
return $this->get($key, $index); |
|
40
|
|
|
} |
|
41
|
|
|
|
|
42
|
|
|
/** |
|
43
|
|
|
* Asserts that the key's value matches the specified value. |
|
44
|
|
|
* |
|
45
|
|
|
* @param string $key The key to check. @see self::get() for formatting options. |
|
46
|
|
|
* @param mixed $value The expected value. |
|
47
|
|
|
* @param int $index [optional] The index of the key entry to retrieve. If not specified, the |
|
48
|
|
|
* method will check the most recent value stored under the key. |
|
49
|
|
|
* @throws OutOfBoundsException If a value has not been stored for the specified key. |
|
50
|
|
|
* @throws InvalidArgumentException if both an $index and $key are provided, but the $key contains an nth value |
|
51
|
|
|
* that does not match the index. |
|
52
|
|
|
*/ |
|
53
|
10 |
|
public function assertKeyValueIs($key, $value, $index = null) |
|
54
|
|
|
{ |
|
55
|
10 |
|
list($key, $index) = $this->keyService->parse($key, $index); |
|
56
|
|
|
|
|
57
|
9 |
|
$this->assertKeyExists($key, $index); |
|
58
|
|
|
|
|
59
|
7 |
|
if ($this->get($key, $index) != $value) { |
|
60
|
2 |
|
throw new RuntimeException( |
|
61
|
2 |
|
"Entry '{$this->buildKey($key, $index)}' does not match '" . print_r($value, true) . "'" |
|
62
|
|
|
); |
|
63
|
|
|
} |
|
64
|
5 |
|
} |
|
65
|
|
|
|
|
66
|
|
|
/** |
|
67
|
|
|
* Asserts that the key's value contains the specified string. |
|
68
|
|
|
* |
|
69
|
|
|
* @param string $key The key to check. @see self::get() for formatting options. |
|
70
|
|
|
* @param string $value The value expected to be contained within the key's value. |
|
71
|
|
|
* @param int $index [optional] The index of the key entry to retrieve. If not specified, the |
|
72
|
|
|
* method will check the most recent value stored under the key. |
|
73
|
|
|
* @throws OutOfBoundsException If a value has not been stored for the specified key. |
|
74
|
|
|
* @throws InvalidArgumentException if both an $index and $key are provided, but the $key contains an nth value |
|
75
|
|
|
* that does not match the index. |
|
76
|
|
|
*/ |
|
77
|
10 |
View Code Duplication |
public function assertKeyValueContains($key, $value, $index = null) |
|
|
|
|
|
|
78
|
|
|
{ |
|
79
|
10 |
|
list($key, $index) = $this->keyService->parse($key, $index); |
|
80
|
|
|
|
|
81
|
9 |
|
$this->assertKeyExists($key, $index); |
|
82
|
|
|
|
|
83
|
7 |
|
if (!$this->keyValueContains($key, $value, $index)) { |
|
84
|
2 |
|
throw new RuntimeException( |
|
85
|
2 |
|
"Entry '{$this->buildKey($key, $index)}' does not contain '$value'" |
|
86
|
|
|
); |
|
87
|
|
|
} |
|
88
|
5 |
|
} |
|
89
|
|
|
|
|
90
|
|
|
/** |
|
91
|
|
|
* Removes all entries from the store. |
|
92
|
|
|
* |
|
93
|
|
|
* @return void |
|
94
|
|
|
*/ |
|
95
|
1 |
|
public function reset() |
|
96
|
|
|
{ |
|
97
|
1 |
|
$this->nouns = []; |
|
98
|
1 |
|
} |
|
99
|
|
|
|
|
100
|
|
|
/** |
|
101
|
|
|
* Retrieves a value for the specified key. |
|
102
|
|
|
* |
|
103
|
|
|
* Each key is actually a collection. If you do not specify which item in the collection you want, |
|
104
|
|
|
* the method will return the most recent entry. You can specify the entry you want by either |
|
105
|
|
|
* using the plain english 1st, 2nd, 3rd etc in the $key param, or by specifying 0, 1, 2 etc in |
|
106
|
|
|
* the $index param. For example: |
|
107
|
|
|
* |
|
108
|
|
|
* Retrieve the most recent entry "Thing" collection: |
|
109
|
|
|
* retrieve("Thing") |
|
110
|
|
|
* |
|
111
|
|
|
* Retrieve the 1st entry in the "Thing" collection: |
|
112
|
|
|
* retrieve("1st Thing") |
|
113
|
|
|
* retrieve("Thing", 0) |
|
114
|
|
|
* |
|
115
|
|
|
* Retrieve the 3rd entry in the "Thing" collection: |
|
116
|
|
|
* retrieve("3rd Thing") |
|
117
|
|
|
* retrieve("Thing", 2) |
|
118
|
|
|
* |
|
119
|
|
|
* Please note: The nth value in the string key is indexed from 1. In that "1st" is the first item stored. |
|
120
|
|
|
* The index parameter is indexed from 0. In that 0 is the first item stored. |
|
121
|
|
|
* |
|
122
|
|
|
* Please Note: If you specify both an $index param and an nth in the $key, they must both reference the same index. |
|
123
|
|
|
* If they do not, the method will throw an InvalidArgumentException. |
|
124
|
|
|
* |
|
125
|
|
|
* retrieve("1st Thing", 1); |
|
126
|
|
|
* |
|
127
|
|
|
* @param string $key The key to retrieve the value for. Can be prefixed with an nth descriptor. |
|
128
|
|
|
* @param int $index [optional] The index of the key entry to retrieve. If not specified, the |
|
129
|
|
|
* method will return the most recent value stored under the key. |
|
130
|
|
|
* @throws InvalidArgumentException if both an $index and $key are provided, but the $key contains an nth value |
|
131
|
|
|
* that does not match the index. |
|
132
|
|
|
* @return mixed The value, or null if no value exists for the specified key/index combination. |
|
133
|
|
|
*/ |
|
134
|
32 |
|
public function get($key, $index = null) |
|
135
|
|
|
{ |
|
136
|
32 |
|
list($key, $index) = $this->keyService->parse($key, $index); |
|
137
|
|
|
|
|
138
|
31 |
|
if (!$this->keyExists($key, $index)) { |
|
139
|
5 |
|
return; |
|
140
|
|
|
} |
|
141
|
|
|
|
|
142
|
26 |
|
return $index !== null ? $this->nouns[$key][$index] : end($this->nouns[$key]); |
|
143
|
|
|
} |
|
144
|
|
|
|
|
145
|
|
|
/** |
|
146
|
|
|
* Retrieves all values for the specified key. |
|
147
|
|
|
* |
|
148
|
|
|
* @param string $key The key to retrieve the values for. |
|
149
|
|
|
* @throws OutOfBoundsException if the specified $key does not exist in the store. |
|
150
|
|
|
* @return array The values. |
|
151
|
|
|
*/ |
|
152
|
2 |
|
public function getAll($key) |
|
153
|
|
|
{ |
|
154
|
2 |
|
if (!isset($this->nouns[$key])) { |
|
155
|
1 |
|
throw new OutOfBoundsException("'$key' does not exist in the store"); |
|
156
|
|
|
} |
|
157
|
|
|
|
|
158
|
1 |
|
return $this->nouns[$key]; |
|
159
|
|
|
} |
|
160
|
|
|
|
|
161
|
|
|
/** |
|
162
|
|
|
* Determines if a value has been stored for the specified key. |
|
163
|
|
|
* |
|
164
|
|
|
* @param string $key The key to check. |
|
165
|
|
|
* @param int $index [optional] The index of the key entry to check. If not specified, the |
|
166
|
|
|
* method will ensure that at least one item is stored for the key. |
|
167
|
|
|
* @throws InvalidArgumentException if both an $index and $key are provided, but the $key contains an nth value |
|
168
|
|
|
* that does not match the index. |
|
169
|
|
|
* @return bool True if the a value has been stored, false if not. |
|
170
|
|
|
*/ |
|
171
|
42 |
|
public function keyExists($key, $index = null) |
|
172
|
|
|
{ |
|
173
|
42 |
|
list($key, $index) = $this->keyService->parse($key, $index); |
|
174
|
|
|
|
|
175
|
41 |
|
return $index !== null ? isset($this->nouns[$key][$index]) : isset($this->nouns[$key]); |
|
176
|
|
|
} |
|
177
|
|
|
|
|
178
|
|
|
/** |
|
179
|
|
|
* Asserts that the key's value contains the specified string. |
|
180
|
|
|
* |
|
181
|
|
|
* @param string $key The key to check. @see self::get() for formatting options. |
|
182
|
|
|
* @param string $value The value expected to be contained within the key's value. |
|
183
|
|
|
* @param int $index [optional] The index of the key entry to retrieve. If not specified, the |
|
184
|
|
|
* method will check the most recent value stored under the key. |
|
185
|
|
|
* @throws InvalidArgumentException if both an $index and $key are provided, but the $key contains an nth value |
|
186
|
|
|
* that does not match the index. |
|
187
|
|
|
* @return bool True if the key's value contains the specified string, false if not. |
|
188
|
|
|
*/ |
|
189
|
17 |
|
public function keyValueContains($key, $value, $index = null) |
|
190
|
|
|
{ |
|
191
|
17 |
|
list($key, $index) = $this->keyService->parse($key, $index); |
|
192
|
|
|
|
|
193
|
16 |
|
$actual = $this->get($key, $index); |
|
194
|
|
|
|
|
195
|
16 |
|
return is_string($actual) && strpos($actual, $value) !== false; |
|
196
|
|
|
} |
|
197
|
|
|
|
|
198
|
|
|
/** |
|
199
|
|
|
* Stores a value for the specified key. |
|
200
|
|
|
* |
|
201
|
|
|
* @param string $key The key to store the value under. |
|
202
|
|
|
* @param mixed $value The value to store. |
|
203
|
|
|
*/ |
|
204
|
59 |
|
public function set($key, $value) |
|
205
|
|
|
{ |
|
206
|
59 |
|
$this->nouns[$key][] = $value; |
|
207
|
59 |
|
} |
|
208
|
|
|
|
|
209
|
|
|
/** |
|
210
|
|
|
* Builds a key from it's separate key and index values. |
|
211
|
|
|
* |
|
212
|
|
|
* @example buildKey("Item", null): "Item" |
|
213
|
|
|
* @example buildKey("Item", 0): "1st Item" |
|
214
|
|
|
* @example buildKey("Item", 1): "2nd Item" |
|
215
|
|
|
* @example buildKey("Item", 2): "3rd Item" |
|
216
|
|
|
* |
|
217
|
|
|
* @param string $key The key to check. |
|
218
|
|
|
* @param int $index The index (zero indexed) value for the key. If not specified, the method |
|
219
|
|
|
* will not add an index notation to the key. |
|
220
|
|
|
* @throws InvalidArgumentException if $key is not a string. |
|
221
|
|
|
* @throws InvalidArgumentException if $index is not an int. |
|
222
|
|
|
* @return string the key with the index, or just the key if index is null. |
|
223
|
|
|
*/ |
|
224
|
17 |
|
protected function buildKey($key, $index) |
|
225
|
|
|
{ |
|
226
|
17 |
|
if ($index === null) { |
|
227
|
3 |
|
return $key; |
|
228
|
|
|
} |
|
229
|
|
|
|
|
230
|
14 |
|
$nth = $index + 1; |
|
231
|
|
|
|
|
232
|
14 |
|
return $nth . $this->keyService->getOrdinal($nth) . ' ' . $key; |
|
233
|
|
|
} |
|
234
|
|
|
} |
|
235
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.