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

namespace Doctrine\Tests\DBAL\Functional;
4

5
use Doctrine\DBAL\Cache\QueryCacheProfile;
6
use Doctrine\DBAL\FetchMode;
Gabriel Caruso's avatar
Gabriel Caruso committed
7
use Doctrine\DBAL\Logging\DebugStack;
8 9 10 11 12 13
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;
14 15 16 17 18 19

/**
 * @group DDC-217
 */
class ResultCacheTest extends \Doctrine\Tests\DbalFunctionalTestCase
{
Gabriel Caruso's avatar
Gabriel Caruso committed
20
    /**
21
     * @var int[][]|string[][]
Gabriel Caruso's avatar
Gabriel Caruso committed
22
     */
23
    private $expectedResult = array(array('test_int' => 100, 'test_string' => 'foo'), array('test_int' => 200, 'test_string' => 'bar'), array('test_int' => 300, 'test_string' => 'baz'));
Gabriel Caruso's avatar
Gabriel Caruso committed
24 25

    /**
Gabriel Caruso's avatar
Gabriel Caruso committed
26
     * @var DebugStack
Gabriel Caruso's avatar
Gabriel Caruso committed
27
     */
28 29
    private $sqlLogger;

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

34 35 36 37
        $table = new \Doctrine\DBAL\Schema\Table("caching");
        $table->addColumn('test_int', 'integer');
        $table->addColumn('test_string', 'string', array('notnull' => false));
        $table->setPrimaryKey(array('test_int'));
38

39 40
        $sm = $this->_conn->getSchemaManager();
        $sm->createTable($table);
41

jeroendedauw's avatar
jeroendedauw committed
42
        foreach ($this->expectedResult as $row) {
43 44 45 46
            $this->_conn->insert('caching', $row);
        }

        $config = $this->_conn->getConfiguration();
Gabriel Caruso's avatar
Gabriel Caruso committed
47
        $config->setSQLLogger($this->sqlLogger = new DebugStack);
48 49 50

        $cache = new \Doctrine\Common\Cache\ArrayCache;
        $config->setResultCacheImpl($cache);
51 52
    }

53 54 55 56 57 58 59
    protected function tearDown()
    {
        $this->_conn->getSchemaManager()->dropTable('caching');

        parent::tearDown();
    }

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

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

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

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

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

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

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

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

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

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

110
        $stmt = $this->_conn->executeQuery("SELECT * FROM caching ORDER BY test_int ASC", array(), array(), new QueryCacheProfile(10, "testcachekey"));
111

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

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

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

124
    public function assertStandardAndIteratorFetchAreEqual($fetchMode)
125
    {
126
        $stmt = $this->_conn->executeQuery("SELECT * FROM caching ORDER BY test_int ASC", array(), array(), new QueryCacheProfile(10, "testcachekey"));
127
        $data = $this->hydrateStmt($stmt, $fetchMode);
128

129
        $stmt = $this->_conn->executeQuery("SELECT * FROM caching ORDER BY test_int ASC", array(), array(), new QueryCacheProfile(10, "testcachekey"));
130
        $data_iterator = $this->hydrateStmtIterator($stmt, $fetchMode);
131

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

135 136
    public function testDontCloseNoCache()
    {
137
        $stmt = $this->_conn->executeQuery("SELECT * FROM caching ORDER BY test_int ASC", array(), array(), new QueryCacheProfile(10, "testcachekey"));
138 139

        $data = array();
140 141

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

145
        $stmt = $this->_conn->executeQuery("SELECT * FROM caching ORDER BY test_int ASC", array(), array(), new QueryCacheProfile(10, "testcachekey"));
146 147

        $data = array();
148 149

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

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

    public function testDontFinishNoCache()
    {
158
        $stmt = $this->_conn->executeQuery("SELECT * FROM caching ORDER BY test_int ASC", array(), array(), new QueryCacheProfile(10, "testcachekey"));
159

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

163
        $stmt = $this->_conn->executeQuery("SELECT * FROM caching ORDER BY test_int ASC", array(), array(), new QueryCacheProfile(10, "testcachekey"));
164

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

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

170
    public function assertCacheNonCacheSelectSameFetchModeAreEqual($expectedResult, $fetchMode)
171
    {
172
        $stmt = $this->_conn->executeQuery("SELECT * FROM caching ORDER BY test_int ASC", array(), array(), new QueryCacheProfile(10, "testcachekey"));
173

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

178
        $stmt = $this->_conn->executeQuery("SELECT * FROM caching ORDER BY test_int ASC", array(), array(), new QueryCacheProfile(10, "testcachekey"));
179

180
        self::assertEquals(2, $stmt->columnCount());
181
        $data = $this->hydrateStmt($stmt, $fetchMode);
182
        self::assertEquals($expectedResult, $data);
Gabriel Caruso's avatar
Gabriel Caruso committed
183
        self::assertCount(1, $this->sqlLogger->queries, "just one dbal hit");
184 185 186 187 188 189 190 191 192 193
    }

    public function testEmptyResultCache()
    {
        $stmt = $this->_conn->executeQuery("SELECT * FROM caching WHERE test_int > 500", array(), array(), new QueryCacheProfile(10, "emptycachekey"));
        $data = $this->hydrateStmt($stmt);

        $stmt = $this->_conn->executeQuery("SELECT * FROM caching WHERE test_int > 500", array(), array(), new QueryCacheProfile(10, "emptycachekey"));
        $data = $this->hydrateStmt($stmt);

Gabriel Caruso's avatar
Gabriel Caruso committed
194
        self::assertCount(1, $this->sqlLogger->queries, "just one dbal hit");
195
    }
196

197 198 199 200 201 202 203 204 205
    public function testChangeCacheImpl()
    {
        $stmt = $this->_conn->executeQuery("SELECT * FROM caching WHERE test_int > 500", array(), array(), new QueryCacheProfile(10, "emptycachekey"));
        $data = $this->hydrateStmt($stmt);

        $secondCache = new \Doctrine\Common\Cache\ArrayCache;
        $stmt = $this->_conn->executeQuery("SELECT * FROM caching WHERE test_int > 500", array(), array(), new QueryCacheProfile(10, "emptycachekey", $secondCache));
        $data = $this->hydrateStmt($stmt);

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

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

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