Passed
Push — programming-is-horrible ( 2233ca...483908 )
by Sam
08:19
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
    /**
22
     * Hook the result-set given into a Query class, suitable for use by SilverStripe.
23
     * @param PDOStatement $statement The internal PDOStatement containing the results
24
     */
25
    public function __construct(PDOStatement $statement, PDOConnector $conn)
26
    {
27
        $this->statement = $statement;
28
        // Since no more than one PDOStatement for any one connection can be safely
29
        // traversed, each statement simply requests all rows at once for safety.
30
        // This could be re-engineered to call fetchAll on an as-needed basis
31
32
        // Special case for Postgres
33
        if ($conn->getDriver() == 'pgsql') {
34
            $this->results = $this->fetchAllPgsql($statement);
35
        } else {
36
            $this->results = $statement->fetchAll(PDO::FETCH_ASSOC);
37
        }
38
        $statement->closeCursor();
39
    }
40
41
    /**
42
     * Fetch a record form the statement with its type data corrected
43
     * Necessary to fix float data retrieved from PGSQL
44
     * Returns data as an array of maps
45
     * @return array
46
     */
47
    protected function fetchAllPgsql($statement)
48
    {
49
        $columnCount = $statement->columnCount();
50
        $columnMeta = [];
51
        for ($i = 0; $i<$columnCount; $i++) {
52
            $columnMeta[$i] = $statement->getColumnMeta($i);
53
        }
54
55
        // Re-map fetched data using columnMeta
56
        return array_map(
57
            function ($rowArray) use ($columnMeta) {
58
                $row = [];
59
                foreach ($columnMeta as $i => $meta) {
60
                    // Coerce floats from string to float
61
                    // PDO PostgreSQL fails to do this
62
                    if (isset($meta['native_type']) && strpos($meta['native_type'], 'float') === 0) {
63
                        $rowArray[$i] = (float)$rowArray[$i];
64
                    }
65
                    $row[$meta['name']] = $rowArray[$i];
66
                }
67
                return $row;
68
            },
69
            $statement->fetchAll(PDO::FETCH_NUM)
70
        );
71
    }
72
73
    public function seek($row)
74
    {
75
        $this->rowNum = $row - 1;
76
        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...
77
    }
78
79
    public function numRecords()
80
    {
81
        return count($this->results);
82
    }
83
84
    public function nextRecord()
85
    {
86
        $index = $this->rowNum + 1;
87
88
        if (isset($this->results[$index])) {
89
            return $this->results[$index];
90
        } else {
91
            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...
92
        }
93
    }
94
}
95