ResultCacheTest.php 7.91 KB
Newer Older
1 2 3
<?php

namespace Doctrine\Tests\DBAL\Functional;
4

Sergei Morozov's avatar
Sergei Morozov committed
5
use Doctrine\Common\Cache\ArrayCache;
6
use Doctrine\DBAL\Cache\QueryCacheProfile;
7
use Doctrine\DBAL\FetchMode;
Gabriel Caruso's avatar
Gabriel Caruso committed
8
use Doctrine\DBAL\Logging\DebugStack;
Sergei Morozov's avatar
Sergei Morozov committed
9 10
use Doctrine\DBAL\Schema\Table;
use Doctrine\Tests\DbalFunctionalTestCase;
11 12 13 14 15 16
use const CASE_LOWER;
use function array_change_key_case;
use function array_merge;
use function array_shift;
use function array_values;
use function is_array;
17 18 19 20

/**
 * @group DDC-217
 */
Sergei Morozov's avatar
Sergei Morozov committed
21
class ResultCacheTest extends DbalFunctionalTestCase
22
{
Sergei Morozov's avatar
Sergei Morozov committed
23 24 25 26
    /** @var int[][]|string[][] */
    private $expectedResult = [['test_int' => 100, 'test_string' => 'foo'], ['test_int' => 200, 'test_string' => 'bar'], ['test_int' => 300, 'test_string' => 'baz']];

    /** @var DebugStack */
27 28
    private $sqlLogger;

29
    protected function setUp()
30 31 32
    {
        parent::setUp();

Sergei Morozov's avatar
Sergei Morozov committed
33
        $table = new Table('caching');
34
        $table->addColumn('test_int', 'integer');
Sergei Morozov's avatar
Sergei Morozov committed
35 36
        $table->addColumn('test_string', 'string', ['notnull' => false]);
        $table->setPrimaryKey(['test_int']);
37

Sergei Morozov's avatar
Sergei Morozov committed
38
        $sm = $this->connection->getSchemaManager();
39
        $sm->createTable($table);
40

jeroendedauw's avatar
jeroendedauw committed
41
        foreach ($this->expectedResult as $row) {
Sergei Morozov's avatar
Sergei Morozov committed
42
            $this->connection->insert('caching', $row);
43 44
        }

Sergei Morozov's avatar
Sergei Morozov committed
45
        $config                                = $this->connection->getConfiguration();
Sergei Morozov's avatar
Sergei Morozov committed
46
        $config->setSQLLogger($this->sqlLogger = new DebugStack());
47

Sergei Morozov's avatar
Sergei Morozov committed
48
        $cache = new ArrayCache();
49
        $config->setResultCacheImpl($cache);
50 51
    }

52 53
    protected function tearDown()
    {
Sergei Morozov's avatar
Sergei Morozov committed
54
        $this->connection->getSchemaManager()->dropTable('caching');
55 56 57 58

        parent::tearDown();
    }

59 60
    public function testCacheFetchAssoc()
    {
61 62 63 64
        self::assertCacheNonCacheSelectSameFetchModeAreEqual(
            $this->expectedResult,
            FetchMode::ASSOCIATIVE
        );
65 66 67 68
    }

    public function testFetchNum()
    {
Sergei Morozov's avatar
Sergei Morozov committed
69
        $expectedResult = [];
jeroendedauw's avatar
jeroendedauw committed
70
        foreach ($this->expectedResult as $v) {
71 72
            $expectedResult[] = array_values($v);
        }
73 74

        self::assertCacheNonCacheSelectSameFetchModeAreEqual($expectedResult, FetchMode::NUMERIC);
75 76 77 78
    }

    public function testFetchBoth()
    {
Sergei Morozov's avatar
Sergei Morozov committed
79
        $expectedResult = [];
jeroendedauw's avatar
jeroendedauw committed
80
        foreach ($this->expectedResult as $v) {
81 82
            $expectedResult[] = array_merge($v, array_values($v));
        }
83 84

        self::assertCacheNonCacheSelectSameFetchModeAreEqual($expectedResult, FetchMode::MIXED);
85
    }
86

87 88
    public function testFetchColumn()
    {
Sergei Morozov's avatar
Sergei Morozov committed
89
        $expectedResult = [];
jeroendedauw's avatar
jeroendedauw committed
90
        foreach ($this->expectedResult as $v) {
91 92
            $expectedResult[] = array_shift($v);
        }
93 94

        self::assertCacheNonCacheSelectSameFetchModeAreEqual($expectedResult, FetchMode::COLUMN);
95
    }
96 97 98

    public function testMixingFetch()
    {
Sergei Morozov's avatar
Sergei Morozov committed
99
        $numExpectedResult = [];
jeroendedauw's avatar
jeroendedauw committed
100
        foreach ($this->expectedResult as $v) {
101 102
            $numExpectedResult[] = array_values($v);
        }
Sergei Morozov's avatar
Sergei Morozov committed
103
        $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey'));
104

105
        $data = $this->hydrateStmt($stmt, FetchMode::ASSOCIATIVE);
106

107
        self::assertEquals($this->expectedResult, $data);
108

Sergei Morozov's avatar
Sergei Morozov committed
109
        $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey'));
110

111
        $data = $this->hydrateStmt($stmt, FetchMode::NUMERIC);
112

113
        self::assertEquals($numExpectedResult, $data);
114 115
    }

116 117
    public function testIteratorFetch()
    {
118 119 120
        self::assertStandardAndIteratorFetchAreEqual(FetchMode::MIXED);
        self::assertStandardAndIteratorFetchAreEqual(FetchMode::ASSOCIATIVE);
        self::assertStandardAndIteratorFetchAreEqual(FetchMode::NUMERIC);
121 122
    }

123
    public function assertStandardAndIteratorFetchAreEqual($fetchMode)
124
    {
Sergei Morozov's avatar
Sergei Morozov committed
125
        $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey'));
126
        $data = $this->hydrateStmt($stmt, $fetchMode);
127

Sergei Morozov's avatar
Sergei Morozov committed
128
        $stmt          = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey'));
129
        $data_iterator = $this->hydrateStmtIterator($stmt, $fetchMode);
130

131
        self::assertEquals($data, $data_iterator);
132 133
    }

134 135
    public function testDontCloseNoCache()
    {
Sergei Morozov's avatar
Sergei Morozov committed
136
        $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey'));
137

Sergei Morozov's avatar
Sergei Morozov committed
138
        $data = [];
139 140

        while ($row = $stmt->fetch(FetchMode::ASSOCIATIVE)) {
141 142 143
            $data[] = $row;
        }

Sergei Morozov's avatar
Sergei Morozov committed
144
        $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey'));
145

Sergei Morozov's avatar
Sergei Morozov committed
146
        $data = [];
147 148

        while ($row = $stmt->fetch(FetchMode::NUMERIC)) {
149 150 151
            $data[] = $row;
        }

Gabriel Caruso's avatar
Gabriel Caruso committed
152
        self::assertCount(2, $this->sqlLogger->queries);
153 154 155 156
    }

    public function testDontFinishNoCache()
    {
Sergei Morozov's avatar
Sergei Morozov committed
157
        $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey'));
158

159
        $stmt->fetch(FetchMode::ASSOCIATIVE);
160 161
        $stmt->closeCursor();

Sergei Morozov's avatar
Sergei Morozov committed
162
        $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey'));
163

164
        $this->hydrateStmt($stmt, FetchMode::NUMERIC);
165

Gabriel Caruso's avatar
Gabriel Caruso committed
166
        self::assertCount(2, $this->sqlLogger->queries);
167 168
    }

169
    public function assertCacheNonCacheSelectSameFetchModeAreEqual($expectedResult, $fetchMode)
170
    {
Sergei Morozov's avatar
Sergei Morozov committed
171
        $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey'));
172

173
        self::assertEquals(2, $stmt->columnCount());
174
        $data = $this->hydrateStmt($stmt, $fetchMode);
175
        self::assertEquals($expectedResult, $data);
176

Sergei Morozov's avatar
Sergei Morozov committed
177
        $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey'));
178

179
        self::assertEquals(2, $stmt->columnCount());
180
        $data = $this->hydrateStmt($stmt, $fetchMode);
181
        self::assertEquals($expectedResult, $data);
Sergei Morozov's avatar
Sergei Morozov committed
182
        self::assertCount(1, $this->sqlLogger->queries, 'just one dbal hit');
183 184 185 186
    }

    public function testEmptyResultCache()
    {
Sergei Morozov's avatar
Sergei Morozov committed
187
        $stmt = $this->connection->executeQuery('SELECT * FROM caching WHERE test_int > 500', [], [], new QueryCacheProfile(10, 'emptycachekey'));
188 189
        $data = $this->hydrateStmt($stmt);

Sergei Morozov's avatar
Sergei Morozov committed
190
        $stmt = $this->connection->executeQuery('SELECT * FROM caching WHERE test_int > 500', [], [], new QueryCacheProfile(10, 'emptycachekey'));
191 192
        $data = $this->hydrateStmt($stmt);

Sergei Morozov's avatar
Sergei Morozov committed
193
        self::assertCount(1, $this->sqlLogger->queries, 'just one dbal hit');
194
    }
195

196 197
    public function testChangeCacheImpl()
    {
Sergei Morozov's avatar
Sergei Morozov committed
198
        $stmt = $this->connection->executeQuery('SELECT * FROM caching WHERE test_int > 500', [], [], new QueryCacheProfile(10, 'emptycachekey'));
199 200
        $data = $this->hydrateStmt($stmt);

Sergei Morozov's avatar
Sergei Morozov committed
201
        $secondCache = new ArrayCache();
Sergei Morozov's avatar
Sergei Morozov committed
202
        $stmt        = $this->connection->executeQuery('SELECT * FROM caching WHERE test_int > 500', [], [], new QueryCacheProfile(10, 'emptycachekey', $secondCache));
Sergei Morozov's avatar
Sergei Morozov committed
203
        $data        = $this->hydrateStmt($stmt);
204

Sergei Morozov's avatar
Sergei Morozov committed
205 206
        self::assertCount(2, $this->sqlLogger->queries, 'two hits');
        self::assertCount(1, $secondCache->fetch('emptycachekey'));
207 208
    }

209
    private function hydrateStmt($stmt, $fetchMode = FetchMode::ASSOCIATIVE)
210
    {
Sergei Morozov's avatar
Sergei Morozov committed
211
        $data = [];
212
        while ($row = $stmt->fetch($fetchMode)) {
213
            $data[] = is_array($row) ? array_change_key_case($row, CASE_LOWER) : $row;
214 215
        }
        $stmt->closeCursor();
216
        return $data;
217
    }
218

219
    private function hydrateStmtIterator($stmt, $fetchMode = FetchMode::ASSOCIATIVE)
220
    {
Sergei Morozov's avatar
Sergei Morozov committed
221
        $data = [];
222
        $stmt->setFetchMode($fetchMode);
223
        foreach ($stmt as $row) {
224
            $data[] = is_array($row) ? array_change_key_case($row, CASE_LOWER) : $row;
225 226 227 228
        }
        $stmt->closeCursor();
        return $data;
    }
229
}