Completed
Push — 2.9 ( e738a7...a2bfa4 )
by Sergei
85:25 queued 20:23
created

ResultCacheTest::testFetchNum()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 8
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 0
1
<?php
2
3
namespace Doctrine\Tests\DBAL\Functional;
4
5
use Doctrine\Common\Cache\ArrayCache;
6
use Doctrine\DBAL\Cache\QueryCacheProfile;
7
use Doctrine\DBAL\FetchMode;
8
use Doctrine\DBAL\Logging\DebugStack;
9
use Doctrine\DBAL\Schema\Table;
10
use Doctrine\Tests\DbalFunctionalTestCase;
11
use const CASE_LOWER;
12
use function array_change_key_case;
13
use function array_merge;
14
use function array_shift;
15
use function array_values;
16
use function is_array;
17
18
/**
19
 * @group DDC-217
20
 */
21
class ResultCacheTest extends DbalFunctionalTestCase
22
{
23
    /** @var int[][]|string[][] */
24
    private $expectedResult = [['test_int' => 100, 'test_string' => 'foo'], ['test_int' => 200, 'test_string' => 'bar'], ['test_int' => 300, 'test_string' => 'baz']];
25
26
    /** @var DebugStack */
27
    private $sqlLogger;
28
29
    protected function setUp()
30
    {
31
        parent::setUp();
32
33
        $table = new Table('caching');
34
        $table->addColumn('test_int', 'integer');
35
        $table->addColumn('test_string', 'string', ['notnull' => false]);
36
        $table->setPrimaryKey(['test_int']);
37
38
        $sm = $this->connection->getSchemaManager();
39
        $sm->createTable($table);
40
41
        foreach ($this->expectedResult as $row) {
42
            $this->connection->insert('caching', $row);
43
        }
44
45
        $config                                = $this->connection->getConfiguration();
46
        $config->setSQLLogger($this->sqlLogger = new DebugStack());
47
48
        $cache = new ArrayCache();
49
        $config->setResultCacheImpl($cache);
50
    }
51
52
    protected function tearDown()
53
    {
54
        $this->connection->getSchemaManager()->dropTable('caching');
55
56
        parent::tearDown();
57
    }
58
59
    public function testCacheFetchAssoc()
60
    {
61
        self::assertCacheNonCacheSelectSameFetchModeAreEqual(
0 ignored issues
show
Bug Best Practice introduced by
The method Doctrine\Tests\DBAL\Func...SameFetchModeAreEqual() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

61
        self::/** @scrutinizer ignore-call */ 
62
              assertCacheNonCacheSelectSameFetchModeAreEqual(
Loading history...
62
            $this->expectedResult,
63
            FetchMode::ASSOCIATIVE
64
        );
65
    }
66
67
    public function testFetchNum()
68
    {
69
        $expectedResult = [];
70
        foreach ($this->expectedResult as $v) {
71
            $expectedResult[] = array_values($v);
72
        }
73
74
        self::assertCacheNonCacheSelectSameFetchModeAreEqual($expectedResult, FetchMode::NUMERIC);
0 ignored issues
show
Bug Best Practice introduced by
The method Doctrine\Tests\DBAL\Func...SameFetchModeAreEqual() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

74
        self::/** @scrutinizer ignore-call */ 
75
              assertCacheNonCacheSelectSameFetchModeAreEqual($expectedResult, FetchMode::NUMERIC);
Loading history...
75
    }
76
77
    public function testFetchBoth()
78
    {
79
        $expectedResult = [];
80
        foreach ($this->expectedResult as $v) {
81
            $expectedResult[] = array_merge($v, array_values($v));
82
        }
83
84
        self::assertCacheNonCacheSelectSameFetchModeAreEqual($expectedResult, FetchMode::MIXED);
0 ignored issues
show
Bug Best Practice introduced by
The method Doctrine\Tests\DBAL\Func...SameFetchModeAreEqual() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

84
        self::/** @scrutinizer ignore-call */ 
85
              assertCacheNonCacheSelectSameFetchModeAreEqual($expectedResult, FetchMode::MIXED);
Loading history...
85
    }
86
87
    public function testFetchColumn()
88
    {
89
        $expectedResult = [];
90
        foreach ($this->expectedResult as $v) {
91
            $expectedResult[] = array_shift($v);
92
        }
93
94
        self::assertCacheNonCacheSelectSameFetchModeAreEqual($expectedResult, FetchMode::COLUMN);
0 ignored issues
show
Bug Best Practice introduced by
The method Doctrine\Tests\DBAL\Func...SameFetchModeAreEqual() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

94
        self::/** @scrutinizer ignore-call */ 
95
              assertCacheNonCacheSelectSameFetchModeAreEqual($expectedResult, FetchMode::COLUMN);
Loading history...
95
    }
96
97
    public function testMixingFetch()
98
    {
99
        $numExpectedResult = [];
100
        foreach ($this->expectedResult as $v) {
101
            $numExpectedResult[] = array_values($v);
102
        }
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
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
    public function testIteratorFetch()
117
    {
118
        self::assertStandardAndIteratorFetchAreEqual(FetchMode::MIXED);
0 ignored issues
show
Bug Best Practice introduced by
The method Doctrine\Tests\DBAL\Func...IteratorFetchAreEqual() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

118
        self::/** @scrutinizer ignore-call */ 
119
              assertStandardAndIteratorFetchAreEqual(FetchMode::MIXED);
Loading history...
119
        self::assertStandardAndIteratorFetchAreEqual(FetchMode::ASSOCIATIVE);
120
        self::assertStandardAndIteratorFetchAreEqual(FetchMode::NUMERIC);
121
    }
122
123
    public function assertStandardAndIteratorFetchAreEqual($fetchMode)
124
    {
125
        $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey'));
126
        $data = $this->hydrateStmt($stmt, $fetchMode);
127
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
    public function testDontCloseNoCache()
135
    {
136
        $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey'));
137
138
        $data = [];
139
140
        while ($row = $stmt->fetch(FetchMode::ASSOCIATIVE)) {
141
            $data[] = $row;
142
        }
143
144
        $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey'));
145
146
        $data = [];
147
148
        while ($row = $stmt->fetch(FetchMode::NUMERIC)) {
149
            $data[] = $row;
150
        }
151
152
        self::assertCount(2, $this->sqlLogger->queries);
153
    }
154
155
    public function testDontFinishNoCache()
156
    {
157
        $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey'));
158
159
        $stmt->fetch(FetchMode::ASSOCIATIVE);
160
        $stmt->closeCursor();
161
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
166
        self::assertCount(2, $this->sqlLogger->queries);
167
    }
168
169
    public function testFetchAllAndFinishSavesCache()
170
    {
171
        $layerCache = new ArrayCache();
172
        $stmt       = $this->connection->executeQuery('SELECT * FROM caching WHERE test_int > 500', [], [], new QueryCacheProfile(10, 'testcachekey', $layerCache));
173
        $stmt->fetchAll();
174
        $stmt->closeCursor();
175
176
        self::assertCount(1, $layerCache->fetch('testcachekey'));
0 ignored issues
show
Bug introduced by
It seems like $layerCache->fetch('testcachekey') can also be of type false; however, parameter $haystack of PHPUnit\Framework\Assert::assertCount() does only seem to accept Countable|iterable, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

176
        self::assertCount(1, /** @scrutinizer ignore-type */ $layerCache->fetch('testcachekey'));
Loading history...
177
    }
178
179
    public function testFetchAllColumn() : void
180
    {
181
        $query = $this->connection->getDatabasePlatform()
182
            ->getDummySelectSQL('1');
183
184
        $qcp = new QueryCacheProfile(0, 0, new ArrayCache());
185
186
        $stmt = $this->connection->executeCacheQuery($query, [], [], $qcp);
187
        $stmt->fetchAll(FetchMode::COLUMN);
188
        $stmt->closeCursor();
189
190
        $stmt = $this->connection->executeCacheQuery($query, [], [], $qcp);
191
192
        self::assertEquals([1], $stmt->fetchAll(FetchMode::COLUMN));
193
    }
194
195
    public function assertCacheNonCacheSelectSameFetchModeAreEqual($expectedResult, $fetchMode)
196
    {
197
        $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey'));
198
199
        self::assertEquals(2, $stmt->columnCount());
200
        $data = $this->hydrateStmt($stmt, $fetchMode);
201
        self::assertEquals($expectedResult, $data);
202
203
        $stmt = $this->connection->executeQuery('SELECT * FROM caching ORDER BY test_int ASC', [], [], new QueryCacheProfile(10, 'testcachekey'));
204
205
        self::assertEquals(2, $stmt->columnCount());
206
        $data = $this->hydrateStmt($stmt, $fetchMode);
207
        self::assertEquals($expectedResult, $data);
208
        self::assertCount(1, $this->sqlLogger->queries, 'just one dbal hit');
209
    }
210
211
    public function testEmptyResultCache()
212
    {
213
        $stmt = $this->connection->executeQuery('SELECT * FROM caching WHERE test_int > 500', [], [], new QueryCacheProfile(10, 'emptycachekey'));
214
        $data = $this->hydrateStmt($stmt);
0 ignored issues
show
Unused Code introduced by
The assignment to $data is dead and can be removed.
Loading history...
215
216
        $stmt = $this->connection->executeQuery('SELECT * FROM caching WHERE test_int > 500', [], [], new QueryCacheProfile(10, 'emptycachekey'));
217
        $data = $this->hydrateStmt($stmt);
218
219
        self::assertCount(1, $this->sqlLogger->queries, 'just one dbal hit');
220
    }
221
222
    public function testChangeCacheImpl()
223
    {
224
        $stmt = $this->connection->executeQuery('SELECT * FROM caching WHERE test_int > 500', [], [], new QueryCacheProfile(10, 'emptycachekey'));
225
        $data = $this->hydrateStmt($stmt);
0 ignored issues
show
Unused Code introduced by
The assignment to $data is dead and can be removed.
Loading history...
226
227
        $secondCache = new ArrayCache();
228
        $stmt        = $this->connection->executeQuery('SELECT * FROM caching WHERE test_int > 500', [], [], new QueryCacheProfile(10, 'emptycachekey', $secondCache));
229
        $data        = $this->hydrateStmt($stmt);
230
231
        self::assertCount(2, $this->sqlLogger->queries, 'two hits');
232
        self::assertCount(1, $secondCache->fetch('emptycachekey'));
0 ignored issues
show
Bug introduced by
It seems like $secondCache->fetch('emptycachekey') can also be of type false; however, parameter $haystack of PHPUnit\Framework\Assert::assertCount() does only seem to accept Countable|iterable, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

232
        self::assertCount(1, /** @scrutinizer ignore-type */ $secondCache->fetch('emptycachekey'));
Loading history...
233
    }
234
235
    private function hydrateStmt($stmt, $fetchMode = FetchMode::ASSOCIATIVE)
236
    {
237
        $data = [];
238
        while ($row = $stmt->fetch($fetchMode)) {
239
            $data[] = is_array($row) ? array_change_key_case($row, CASE_LOWER) : $row;
240
        }
241
        $stmt->closeCursor();
242
        return $data;
243
    }
244
245
    private function hydrateStmtIterator($stmt, $fetchMode = FetchMode::ASSOCIATIVE)
246
    {
247
        $data = [];
248
        $stmt->setFetchMode($fetchMode);
249
        foreach ($stmt as $row) {
250
            $data[] = is_array($row) ? array_change_key_case($row, CASE_LOWER) : $row;
251
        }
252
        $stmt->closeCursor();
253
        return $data;
254
    }
255
}
256