Failed Conditions
Push — master ( edfbda...298c91 )
by Luís
16s
created

lib/Doctrine/DBAL/Cache/ResultCacheStatement.php (2 issues)

1
<?php
2
/*
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the MIT license. For more information, see
17
 * <http://www.doctrine-project.org>.
18
 */
19
20
namespace Doctrine\DBAL\Cache;
21
22
use Doctrine\DBAL\Driver\Statement;
23
use Doctrine\DBAL\Driver\ResultStatement;
24
use Doctrine\Common\Cache\Cache;
25
use PDO;
26
27
/**
28
 * Cache statement for SQL results.
29
 *
30
 * A result is saved in multiple cache keys, there is the originally specified
31
 * cache key which is just pointing to result rows by key. The following things
32
 * have to be ensured:
33
 *
34
 * 1. lifetime of the original key has to be longer than that of all the individual rows keys
35
 * 2. if any one row key is missing the query has to be re-executed.
36
 *
37
 * Also you have to realize that the cache will load the whole result into memory at once to ensure 2.
38
 * This means that the memory usage for cached results might increase by using this feature.
39
 */
40
class ResultCacheStatement implements \IteratorAggregate, ResultStatement
41
{
42
    /**
43
     * @var \Doctrine\Common\Cache\Cache
44
     */
45
    private $resultCache;
46
47
    /**
48
     *
49
     * @var string
50
     */
51
    private $cacheKey;
52
53
    /**
54
     * @var string
55
     */
56
    private $realKey;
57
58
    /**
59
     * @var integer
60
     */
61
    private $lifetime;
62
63
    /**
64
     * @var \Doctrine\DBAL\Driver\Statement
65
     */
66
    private $statement;
67
68
    /**
69
     * Did we reach the end of the statement?
70
     *
71
     * @var boolean
72
     */
73
    private $emptied = false;
74
75
    /**
76
     * @var array
77
     */
78
    private $data;
79
80
    /**
81
     * @var integer
82
     */
83
    private $defaultFetchMode = PDO::FETCH_BOTH;
84
85
    /**
86
     * @param \Doctrine\DBAL\Driver\Statement $stmt
87
     * @param \Doctrine\Common\Cache\Cache    $resultCache
88
     * @param string                          $cacheKey
89
     * @param string                          $realKey
90
     * @param integer                         $lifetime
91
     */
92 10
    public function __construct(Statement $stmt, Cache $resultCache, $cacheKey, $realKey, $lifetime)
93
    {
94 10
        $this->statement = $stmt;
95 10
        $this->resultCache = $resultCache;
96 10
        $this->cacheKey = $cacheKey;
97 10
        $this->realKey = $realKey;
98 10
        $this->lifetime = $lifetime;
99 10
    }
100
101
    /**
102
     * {@inheritdoc}
103
     */
104 9
    public function closeCursor()
105
    {
106 9
        $this->statement->closeCursor();
107 9
        if ($this->emptied && $this->data !== null) {
108 9
            $data = $this->resultCache->fetch($this->cacheKey);
109 9
            if ( ! $data) {
110 9
                $data = [];
111
            }
112 9
            $data[$this->realKey] = $this->data;
113
114 9
            $this->resultCache->save($this->cacheKey, $data, $this->lifetime);
115 9
            unset($this->data);
116
        }
117 9
    }
118
119
    /**
120
     * {@inheritdoc}
121
     */
122 4
    public function columnCount()
123
    {
124 4
        return $this->statement->columnCount();
125
    }
126
127
    /**
128
     * {@inheritdoc}
129
     */
130 10
    public function setFetchMode($fetchMode, $arg2 = null, $arg3 = null)
131
    {
132 10
        $this->defaultFetchMode = $fetchMode;
133
134 10
        return true;
135
    }
136
137
    /**
138
     * {@inheritdoc}
139
     */
140
    public function getIterator()
141
    {
142
        $data = $this->fetchAll();
143
144
        return new \ArrayIterator($data);
145
    }
146
147
    /**
148
     * {@inheritdoc}
149
     */
150 10
    public function fetch($fetchMode = null, $cursorOrientation = \PDO::FETCH_ORI_NEXT, $cursorOffset = 0)
151
    {
152 10
        if ($this->data === null) {
153 10
            $this->data = [];
154
        }
155
156 10
        $row = $this->statement->fetch(PDO::FETCH_ASSOC);
157 10
        if ($row) {
158 8
            $this->data[] = $row;
159
160 8
            $fetchMode = $fetchMode ?: $this->defaultFetchMode;
161
162 8
            if ($fetchMode == PDO::FETCH_ASSOC) {
163 4
                return $row;
164 6
            } elseif ($fetchMode == PDO::FETCH_NUM) {
165 3
                return array_values($row);
166 3
            } elseif ($fetchMode == PDO::FETCH_BOTH) {
167 2
                return array_merge($row, array_values($row));
168 1
            } elseif ($fetchMode == PDO::FETCH_COLUMN) {
169 1
                return reset($row);
170
            } else {
171
                throw new \InvalidArgumentException("Invalid fetch-style given for caching result.");
172
            }
173
        }
174 10
        $this->emptied = true;
175
176 10
        return false;
177
    }
178
179
    /**
180
     * {@inheritdoc}
181
     */
182 View Code Duplication
    public function fetchAll($fetchMode = null, $fetchArgument = null, $ctorArgs = null)
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
183
    {
184
        $rows = [];
185
        while ($row = $this->fetch($fetchMode)) {
186
            $rows[] = $row;
187
        }
188
189
        return $rows;
190
    }
191
192
    /**
193
     * {@inheritdoc}
194
     */
195 View Code Duplication
    public function fetchColumn($columnIndex = 0)
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
196
    {
197
        $row = $this->fetch(PDO::FETCH_NUM);
198
        if (!isset($row[$columnIndex])) {
199
            // TODO: verify this is correct behavior
200
            return false;
201
        }
202
203
        return $row[$columnIndex];
204
    }
205
206
    /**
207
     * Returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement
208
     * executed by the corresponding object.
209
     *
210
     * If the last SQL statement executed by the associated Statement object was a SELECT statement,
211
     * some databases may return the number of rows returned by that statement. However,
212
     * this behaviour is not guaranteed for all databases and should not be
213
     * relied on for portable applications.
214
     *
215
     * @return integer The number of rows.
216
     */
217
    public function rowCount()
218
    {
219
        return $this->statement->rowCount();
220
    }
221
}
222