DatasetTrait::jsonSerialize()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 2
ccs 0
cts 2
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * @author Todd Burry <[email protected]>
4
 * @copyright 2009-2017 Vanilla Forums Inc.
5
 * @license MIT
6
 */
7
8
namespace Garden\Db\Utils;
9
10
use PDO;
11
12
trait DatasetTrait {
13
    /**
14
     * @var int
15
     */
16
    private $offset = 0;
17
18
    /**
19
     * @var int
20
     */
21
    private $limit = 0;
22
23
    /**
24
     * @var string[]
25
     */
26
    private $order;
27
28
    /**
29
     * Get the dataset array.
30
     *
31
     * @return array
32
     */
33
    abstract public function getData();
34
35
    /**
36
     * Get the current page.
37
     *
38
     * @return int Returns the page number.
39
     */
40 1
    public function getPage(): int {
41 1
        if ($this->getLimit() === 0) {
42
            return 1;
43
        }
44 1
        $result = floor($this->getOffset() / (int)$this->getLimit()) + 1;
45
//        $result = intdiv($this->getOffset(), (int)$this->getLimit()) + 1;
46 1
        return (int)$result;
47
    }
48
49
    /**
50
     * Set the current page.
51
     *
52
     * @param int $page A valid page number.
53
     * @return $this
54
     */
55 3
    public function setPage(int $page) {
56 3
        if ($page < 0) {
57
            throw new \InvalidArgumentException("Invalid page '$page.'", 500);
58
        }
59
60 3
        $this->setOffset(($page - 1) * $this->getLimit());
61 3
        return $this;
62
    }
63
64
    /**
65
     * Retrieve an external iterator
66
     * @link http://php.net/manual/en/iteratoraggregate.getiterator.php
67
     * @return Traversable Returns a generator of all rows.
0 ignored issues
show
Bug introduced by
The type Garden\Db\Utils\Traversable was not found. Did you mean Traversable? If so, make sure to prefix the type with \.
Loading history...
68
     */
69 4
    public function getIterator() {
70 4
        return new \ArrayIterator($this->getData());
0 ignored issues
show
Bug Best Practice introduced by
The expression return new ArrayIterator($this->getData()) returns the type ArrayIterator which is incompatible with the documented return type Garden\Db\Utils\Traversable.
Loading history...
71
    }
72
73 10
    public function fetchAll(int $mode = 0, ...$args): array {
74 10
        if ($mode === 0) {
75 1
            return $this->getData();
76
        }
77
78 9
        switch ($mode) {
79
            case PDO::FETCH_COLUMN:
80 3
                $result = $this->fetchArrayColumn(reset($args) ?: 0);
81 3
                break;
82
            case PDO::FETCH_COLUMN | PDO::FETCH_GROUP;
83 3
                $result = $this->fetchArrayColumn(0, reset($args) ?: 0, true);
84 3
                break;
85
            case PDO::FETCH_KEY_PAIR:
86 3
                $result = $this->fetchArrayColumn(1, 0);
87 3
                break;
88
            case PDO::FETCH_UNIQUE:
89
                $result = $this->fetchArrayColumn(null, reset($args) ?: 0);
90
                break;
91
            case PDO::FETCH_OBJ:
92
                $result = array_map(function ($row) {
93
                    return (object)$row;
94
                }, $this->getData());
95
                break;
96
            case PDO::FETCH_ASSOC:
97
                $result = array_map(function ($row) {
98
                    return (array)$row;
99
                }, $this->getData());
100
                break;
101
            default:
102
                // Don't know what to do, return null.
103
                $result = null;
104
        }
105 9
        return $result;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $result could return the type null which is incompatible with the type-hinted return array. Consider adding an additional type-check to rule them out.
Loading history...
106
    }
107
108
    /**
109
     * Fetch the data and perform a quasi-{@link array_column()} operation on it.
110
     *
111
     * @param string|int|null $columnKey The key or ordinal of the value or **null** to return the entire row.
112
     * @param string|int|null $indexKey The key or ordinal of the index or **null** to not index the data.
113
     * @param bool $grouped If true the result will be grouped by {@link $indexKey} and each value will be an array of rows.
114
     * @return array Returns the array of results.
115
     */
116 9
    public function fetchArrayColumn($columnKey = null, $indexKey = null, bool $grouped = false): array {
117 9
        $arr = $this->getData();
118
119 9
        if (empty($arr)) {
120
            return [];
121
        }
122
123 9
        $firstRow = reset($arr);
124
125 9
        if (is_int($columnKey) || is_int($indexKey)) {
126 9
            $i = 0;
127 9
            foreach ($firstRow as $name => $value) {
128 9
                if ($i === $columnKey) {
129 9
                    $columnKey = $name;
130
                }
131
132 9
                if ($i === $indexKey) {
133 6
                    $indexKey = $name;
134
                }
135
136 9
                if (!(is_int($columnKey) || is_int($indexKey))) {
137 9
                    break;
138
                }
139 9
                $i++;
140
            }
141
        }
142
143 9
        if (!$grouped && is_array($firstRow)) {
144 2
            return array_column($arr, $columnKey, $indexKey);
145
        } else {
146 7
            $result = [];
147
148 7
            foreach ($arr as $i => $row) {
149 7
                if (is_array($row) || $row instanceof \ArrayAccess ) {
150 4
                    $value = $columnKey === null ? $row : $row[$columnKey];
151 4
                    $index = $indexKey === null ? $i : $row[$indexKey];
152
                } else {
153 3
                    $value = $columnKey === null ? $row : $row->$columnKey;
154 3
                    $index = $indexKey === null ? $i : $row->$indexKey;
155
                }
156
157 7
                if ($grouped) {
158 3
                    $result[$index][] = $value;
159
                } else {
160 4
                    $result[$index] = $value;
161
                }
162
            }
163
164 7
            return $result;
165
        }
166
    }
167
168
    /**
169
     * Get the first row of data.
170
     *
171
     * @return mixed|null Returns the first row or **null** if there is no data.
172
     */
173 1
    public function firstRow() {
174 1
        $data = $this->getData();
175
176 1
        return empty($data) ? null : $data[0];
177
    }
178
179
    /**
180
     * Get the number of records queried.
181
     *
182
     * @return int Returns the count.
183
     */
184 11
    public function count(): int {
185 11
        return count($this->getData());
186
    }
187
188
    /**
189
     * Specify data which should be serialized to JSON
190
     * @link http://php.net/manual/en/jsonserializable.jsonserialize.php
191
     * @return mixed data which can be serialized by <b>json_encode</b>,
192
     * which is a value of any type other than a resource.
193
     * @since 5.4.0
194
     */
195
    public function jsonSerialize() {
196
        return $this->getData();
197
    }
198
199
    /**
200
     * Get the offset.
201
     *
202
     * @return int Returns the offset.
203
     */
204 2
    public function getOffset() {
205 2
        return $this->offset;
206
    }
207
208
    /**
209
     * Set the offset.
210
     *
211
     * @param int $offset
212
     * @return $this
213
     */
214 1
    public function setOffset($offset) {
215 1
        if (!is_numeric($offset) || $offset < 0) {
0 ignored issues
show
introduced by
The condition is_numeric($offset) is always true.
Loading history...
216
            throw new \InvalidArgumentException("Invalid offset '$offset.'", 500);
217
        }
218
219 1
        $this->offset = (int)$offset;
220 1
        return $this;
221
    }
222
223
    /**
224
     * Get the limit.
225
     *
226
     * @return int Returns the limit.
227
     */
228 4
    public function getLimit() {
229 4
        return $this->limit;
230
    }
231
232
    /**
233
     * Set the limit.
234
     *
235
     * @param int $limit
236
     * @return $this
237
     */
238 2
    public function setLimit($limit) {
239 2
        if (!is_numeric($limit) || $limit < 0) {
0 ignored issues
show
introduced by
The condition is_numeric($limit) is always true.
Loading history...
240
            throw new \InvalidArgumentException("Invalid limit '$limit.'", 500);
241
        }
242
243 2
        $this->limit = (int)$limit;
244 2
        return $this;
245
    }
246
247
    /**
248
     * Get the sort order.
249
     *
250
     * @return string[] Returns an array of column names, optionally prefixed with "-" to denote descending order.
251
     */
252 4
    public function getOrder() {
253 4
        return $this->order;
254
    }
255
256
    /**
257
     * Set the sort order.
258
     *
259
     * @param string ...$columns The column names to sort by, optionally prefixed with "-" to denote descending order.
260
     * @return $this
261
     */
262
    public function setOrder(...$columns) {
263
        $this->order = $columns;
264
        return $this;
265
    }
266
}
267