Statement.php 5.48 KB
Newer Older
1 2
<?php

Michael Moravec's avatar
Michael Moravec committed
3 4
declare(strict_types=1);

5 6
namespace Doctrine\DBAL\Portability;

Sergei Morozov's avatar
Sergei Morozov committed
7
use Doctrine\DBAL\Driver\ResultStatement;
8
use Doctrine\DBAL\Driver\Statement as DriverStatement;
9
use Doctrine\DBAL\Driver\StatementIterator;
10 11
use Doctrine\DBAL\FetchMode;
use Doctrine\DBAL\ParameterType;
12
use IteratorAggregate;
13
use function array_change_key_case;
Sergei Morozov's avatar
Sergei Morozov committed
14
use function assert;
15 16
use function is_string;
use function rtrim;
17 18

/**
Benjamin Morel's avatar
Benjamin Morel committed
19
 * Portability wrapper for a Statement.
20
 */
21
final class Statement implements IteratorAggregate, DriverStatement
22
{
23
    /** @var int */
24
    private $portability;
25

Sergei Morozov's avatar
Sergei Morozov committed
26
    /** @var DriverStatement|ResultStatement */
27
    private $stmt;
28

Benjamin Morel's avatar
Benjamin Morel committed
29
    /** @var int|null */
30 31
    private $case;

32
    /** @var int */
33
    private $defaultFetchMode = FetchMode::MIXED;
34

35
    /**
Benjamin Morel's avatar
Benjamin Morel committed
36
     * Wraps <tt>Statement</tt> and applies portability measures.
37
     *
Sergei Morozov's avatar
Sergei Morozov committed
38
     * @param DriverStatement|ResultStatement $stmt
39 40 41
     */
    public function __construct($stmt, Connection $conn)
    {
42
        $this->stmt        = $stmt;
43
        $this->portability = $conn->getPortability();
44
        $this->case        = $conn->getFetchCase();
45 46
    }

Benjamin Morel's avatar
Benjamin Morel committed
47 48 49
    /**
     * {@inheritdoc}
     */
50
    public function bindParam($param, &$variable, int $type = ParameterType::STRING, ?int $length = null) : void
51
    {
Sergei Morozov's avatar
Sergei Morozov committed
52 53
        assert($this->stmt instanceof DriverStatement);

54
        $this->stmt->bindParam($param, $variable, $type, $length);
55
    }
56

Benjamin Morel's avatar
Benjamin Morel committed
57 58 59
    /**
     * {@inheritdoc}
     */
60
    public function bindValue($param, $value, int $type = ParameterType::STRING) : void
61
    {
Sergei Morozov's avatar
Sergei Morozov committed
62 63
        assert($this->stmt instanceof DriverStatement);

64
        $this->stmt->bindValue($param, $value, $type);
65 66
    }

67
    public function closeCursor() : void
68
    {
69
        $this->stmt->closeCursor();
70 71
    }

72
    public function columnCount() : int
73 74 75 76
    {
        return $this->stmt->columnCount();
    }

Benjamin Morel's avatar
Benjamin Morel committed
77 78 79
    /**
     * {@inheritdoc}
     */
80
    public function execute(?array $params = null) : void
81
    {
Sergei Morozov's avatar
Sergei Morozov committed
82 83
        assert($this->stmt instanceof DriverStatement);

84
        $this->stmt->execute($params);
85 86
    }

Benjamin Morel's avatar
Benjamin Morel committed
87 88 89
    /**
     * {@inheritdoc}
     */
90
    public function setFetchMode(int $fetchMode, ...$args) : void
91
    {
92
        $this->defaultFetchMode = $fetchMode;
Benjamin Morel's avatar
Benjamin Morel committed
93

94
        $this->stmt->setFetchMode($fetchMode, ...$args);
95 96
    }

Benjamin Morel's avatar
Benjamin Morel committed
97 98 99
    /**
     * {@inheritdoc}
     */
100 101
    public function getIterator()
    {
102
        return new StatementIterator($this);
103 104
    }

Benjamin Morel's avatar
Benjamin Morel committed
105 106 107
    /**
     * {@inheritdoc}
     */
108
    public function fetch(?int $fetchMode = null, ...$args)
109
    {
110
        $fetchMode = $fetchMode ?: $this->defaultFetchMode;
111

112
        $row = $this->stmt->fetch($fetchMode, ...$args);
113

114
        $iterateRow = ($this->portability & (Connection::PORTABILITY_EMPTY_TO_NULL|Connection::PORTABILITY_RTRIM)) !== 0;
115
        $fixCase    = $this->case !== null
116
            && ($fetchMode === FetchMode::ASSOCIATIVE || $fetchMode === FetchMode::MIXED)
117 118 119
            && ($this->portability & Connection::PORTABILITY_FIX_CASE);

        $row = $this->fixRow($row, $iterateRow, $fixCase);
120

121 122 123
        return $row;
    }

Benjamin Morel's avatar
Benjamin Morel committed
124 125 126
    /**
     * {@inheritdoc}
     */
127
    public function fetchAll(?int $fetchMode = null, ...$args) : array
128
    {
129
        $fetchMode = $fetchMode ?: $this->defaultFetchMode;
130

131
        $rows = $this->stmt->fetchAll($fetchMode, ...$args);
132

133
        $iterateRow = ($this->portability & (Connection::PORTABILITY_EMPTY_TO_NULL|Connection::PORTABILITY_RTRIM)) !== 0;
134
        $fixCase    = $this->case !== null
135 136 137
            && ($fetchMode === FetchMode::ASSOCIATIVE || $fetchMode === FetchMode::MIXED)
            && ($this->portability & Connection::PORTABILITY_FIX_CASE);

138
        if (! $iterateRow && ! $fixCase) {
139 140 141
            return $rows;
        }

142
        if ($fetchMode === FetchMode::COLUMN) {
143
            foreach ($rows as $num => $row) {
144
                $rows[$num] = [$row];
145 146 147
            }
        }

148
        foreach ($rows as $num => $row) {
149 150
            $rows[$num] = $this->fixRow($row, $iterateRow, $fixCase);
        }
151

152
        if ($fetchMode === FetchMode::COLUMN) {
153 154 155 156 157
            foreach ($rows as $num => $row) {
                $rows[$num] = $row[0];
            }
        }

158 159
        return $rows;
    }
160

Benjamin Morel's avatar
Benjamin Morel committed
161 162 163
    /**
     * {@inheritdoc}
     */
164
    public function fetchColumn(int $columnIndex = 0)
165 166
    {
        $value = $this->stmt->fetchColumn($columnIndex);
167

168 169 170
        if ($this->portability & (Connection::PORTABILITY_EMPTY_TO_NULL|Connection::PORTABILITY_RTRIM)) {
            if (($this->portability & Connection::PORTABILITY_EMPTY_TO_NULL) && $value === '') {
                $value = null;
Steve Müller's avatar
Steve Müller committed
171
            } elseif (($this->portability & Connection::PORTABILITY_RTRIM) && is_string($value)) {
172 173 174
                $value = rtrim($value);
            }
        }
175

176 177 178
        return $value;
    }

179
    public function rowCount() : int
180
    {
Sergei Morozov's avatar
Sergei Morozov committed
181 182
        assert($this->stmt instanceof DriverStatement);

183 184
        return $this->stmt->rowCount();
    }
185 186 187 188 189 190 191 192 193 194 195 196 197

    /**
     * @param mixed $row
     *
     * @return mixed
     */
    private function fixRow($row, bool $iterateRow, bool $fixCase)
    {
        if (! $row) {
            return $row;
        }

        if ($fixCase) {
Benjamin Morel's avatar
Benjamin Morel committed
198
            assert($this->case !== null);
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
            $row = array_change_key_case($row, $this->case);
        }

        if ($iterateRow) {
            foreach ($row as $k => $v) {
                if (($this->portability & Connection::PORTABILITY_EMPTY_TO_NULL) && $v === '') {
                    $row[$k] = null;
                } elseif (($this->portability & Connection::PORTABILITY_RTRIM) && is_string($v)) {
                    $row[$k] = rtrim($v);
                }
            }
        }

        return $row;
    }
214
}