1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Intraxia\Jaxion\Axolotl; |
4
|
|
|
|
5
|
|
|
use Intraxia\Jaxion\Contract\Axolotl\Dictionary as DictionaryContract; |
6
|
|
|
use Intraxia\Jaxion\Contract\Axolotl\Serializes; |
7
|
|
|
use InvalidArgumentException; |
8
|
|
|
|
9
|
|
|
/** |
10
|
|
|
* Class Dictionary |
11
|
|
|
* |
12
|
|
|
* @package Intraxia\Jaxion |
13
|
|
|
* @subpackage Axolotl |
14
|
|
|
*/ |
15
|
|
|
class Dictionary implements DictionaryContract { |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* Dictionary storage array. |
19
|
|
|
* |
20
|
|
|
* @var array |
21
|
|
|
*/ |
22
|
|
|
protected $storage = array(); |
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* Key Type service. |
26
|
|
|
* |
27
|
|
|
* @var Type |
28
|
|
|
*/ |
29
|
|
|
protected $key_type; |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* Value Type service. |
33
|
|
|
* |
34
|
|
|
* @var Type |
35
|
|
|
*/ |
36
|
|
|
protected $val_type; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* Where Dictionary is in loop. |
40
|
|
|
* |
41
|
|
|
* @var int |
42
|
|
|
*/ |
43
|
|
|
protected $position = 0; |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* Dictionary keys. |
47
|
|
|
* |
48
|
|
|
* @var array |
49
|
|
|
*/ |
50
|
|
|
protected $keys = array(); |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* Dictionary constructor. |
54
|
|
|
* |
55
|
|
|
* @param string $key_type |
56
|
|
|
* @param string $val_type |
57
|
|
|
* @param array $storage |
58
|
|
|
* |
59
|
|
|
* @throws InvalidArgumentException |
60
|
|
|
*/ |
61
|
105 |
|
public function __construct( $key_type, $val_type, array $storage = array() ) { |
62
|
105 |
|
$this->key_type = new Type( $key_type, true ); |
63
|
84 |
|
$this->val_type = new Type( $val_type ); |
64
|
|
|
|
65
|
84 |
|
foreach ( $storage as $key => $val ) { |
66
|
84 |
|
$this->key_type->validate_element( $key ); |
67
|
81 |
|
$this->val_type->validate_element( $val ); |
68
|
|
|
|
69
|
75 |
|
$this->storage[ $key ] = $val; |
70
|
84 |
|
} |
71
|
84 |
|
} |
72
|
|
|
|
73
|
|
|
/** |
74
|
|
|
* {@inheritdoc} |
75
|
|
|
* |
76
|
|
|
* @return string |
77
|
|
|
*/ |
78
|
45 |
|
public function get_key_type() { |
79
|
45 |
|
return $this->key_type->get_type(); |
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
/** |
83
|
|
|
* {@inheritdoc} |
84
|
|
|
* |
85
|
|
|
* @return string |
86
|
|
|
*/ |
87
|
45 |
|
public function get_value_type() { |
88
|
45 |
|
return $this->val_type->get_type(); |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
/** |
92
|
|
|
* {@inheritdoc} |
93
|
|
|
* |
94
|
|
|
* @param mixed $key Key to check. |
95
|
|
|
* |
96
|
|
|
* @return bool |
97
|
|
|
*/ |
98
|
36 |
|
public function exists( $key ) { |
99
|
36 |
|
return array_key_exists( $key, $this->storage ); |
100
|
|
|
} |
101
|
|
|
|
102
|
|
|
/** |
103
|
|
|
* {@inheritdoc} |
104
|
|
|
* |
105
|
|
|
* @param mixed $key Key to get. |
106
|
|
|
* |
107
|
|
|
* @return mixed|null |
108
|
|
|
*/ |
109
|
27 |
|
public function get( $key ) { |
110
|
27 |
|
return $this->exists( $key ) ? $this->storage[ $key ] : null; |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
/** |
114
|
|
|
* {@inheritdoc} |
115
|
|
|
* |
116
|
|
|
* @param mixed $key Key to remove. |
117
|
|
|
* |
118
|
|
|
* @return DictionaryContract |
119
|
|
|
*/ |
120
|
3 |
|
public function delete( $key ) { |
121
|
3 |
|
$storage = $this->storage; |
122
|
3 |
|
if ( $this->exists( $key ) ) { |
123
|
3 |
|
unset( $storage[ $key ] ); |
124
|
3 |
|
} |
125
|
|
|
|
126
|
3 |
|
return new static( $this->get_key_type(), $this->get_value_type(), $storage ); |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
/** |
130
|
|
|
* {@inheritdoc} |
131
|
|
|
* |
132
|
|
|
* @param mixed $value Value to validate. |
133
|
|
|
* |
134
|
|
|
* @return bool |
135
|
|
|
*/ |
136
|
9 |
|
public function value_exists( $value ) { |
137
|
9 |
|
return in_array( $value, $this->storage ); |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
/** |
141
|
|
|
* {@inheritdoc} |
142
|
|
|
*/ |
143
|
24 |
|
public function count() { |
144
|
24 |
|
return count( $this->storage ); |
145
|
|
|
} |
146
|
|
|
|
147
|
|
|
/** |
148
|
|
|
* {@inheritdoc} |
149
|
|
|
*/ |
150
|
3 |
|
public function clear() { |
151
|
3 |
|
return new static( $this->get_key_type(), $this->get_value_type() ); |
152
|
|
|
} |
153
|
|
|
|
154
|
|
|
/** |
155
|
|
|
* {@inheritdoc} |
156
|
|
|
* |
157
|
|
|
* @return array |
158
|
|
|
*/ |
159
|
9 |
|
public function to_array() { |
160
|
9 |
|
return $this->storage; |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
/** |
164
|
|
|
* {@inheritdoc} |
165
|
|
|
* |
166
|
|
|
* @param callable $condition Conditional callback. |
167
|
|
|
* |
168
|
|
|
* @return DictionaryContract |
169
|
|
|
*/ |
170
|
6 |
|
public function filter( $condition ) { |
171
|
6 |
|
$storage = array(); |
172
|
|
|
|
173
|
6 |
|
foreach ( $this->storage as $key => $value ) { |
174
|
6 |
|
if ( call_user_func( $condition, $value, $key ) ) { |
175
|
6 |
|
$storage[ $key ] = $value; |
176
|
6 |
|
} |
177
|
6 |
|
} |
178
|
|
|
|
179
|
6 |
|
return new static( $this->get_key_type(), $this->get_value_type(), $storage ); |
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
/** |
183
|
|
|
* {@inheritdoc} |
184
|
|
|
* |
185
|
|
|
* @param callable $condition Callback condition. |
186
|
|
|
* |
187
|
|
|
* @return DictionaryContract |
188
|
|
|
*/ |
189
|
3 |
|
public function reject( $condition ) { |
190
|
|
|
return $this->filter( function ( $v, $k ) use ( $condition ) { |
191
|
3 |
|
return ! call_user_func( $condition, $v, $k ); |
192
|
3 |
|
} ); |
193
|
|
|
} |
194
|
|
|
|
195
|
|
|
/** |
196
|
|
|
* {@inheritdoc} |
197
|
|
|
* |
198
|
|
|
* @param mixed $key Key to add. |
199
|
|
|
* @param mixed $value Value to add. |
200
|
|
|
* |
201
|
|
|
* @return DictionaryContract |
202
|
|
|
*/ |
203
|
21 |
|
public function add( $key, $value ) { |
204
|
21 |
|
$storage = $this->storage; |
205
|
21 |
|
$storage[ $key ] = $value; |
206
|
|
|
|
207
|
21 |
|
return new static( $this->get_key_type(), $this->get_value_type(), $storage ); |
208
|
|
|
} |
209
|
|
|
|
210
|
|
|
/** |
211
|
|
|
* {@inheritdoc} |
212
|
|
|
* |
213
|
|
|
* @param callable $callable Function to call. |
214
|
|
|
*/ |
215
|
3 |
|
public function each( $callable ) { |
216
|
3 |
|
foreach ( $this->storage as $key => $value ) { |
217
|
3 |
|
call_user_func( $callable, $value, $key ); |
218
|
3 |
|
} |
219
|
3 |
|
} |
220
|
|
|
|
221
|
|
|
/** |
222
|
|
|
* {@inheritdoc} |
223
|
|
|
* |
224
|
|
|
* @param mixed $key Key to fetch. |
225
|
|
|
* @param mixed $default Default to return if key is missing. |
226
|
|
|
* |
227
|
|
|
* @return mixed |
228
|
|
|
*/ |
229
|
3 |
|
public function get_or_else( $key, $default ) { |
230
|
3 |
|
return ( $this->exists( $key ) ) ? $this->get( $key ) : $default; |
231
|
|
|
} |
232
|
|
|
|
233
|
|
|
/** |
234
|
|
|
* {@inheritdoc} |
235
|
|
|
*/ |
236
|
3 |
|
public function keys() { |
237
|
3 |
|
return array_keys( $this->storage ); |
238
|
|
|
} |
239
|
|
|
|
240
|
|
|
/** |
241
|
|
|
* {@inheritdoc} |
242
|
|
|
*/ |
243
|
3 |
|
public function values() { |
244
|
3 |
|
return array_values( $this->storage ); |
245
|
|
|
} |
246
|
|
|
|
247
|
|
|
/** |
248
|
|
|
* {@inheritdoc} |
249
|
|
|
* |
250
|
|
|
* @param callable $callable Function to call. |
251
|
|
|
* |
252
|
|
|
* @return DictionaryContract |
253
|
|
|
*/ |
254
|
6 |
|
public function map( $callable ) { |
255
|
6 |
|
$items = array(); |
256
|
6 |
|
$val_type = null; |
257
|
|
|
|
258
|
6 |
|
foreach ( $this->storage as $key => $val ) { |
259
|
6 |
|
$v = call_user_func( $callable, $val, $key ); |
260
|
|
|
|
261
|
6 |
|
if ( ! isset( $val_type ) ) { |
262
|
6 |
|
$val_type = gettype( $v ); |
263
|
6 |
|
} |
264
|
|
|
|
265
|
6 |
|
$items[ $key ] = $v; |
266
|
6 |
|
} |
267
|
|
|
|
268
|
6 |
|
return new static( $this->get_key_type(), $val_type, $items ); |
269
|
|
|
} |
270
|
|
|
|
271
|
|
|
/** |
272
|
|
|
* {@inheritdoc} |
273
|
|
|
* |
274
|
|
|
* @param array|DictionaryContract $source Source to merge. |
275
|
|
|
* |
276
|
|
|
* @return DictionaryContract |
277
|
|
|
* |
278
|
|
|
* @throws InvalidArgumentException |
279
|
|
|
*/ |
280
|
12 |
View Code Duplication |
public function merge( $source ) { |
|
|
|
|
281
|
12 |
|
if ( $source instanceof self ) { |
282
|
6 |
|
$source = $source->to_array(); |
283
|
6 |
|
} |
284
|
|
|
|
285
|
12 |
|
if ( ! is_array( $source ) ) { |
286
|
3 |
|
throw new InvalidArgumentException( 'Combine must be a Dictionary or an array' ); |
287
|
|
|
} |
288
|
|
|
|
289
|
9 |
|
return new static( $this->get_key_type(), $this->get_value_type(), array_merge( $this->storage, $source ) ); |
290
|
|
|
} |
291
|
|
|
|
292
|
|
|
|
293
|
|
|
/** |
294
|
|
|
* {@inheritdoc} |
295
|
|
|
* |
296
|
|
|
* @param callable $callable |
297
|
|
|
* |
298
|
|
|
* @return bool |
299
|
|
|
*/ |
300
|
3 |
|
public function contains( $callable ) { |
301
|
3 |
|
foreach ( $this->storage as $key => $value ) { |
302
|
3 |
|
if ( call_user_func( $callable, $value, $key ) ) { |
303
|
3 |
|
return true; |
304
|
|
|
} |
305
|
3 |
|
} |
306
|
|
|
|
307
|
3 |
|
return false; |
308
|
|
|
} |
309
|
|
|
|
310
|
|
|
/** |
311
|
|
|
* {@inheritdoc} |
312
|
|
|
* |
313
|
|
|
* @param callable $callable |
314
|
|
|
* @param mixed $initial |
315
|
|
|
* |
316
|
|
|
* @return mixed |
317
|
|
|
*/ |
318
|
3 |
|
public function reduce( $callable, $initial ) { |
319
|
3 |
|
$carry = $initial; |
320
|
|
|
|
321
|
3 |
|
foreach ( $this->storage as $key => $value ) { |
322
|
3 |
|
$carry = $callable( $carry, $value, $key ); |
323
|
3 |
|
} |
324
|
|
|
|
325
|
3 |
|
return $carry; |
326
|
|
|
} |
327
|
|
|
|
328
|
|
|
/** |
329
|
|
|
* Return the current element. |
330
|
|
|
* |
331
|
|
|
* @return mixed |
332
|
|
|
*/ |
333
|
3 |
|
public function current() { |
334
|
3 |
|
$key = $this->keys[ $this->position ]; |
335
|
3 |
|
return $this->storage[ $key ]; |
336
|
|
|
} |
337
|
|
|
|
338
|
|
|
/** |
339
|
|
|
* Move forward to next element. |
340
|
|
|
*/ |
341
|
3 |
|
public function next() { |
342
|
3 |
|
$this->position ++; |
343
|
3 |
|
} |
344
|
|
|
|
345
|
|
|
/** |
346
|
|
|
* Return the key of the current element. |
347
|
|
|
* |
348
|
|
|
* @return mixed |
349
|
|
|
*/ |
350
|
3 |
|
public function key() { |
351
|
3 |
|
return $this->keys[ $this->position ]; |
352
|
|
|
} |
353
|
|
|
|
354
|
|
|
/** |
355
|
|
|
* Checks if current position is valid. |
356
|
|
|
* |
357
|
|
|
* @return bool |
358
|
|
|
*/ |
359
|
3 |
|
public function valid() { |
360
|
3 |
|
return isset( $this->keys[ $this->position ] ); |
361
|
|
|
} |
362
|
|
|
|
363
|
|
|
/** |
364
|
|
|
* Rewind the Iterator to the first element. |
365
|
|
|
*/ |
366
|
3 |
|
public function rewind() { |
367
|
3 |
|
$this->position = 0; |
368
|
3 |
|
$this->keys = array_keys( $this->storage ); |
369
|
3 |
|
} |
370
|
|
|
|
371
|
|
|
/** |
372
|
|
|
* {@inheritDoc} |
373
|
|
|
* |
374
|
|
|
* @return array |
375
|
|
|
*/ |
376
|
|
|
public function serialize() { |
377
|
|
|
return $this->map(function( $val ) { |
378
|
|
|
if ( $val instanceof Serializes ) { |
379
|
|
|
$val = $val->serialize(); |
380
|
|
|
} |
381
|
|
|
|
382
|
|
|
return $val; |
383
|
|
|
})->to_array(); |
384
|
|
|
} |
385
|
|
|
} |
386
|
|
|
|
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.