Completed
Push — master ( 10f953...ab5b42 )
by Todd
9s
created

DatasetTrait::getIterator()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 3
ccs 2
cts 2
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
crap 1
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;
0 ignored issues
show
Unused Code Comprehensibility introduced by
58% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
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
Documentation introduced by
Should the return type not be \ArrayIterator?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
68
     */
69 4
    public function getIterator() {
70 4
        return new \ArrayIterator($this->getData());
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;
0 ignored issues
show
Coding Style introduced by
case statements should be defined using a colon.

As per the PSR-2 coding standard, case statements should not be wrapped in curly braces. There is no need for braces, since each case is terminated by the next break.

There is also the option to use a semicolon instead of a colon, this is discouraged because many programmers do not even know it works and the colon is universal between programming languages.

switch ($expr) {
    case "A": { //wrong
        doSomething();
        break;
    }
    case "B"; //wrong
        doSomething();
        break;
    case "C": //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
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;
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 7
                    $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) {
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) {
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
     */
0 ignored issues
show
Documentation introduced by
Should the type for parameter $columns not be string[]?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
262
    public function setOrder(...$columns) {
263
        $this->order = $columns;
264
        return $this;
265
    }
266
}
267