Passed
Push — zero-is-false ( 14c39e...85b8a2 )
by Sam
06:15
created

PDOQuery::fetchAllPgsql()   A

Complexity

Conditions 5
Paths 2

Size

Total Lines 23
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 13
nc 2
nop 1
dl 0
loc 23
rs 9.5222
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\ORM\Connect;
4
5
use PDOStatement;
6
use PDO;
7
8
/**
9
 * A result-set from a PDO database.
10
 */
11
class PDOQuery extends Query
12
{
13
    /**
14
     * The internal MySQL handle that points to the result set.
15
     * @var PDOStatement
16
     */
17
    protected $statement = null;
18
19
    protected $results = null;
20
21
    const TYPE_MAPPING = [
22
        // PGSQL
23
        'float8' => 'float',
24
        'float16' => 'float',
25
        'numeric' => 'float',
26
27
        // MySQL
28
        'NEWDECIMAL' => 'float',
29
30
        // SQlite
31
        'integer' => 'int',
32
        'double' => 'float',
33
    ];
34
35
    /**
36
     * Hook the result-set given into a Query class, suitable for use by SilverStripe.
37
     * @param PDOStatement $statement The internal PDOStatement containing the results
38
     */
39
    public function __construct(PDOStatement $statement)
40
    {
41
        $this->statement = $statement;
42
        // Since no more than one PDOStatement for any one connection can be safely
43
        // traversed, each statement simply requests all rows at once for safety.
44
        // This could be re-engineered to call fetchAll on an as-needed basis
45
46
        $this->results = $this->typeCorrectedFetchAll($statement);
47
48
        $statement->closeCursor();
49
    }
50
51
    /**
52
     * Fetch a record form the statement with its type data corrected
53
     * Returns data as an array of maps
54
     * @return array
55
     */
56
    protected function typeCorrectedFetchAll($statement)
57
    {
58
        $columnCount = $statement->columnCount();
59
        $columnMeta = [];
60
        for ($i = 0; $i<$columnCount; $i++) {
61
            $columnMeta[$i] = $statement->getColumnMeta($i);
62
        }
63
64
        // Re-map fetched data using columnMeta
65
        return array_map(
66
            function ($rowArray) use ($columnMeta) {
67
                $row = [];
68
                foreach ($columnMeta as $i => $meta) {
69
                    // Coerce any column types that aren't correctly retrieved from the database
70
                    if (isset($meta['native_type']) && isset(self::TYPE_MAPPING[$meta['native_type']])) {
71
                        settype($rowArray[$i], self::TYPE_MAPPING[$meta['native_type']]);
72
                    }
73
                    $row[$meta['name']] = $rowArray[$i];
74
                }
75
                return $row;
76
            },
77
            $statement->fetchAll(PDO::FETCH_NUM)
78
        );
79
    }
80
81
    public function seek($row)
82
    {
83
        $this->rowNum = $row - 1;
84
        return $this->nextRecord();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->nextRecord() also could return the type false which is incompatible with the return type mandated by SilverStripe\ORM\Connect\Query::seek() of array.
Loading history...
85
    }
86
87
    public function numRecords()
88
    {
89
        return count($this->results);
90
    }
91
92
    public function nextRecord()
93
    {
94
        $index = $this->rowNum + 1;
95
96
        if (isset($this->results[$index])) {
97
            return $this->results[$index];
98
        } else {
99
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the return type mandated by SilverStripe\ORM\Connect\Query::nextRecord() of array.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
100
        }
101
    }
102
}
103