Completed
Push — master ( caa5cb...e1e3f4 )
by Alexandr
03:24
created

ArrayRecordset::orderByCallable()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace R2\Helpers;
4
5
use Spatie\Macroable\Macroable;
6
7
class ArrayRecordset
8
{
9
    const CASE_SENSITIVE = 1;
10
    const PRESERVE_KEYS = 2;
11
12
    /** @var string */
13
    protected $name = 'Recordset';
14
15
    use Macroable;
16
17
    /** @var array */
18
    protected $data;
19
20
    /** @var int */
21
    protected $options;
22
23
    /** @var callable[] */
24
    protected $comparators;
25
26
    /**
27
     * Chain constructor.
28
     *
29
     * @param array $data
30
     */
31
    public function __construct(array $data = [], int $options = 0)
32
    {
33
        $this->data = $data;
34
        $this->options = $options;
35
        $this->comparators = [];
36
    }
37
38
    /**
39
     * Set source data.
40
     *
41
     * @param array $data
42
     * @return self
43
     */
44
    public function data(array $data = []): self
45
    {
46
        $this->data = $data;
47
        return $this;
48
    }
49
50
    /**
51
     * Simple sort.
52
     *
53
     * @param string $field
54
     * @param string $direction
55
     * @return self
56
     */
57
    public function orderBy(string $field, string $direction = 'asc'): self
58
    {
59
        $sign = strtolower($direction) === 'asc' ? 1 : -1;
60
        if ($this->options & self::CASE_SENSITIVE) {
61
            $this->comparators[] = function ($a, $b) use ($field, $sign) {
62
                return strnatcmp($a[$field], $b[$field]) * $sign;
63
            };
64
        } else {
65
            $this->comparators[] = function ($a, $b) use ($field, $sign) {
66
                return strnatcasecmp($a[$field], $b[$field]) * $sign;
67
            };
68
        }
69
        return $this;
70
    }
71
72
    /**
73
     * Sort by arbitrary function applicable for PHP usort().
74
     *
75
     * @param callable $func
76
     * @return self
77
     */
78
    public function orderByCallable(callable $func): self
79
    {
80
        $this->comparators[] = $func;
81
        return $this;
82
    }
83
84
    /**
85
     * Group by field.
86
     * It cause additional dimension of array. Should be called right before the get() or first() call.
87
     *
88
     * @param string $field
89
     * @return self
90
     */
91
    public function groupBy(string $field): self
92
    {
93
        $grouped = [];
94
        foreach ($this->get() as $item) {
95
            $key = $item[$field];
96
            $grouped[$key][] = $item;
97
        }
98
        $this->data = $grouped;
99
        $this->comparators = [];
100
        return $this;
101
    }
102
103
    /**
104
     * Get result array.
105
     *
106
     * @return array
107
     */
108
    public function get(): array
109
    {
110
        if ($this->comparators) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->comparators of type array<mixed,callable> is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
111
            $sort = $this->options & self::PRESERVE_KEYS ? 'uasort' : 'usort';
112
            $sort($this->data, function ($a, $b) {
113
                foreach ($this->comparators as $f) {
114
                    $result = $f($a, $b);
115
                    if ($result !== 0) {
116
                        return $result;
117
                    }
118
                }
119
                return 0;
120
            });
121
        }
122
        return $this->data;
123
    }
124
125
    /**
126
     * Get first record only.
127
     *
128
     * @return array
129
     */
130
    public function first(): array
131
    {
132
        $result = $this->get();
133
        return reset($result);
134
    }
135
136
    /**
137
     * Get first given field value of first record only.
138
     *
139
     * @param string $field
140
     * @return mixed
141
     */
142
    public function value(string $field)
143
    {
144
        $result = $this->get();
145
        return reset($result)[$field];
146
    }
147
148
    /**
149
     * Plucka n array of values.
150
     *
151
     * @param mixed      $value
152
     * @param mixed|null $key
153
     * @return array
154
     */
155
    public function pluck($value, $key = null): array
156
    {
157
        $results = [];
158
        foreach ($this->get() as $item) {
159
            $itemValue = $item[$value];
160
            if (is_null($key)) {
161
                $results[] = $itemValue;
162
            } else {
163
                $itemKey = $item[$key];
164
                $results[$itemKey] = $itemValue;
165
            }
166
        }
167
        return $results;
168
    }
169
}
170