Failed Conditions
Pull Request — master (#3359)
by Sergei
25:01 queued 22:04
created

ResultCacheStatement::setFetchMode()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 2
dl 0
loc 5
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 3
crap 1
1
<?php
2
3
namespace Doctrine\DBAL\Cache;
4
5
use ArrayIterator;
6
use Doctrine\Common\Cache\Cache;
7
use Doctrine\DBAL\DBALException;
8
use Doctrine\DBAL\Driver\ResultStatement;
9
use Doctrine\DBAL\Driver\Statement;
10
use Doctrine\DBAL\FetchMode;
11
use InvalidArgumentException;
12
use IteratorAggregate;
13
use PDO;
14
use function array_merge;
15
use function array_values;
16
use function count;
17
use function reset;
18
19
/**
20
 * Cache statement for SQL results.
21
 *
22
 * A result is saved in multiple cache keys, there is the originally specified
23
 * cache key which is just pointing to result rows by key. The following things
24
 * have to be ensured:
25
 *
26
 * 1. lifetime of the original key has to be longer than that of all the individual rows keys
27
 * 2. if any one row key is missing the query has to be re-executed.
28
 *
29
 * Also you have to realize that the cache will load the whole result into memory at once to ensure 2.
30
 * This means that the memory usage for cached results might increase by using this feature.
31
 */
32
class ResultCacheStatement implements IteratorAggregate, ResultStatement
33
{
34
    /** @var Cache */
35
    private $resultCache;
36
37
    /** @var string */
38
    private $cacheKey;
39
40
    /** @var string */
41
    private $realKey;
42
43
    /** @var int */
44
    private $lifetime;
45
46
    /** @var Statement */
47
    private $statement;
48
49
    /**
50
     * Did we reach the end of the statement?
51
     *
52
     * @var bool
53
     */
54
    private $emptied = false;
55
56
    /** @var mixed[] */
57
    private $data;
58
59
    /** @var int */
60
    private $defaultFetchMode = FetchMode::MIXED;
61
62
    /**
63
     * @param string $cacheKey
64
     * @param string $realKey
65
     * @param int    $lifetime
66
     */
67 230
    public function __construct(Statement $stmt, Cache $resultCache, $cacheKey, $realKey, $lifetime)
68
    {
69 230
        $this->statement   = $stmt;
70 230
        $this->resultCache = $resultCache;
71 230
        $this->cacheKey    = $cacheKey;
72 230
        $this->realKey     = $realKey;
73 230
        $this->lifetime    = $lifetime;
74 230
    }
75
76
    /**
77
     * {@inheritdoc}
78
     */
79 207
    public function closeCursor()
80
    {
81 207
        $this->statement->closeCursor();
82 207
        if (! $this->emptied || $this->data === null) {
83 23
            return true;
84
        }
85
86 207
        $data = $this->resultCache->fetch($this->cacheKey);
87 207
        if (! $data) {
88 207
            $data = [];
89
        }
90 207
        $data[$this->realKey] = $this->data;
91
92 207
        $this->resultCache->save($this->cacheKey, $data, $this->lifetime);
93 207
        unset($this->data);
94
95 207
        return true;
96
    }
97
98
    /**
99
     * {@inheritdoc}
100
     */
101 92
    public function columnCount()
102
    {
103 92
        return $this->statement->columnCount();
104
    }
105
106
    /**
107
     * {@inheritdoc}
108
     */
109 230
    public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null)
110
    {
111 230
        $this->defaultFetchMode = $fetchMode;
112
113 230
        return true;
114
    }
115
116
    /**
117
     * {@inheritdoc}
118
     */
119
    public function getIterator()
120
    {
121
        $data = $this->fetchAll();
122
123
        return new ArrayIterator($data);
124
    }
125
126
    /**
127
     * {@inheritdoc}
128
     */
129 230
    public function fetch($fetchMode = null, $cursorOrientation = PDO::FETCH_ORI_NEXT, $cursorOffset = 0)
130
    {
131 230
        if ($this->data === null) {
132 230
            $this->data = [];
133
        }
134
135 230
        $row = $this->statement->fetch(FetchMode::ASSOCIATIVE);
136
137 230
        if ($row) {
138 184
            $this->data[] = $row;
139
140 184
            $fetchMode = $fetchMode ?: $this->defaultFetchMode;
141
142 184
            if ($fetchMode === FetchMode::ASSOCIATIVE) {
143 92
                return $row;
144
            }
145
146 138
            if ($fetchMode === FetchMode::NUMERIC) {
147 69
                return array_values($row);
148
            }
149
150 69
            if ($fetchMode === FetchMode::MIXED) {
151 46
                return array_merge($row, array_values($row));
152
            }
153
154 23
            if ($fetchMode === FetchMode::COLUMN) {
155 23
                return reset($row);
156
            }
157
158
            throw new InvalidArgumentException('Invalid fetch-style given for caching result.');
159
        }
160
161 230
        $this->emptied = true;
162
163 230
        return false;
164
    }
165
166
    /**
167
     * {@inheritdoc}
168
     */
169
    public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null)
170
    {
171
        return $this->statement->fetchAll($fetchMode, $fetchArgument, $ctorArgs);
172
    }
173
174
    /**
175
     * {@inheritdoc}
176
     */
177
    public function fetchColumn($columnIndex = 0)
178
    {
179
        $row = $this->fetch(FetchMode::NUMERIC);
180
181
        if ($row === false) {
182
            return false;
183
        }
184
185
        if ($columnIndex >= count($row)) {
186
            throw DBALException::invalidColumnIndex($columnIndex, count($row));
187
        }
188
189
        return $row[$columnIndex];
190
    }
191
192
    /**
193
     * Returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement
194
     * executed by the corresponding object.
195
     *
196
     * If the last SQL statement executed by the associated Statement object was a SELECT statement,
197
     * some databases may return the number of rows returned by that statement. However,
198
     * this behaviour is not guaranteed for all databases and should not be
199
     * relied on for portable applications.
200
     *
201
     * @return int The number of rows.
202
     */
203
    public function rowCount()
204
    {
205
        return $this->statement->rowCount();
206
    }
207
}
208