Completed
Push — master ( 8775a9...8d3d9a )
by Todd
03:55 queued 39s
created

DatasetTrait::fetchAll()   C

Complexity

Conditions 11
Paths 8

Size

Total Lines 34
Code Lines 29

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 22.6475

Importance

Changes 0
Metric Value
dl 0
loc 34
ccs 13
cts 24
cp 0.5417
rs 5.2653
c 0
b 0
f 0
cc 11
eloc 29
nc 8
nop 2
crap 22.6475

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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;
9
10
use PDO;
11
12
trait DatasetTrait {
13
    private $offset = 0;
14
15
    private $limit = 0;
16
17
    private $order;
18
19
    /**
20
     * Get the dataset array.
21
     *
22
     * @return array
23
     */
24
    abstract public function getData();
25
26 1
    public function getPage() {
27 1
        if ($this->getLimit() === 0) {
28
            return 1;
29
        }
30 1
        $result = floor($this->getOffset() / (int)$this->getLimit()) + 1;
31
//        $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...
32 1
        return (int)$result;
33
    }
34
35 3
    public function setPage($page) {
36 3
        if (!is_numeric($page) || $page < 0) {
37
            throw new \InvalidArgumentException("Invalid page '$page.'", 500);
38
        }
39
40 3
        $this->setOffset(($page - 1) * $this->getLimit());
41 3
        return $this;
42
    }
43
44
    /**
45
     * Retrieve an external iterator
46
     * @link http://php.net/manual/en/iteratoraggregate.getiterator.php
47
     * @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...
48
     */
49 4
    public function getIterator() {
50 4
        return new \ArrayIterator($this->getData());
51
    }
52
53 10
    public function fetchAll($mode = 0, ...$args) {
54 10
        if ($mode === 0) {
55 1
            return $this->getData();
56
        }
57
58
        switch ($mode) {
59 9
            case PDO::FETCH_COLUMN:
60 3
                $result = $this->fetchArrayColumn(reset($args) ?: 0);
61 3
                break;
62 6
            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...
63 3
                $result = $this->fetchArrayColumn(0, reset($args) ?: 0, true);
64 3
                break;
65 3
            case PDO::FETCH_KEY_PAIR:
66 3
                $result = $this->fetchArrayColumn(1, 0);
67 3
                break;
68
            case PDO::FETCH_UNIQUE:
69
                $result = $this->fetchArrayColumn(null, reset($args) ?: 0);
70
                break;
71
            case PDO::FETCH_OBJ:
72
                $result = array_map(function ($row) {
73
                    return (object)$row;
74
                }, $this->getData($row));
0 ignored issues
show
Bug introduced by
The variable $row does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Unused Code introduced by
The call to DatasetTrait::getData() has too many arguments starting with $row.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
75
                break;
76
            case PDO::FETCH_ASSOC:
77
                $result = array_map(function ($row) {
78
                    return (array)$row;
79
                }, $this->getData($row));
0 ignored issues
show
Unused Code introduced by
The call to DatasetTrait::getData() has too many arguments starting with $row.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
80
                break;
81
            default:
82
                // Don't know what to do, return null.
83
                $result = null;
84
        }
85 9
        return $result;
86
    }
87
88
    /**
89
     * Fetch the data and perform a quasi-{@link array_column()} operation on it.
90
     *
91
     * @param string|int|null $columnKey The key or ordinal of the value or **null** to return the entire row.
92
     * @param string|int|null $indexKey The key or ordinal of the index or **null** to not index the data.
93
     * @param bool $grouped If true the result will be grouped by {@link $indexKey} and each value will be an array of rows.
94
     * @return array Returns the array of results.
95
     */
96 9
    public function fetchArrayColumn($columnKey = null, $indexKey = null, $grouped = false) {
97 9
        $arr = $this->getData();
98
99 9
        if (empty($arr)) {
100
            return [];
101
        }
102
103 9
        $firstRow = reset($arr);
104
105 9
        if (is_int($columnKey) || is_int($indexKey)) {
106 9
            $i = 0;
107 9
            foreach ($firstRow as $name => $value) {
108 9
                if ($i === $columnKey) {
109 9
                    $columnKey = $name;
110
                }
111
112 9
                if ($i === $indexKey) {
113 6
                    $indexKey = $name;
114
                }
115
116 9
                if (!(is_int($columnKey) || is_int($indexKey))) {
117 9
                    break;
118
                }
119 9
                $i++;
120
            }
121
        }
122
123 9
        if (!$grouped && is_array($firstRow)) {
124 2
            return array_column($arr, $columnKey, $indexKey);
125
        } else {
126 7
            $result = [];
127
128 7
            foreach ($arr as $i => $row) {
129 7
                if (is_array($row) || $row instanceof \ArrayAccess ) {
130 4
                    $value = $columnKey === null ? $row : $row[$columnKey];
131 4
                    $index = $indexKey === null ? $i : $row[$indexKey];
132
                } else {
133 3
                    $value = $columnKey === null ? $row : $row->$columnKey;
134 3
                    $index = $indexKey === null ? $i : $row->$indexKey;
135
                }
136
137 7
                if ($grouped) {
138 3
                    $result[$index][] = $value;
139
                } else {
140 4
                    $result[$index] = $value;
141
                }
142
            }
143
144 7
            return $result;
145
        }
146
    }
147
148
    /**
149
     * Get the first row of data.
150
     *
151
     * @return mixed|null Returns the first row or **null** if there is no data.
152
     */
153 1
    public function firstRow() {
154 1
        $data = $this->getData();
155
156 1
        return empty($data) ? null : $data[0];
157
    }
158
159
    /**
160
     * Get the number of records queried.
161
     *
162
     * @return int Returns the count.
163
     */
164 11
    public function count() {
165 11
        return count($this->getData());
166
    }
167
168
    /**
169
     * Specify data which should be serialized to JSON
170
     * @link http://php.net/manual/en/jsonserializable.jsonserialize.php
171
     * @return mixed data which can be serialized by <b>json_encode</b>,
172
     * which is a value of any type other than a resource.
173
     * @since 5.4.0
174
     */
175
    public function jsonSerialize() {
176
        return $this->getData();
177
    }
178
179
    /**
180
     * Get the offset.
181
     *
182
     * @return int Returns the offset.
183
     */
184 2
    public function getOffset() {
185 2
        return $this->offset;
186
    }
187
188
    /**
189
     * Set the offset.
190
     *
191
     * @param int $offset
192
     * @return $this
193
     */
194 1
    public function setOffset($offset) {
195 1
        if (!is_numeric($offset) || $offset < 0) {
196
            throw new \InvalidArgumentException("Invalid offset '$offset.'", 500);
197
        }
198
        
199 1
        $this->offset = $offset;
0 ignored issues
show
Documentation Bug introduced by
It seems like $offset can also be of type double or string. However, the property $offset is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
200 1
        return $this;
201
    }
202
203
    /**
204
     * Get the limit.
205
     *
206
     * @return int Returns the limit.
207
     */
208 4
    public function getLimit() {
209 4
        return $this->limit;
210
    }
211
212
    /**
213
     * Set the limit.
214
     *
215
     * @param int $limit
216
     * @return $this
217
     */
218 2
    public function setLimit($limit) {
219 2
        if (!is_numeric($limit) || $limit < 0) {
220
            throw new \InvalidArgumentException("Invalid limit '$limit.'", 500);
221
        }
222
223 2
        $this->limit = $limit;
0 ignored issues
show
Documentation Bug introduced by
It seems like $limit can also be of type double or string. However, the property $limit is declared as type integer. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
224 2
        return $this;
225
    }
226
227
    /**
228
     * Get the order.
229
     *
230
     * @return array Returns the order.
231
     */
232 4
    public function getOrder() {
233 4
        return $this->order;
234
    }
235
236
    /**
237
     * Set the order.
238
     *
239
     * @param mixed $columns
240
     * @return $this
241
     */
242
    public function setOrder(...$columns) {
243
        $this->order = $columns;
244
        return $this;
245
    }
246
}