UnderscoreBase::pairs()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 2
eloc 4
c 1
b 0
f 1
nc 2
nop 0
dl 0
loc 9
rs 10
1
<?php
2
3
/*
4
 * This file is part of the PHP-UNDERSCORE package.
5
 *
6
 * (c) Jitendra Adhikari <[email protected]>
7
 *     <https://github.com/adhocore>
8
 *
9
 * Licensed under MIT license.
10
 */
11
12
namespace Ahc\Underscore;
13
14
class UnderscoreBase implements \ArrayAccess, \Countable, \IteratorAggregate, \JsonSerializable
15
{
16
    use Arrayizes;
17
    use UnderscoreAliases;
18
19
    const VERSION = '0.0.2';
20
21
    /** @var array The array manipulated by this Underscore instance */
22
    protected $data;
23
24
    /** @var array Custom userland functionality through named callbacks */
25
    protected static $mixins = [];
26
27
    /**
28
     * Constructor. Only allow `Ahc\Underscore\Underscore` to be instantiated in userland.
29
     *
30
     * @param array|mixed $data Array or array like or array convertible.
31
     */
32
    protected function __construct($data = [])
33
    {
34
        $this->data = \is_array($data) ? $data : $this->asArray($data);
35
    }
36
37
    /**
38
     * Get the underlying array data.
39
     *
40
     * @param string|int|null $index
41
     *
42
     * @return mixed
43
     */
44
    public function get($index = null)
45
    {
46
        if (null === $index) {
47
            return $this->data;
48
        }
49
50
        return $this->data[$index];
51
    }
52
53
    /**
54
     * Get data.
55
     *
56
     * @return array
57
     */
58
    public function getData()
59
    {
60
        return $this->data;
61
    }
62
63
    /**
64
     * Flatten a multi dimension array to 1 dimension.
65
     *
66
     * @param array $array
67
     *
68
     * @return array
69
     */
70
    public function flat($array, &$flat = [])
71
    {
72
        foreach ($array as $value) {
73
            if ($value instanceof static) {
74
                $value = $value->get();
75
            }
76
77
            if (\is_array($value)) {
78
                $this->flat($value, $flat);
79
            } else {
80
                $flat[] = $value;
81
            }
82
        }
83
84
        return $flat;
85
    }
86
87
    /**
88
     * Negate a given truth test callable.
89
     *
90
     * @param callable $fn
91
     *
92
     * @return callable
93
     */
94
    protected function negate(callable $fn)
95
    {
96
        return function () use ($fn) {
97
            return !\call_user_func_array($fn, \func_get_args());
98
        };
99
    }
100
101
    /**
102
     * Get a value generator callable.
103
     *
104
     * @param callable|string|null $fn
105
     *
106
     * @return callable
107
     */
108
    protected function valueFn($fn)
109
    {
110
        if (\is_callable($fn)) {
111
            return $fn;
112
        }
113
114
        return function ($value) use ($fn) {
115
            if (null === $fn) {
116
                return $value;
117
            }
118
119
            $value = \array_column([$value], $fn);
0 ignored issues
show
Bug introduced by
It seems like $fn can also be of type callable; however, parameter $column_key of array_column() does only seem to accept integer|null|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

119
            $value = \array_column([$value], /** @scrutinizer ignore-type */ $fn);
Loading history...
120
121
            return  $value ? $value[0] : null;
122
        };
123
    }
124
125
    /**
126
     * Checks if offset/index exists.
127
     *
128
     * @param string|int $index
129
     *
130
     * @return bool
131
     */
132
    public function offsetExists($index)
133
    {
134
        return \array_key_exists($index, $this->data);
135
    }
136
137
    /**
138
     * Gets the value at given offset/index.
139
     *
140
     * @return mixed
141
     */
142
    public function offsetGet($index)
143
    {
144
        return $this->data[$index];
145
    }
146
147
    /**
148
     * Sets a new value at the given offset/index.
149
     *
150
     * @param string|int $index
151
     * @param mixed      $value
152
     *
153
     * @return void
154
     */
155
    public function offsetSet($index, $value)
156
    {
157
        $this->data[$index] = $value;
158
    }
159
160
    /**
161
     * Unsets/removes the value at given index.
162
     *
163
     * @param string|int $index
164
     */
165
    public function offsetUnset($index)
166
    {
167
        unset($this->data[$index]);
168
    }
169
170
    /**
171
     * Gets the count of items.
172
     *
173
     * @return int
174
     */
175
    public function count()
176
    {
177
        return \count($this->data);
178
    }
179
180
    /**
181
     * Gets the iterator for looping.
182
     *
183
     * @return \ArrayIterator
184
     */
185
    public function getIterator()
186
    {
187
        return new \ArrayIterator($this->data);
188
    }
189
190
    /**
191
     * Gets the data for json serialization.
192
     *
193
     * @return array
194
     */
195
    public function jsonSerialize()
196
    {
197
        return $this->toArray();
198
    }
199
200
    /**
201
     * Stringify the underscore instance.
202
     *
203
     * @return string Json encoded data.
204
     */
205
    public function __toString()
206
    {
207
        return \json_encode($this->toArray());
208
    }
209
210
    /**
211
     * The current time in millisec.
212
     *
213
     * @return float
214
     */
215
    public function now()
216
    {
217
        return \microtime(1) * 1000;
218
    }
219
220
    /**
221
     * Get all the keys.
222
     *
223
     * @return self
224
     */
225
    public function keys()
226
    {
227
        return new static(\array_keys($this->data));
228
    }
229
230
    /**
231
     * Get all the keys.
232
     *
233
     * @return self
234
     */
235
    public function values()
236
    {
237
        return new static(\array_values($this->data));
238
    }
239
240
    /**
241
     * Pair all items to use an array of index and value.
242
     *
243
     * @return self
244
     */
245
    public function pairs()
246
    {
247
        $pairs = [];
248
249
        foreach ($this->data as $index => $value) {
250
            $pairs[$index] = [$index, $value];
251
        }
252
253
        return new static($pairs);
254
    }
255
256
    /**
257
     * Swap index and value of all the items. The values should be stringifiable.
258
     *
259
     * @return self
260
     */
261
    public function invert()
262
    {
263
        return new static(\array_flip($this->data));
264
    }
265
266
    /**
267
     * Pick only the items having one of the whitelisted indexes.
268
     *
269
     * @param array|...string|...int $index Either whitelisted indexes as array or as variads.
270
     *
271
     * @return self
272
     */
273
    public function pick($index)
274
    {
275
        $indices = \array_flip(\is_array($index) ? $index : \func_get_args());
276
277
        return new static(\array_intersect_key($this->data, $indices));
278
    }
279
280
    /**
281
     * Omit the items having one of the blacklisted indexes.
282
     *
283
     * @param array|...string|...int $index Either blacklisted indexes as array or as variads.
284
     *
285
     * @return self
286
     */
287
    public function omit($index)
288
    {
289
        $indices = \array_diff(
290
            \array_keys($this->data),
291
            \is_array($index) ? $index : \func_get_args()
292
        );
293
294
        return $this->pick($indices);
295
    }
296
297
    /**
298
     * Creates a shallow copy.
299
     *
300
     * @return self
301
     */
302
    public function clon()
303
    {
304
        return clone $this;
305
    }
306
307
    /**
308
     * Invokes callback fn with clone and returns original self.
309
     *
310
     * @param callable $fn
311
     *
312
     * @return self
313
     */
314
    public function tap(callable $fn)
315
    {
316
        $fn($this->clon());
317
318
        return $this;
319
    }
320
321
    /**
322
     * Adds a custom handler/method to instance. The handler is bound to this instance.
323
     *
324
     * @param string   $name
325
     * @param \Closure $fn
326
     *
327
     * @return self
328
     */
329
    public static function mixin($name, \Closure $fn)
330
    {
331
        static::$mixins[$name] = $fn;
332
    }
333
334
    /**
335
     * Calls the registered mixin by its name.
336
     *
337
     * @param string $name
338
     * @param array  $args
339
     *
340
     * @return self
341
     */
342
    public function __call($method, $args)
343
    {
344
        if (isset(static::$mixins[$method])) {
345
            $method = \Closure::bind(static::$mixins[$method], $this);
346
347
            return $method($args);
348
        }
349
350
        throw new UnderscoreException("The mixin with name '$method' is not defined");
351
    }
352
353
    /**
354
     * Facilitates the use of Higher Order Messaging.
355
     *
356
     * @param string $method
357
     *
358
     * @return self
359
     */
360
    public function __get($method)
361
    {
362
        // For now no mixins in HOM :)
363
        if (!\method_exists($this, $method)) {
364
            throw new UnderscoreException("The '$method' is not defined");
365
        }
366
367
        return new HigherOrderMessage($this, $method);
0 ignored issues
show
Bug Best Practice introduced by
The expression return new Ahc\Underscor...Message($this, $method) returns the type Ahc\Underscore\HigherOrderMessage which is incompatible with the documented return type Ahc\Underscore\UnderscoreBase.
Loading history...
368
    }
369
370
    /**
371
     * Get string value (JSON representation) of this instance.
372
     *
373
     * @return string
374
     */
375
    public function valueOf()
376
    {
377
        return (string) $this;
378
    }
379
}
380