Skip to content

Commit fda0e97

Browse files
committed
Merge branch '5.4' into 6.0
* 5.4: Don't rely on session service in tests [Mime] Fix encoding filenames in multipart/form-data Properly warn about deprecation of IS_AUTHENTICATED_ANONYMOUSLY [Lock] Create tables in transaction only if supported by driver [Validator] Improve French translation [HttpFoundation] Take php session.cookie settings into account [Translations] Add missing translations for Galician (gl) [ErrorHandler] fix on patching return types on Windows [DependencyInjection] fix linting callable classes alias `cache.app.taggable` to `cache.app` if using `cache.adapter.redis_tag_aware` restore the overriden locale on tearDown - avoid interfering with any configured value [Serializer] Improve UidNormalizer denormalize error message [DependencyInjection] Cast tag value to string
2 parents cf013d4 + 323dd01 commit fda0e97

File tree

2 files changed

+161
-2
lines changed

2 files changed

+161
-2
lines changed

Store/DoctrineDbalStore.php

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,21 @@ public function save(Key $key)
9090
ParameterType::STRING,
9191
]);
9292
} catch (TableNotFoundException $e) {
93-
$this->createTable();
94-
$this->save($key);
93+
if (!$this->conn->isTransactionActive() || $this->platformSupportsTableCreationInTransaction()) {
94+
$this->createTable();
95+
}
96+
97+
try {
98+
$this->conn->executeStatement($sql, [
99+
$this->getHashedKey($key),
100+
$this->getUniqueToken($key),
101+
], [
102+
ParameterType::STRING,
103+
ParameterType::STRING,
104+
]);
105+
} catch (DBALException $e) {
106+
$this->putOffExpiration($key, $this->initialTtl);
107+
}
95108
} catch (DBALException $e) {
96109
// the lock is already acquired. It could be us. Let's try to put off.
97110
$this->putOffExpiration($key, $this->initialTtl);
@@ -233,4 +246,23 @@ private function getCurrentTimestampStatement(): string
233246
return (string) time();
234247
}
235248
}
249+
250+
/**
251+
* Checks wether current platform supports table creation within transaction.
252+
*/
253+
private function platformSupportsTableCreationInTransaction(): bool
254+
{
255+
$platform = $this->conn->getDatabasePlatform();
256+
257+
switch (true) {
258+
case $platform instanceof \Doctrine\DBAL\Platforms\PostgreSQLPlatform:
259+
case $platform instanceof \Doctrine\DBAL\Platforms\PostgreSQL94Platform:
260+
case $platform instanceof \Doctrine\DBAL\Platforms\SqlitePlatform:
261+
case $platform instanceof \Doctrine\DBAL\Platforms\SQLServerPlatform:
262+
case $platform instanceof \Doctrine\DBAL\Platforms\SQLServer2012Platform:
263+
return true;
264+
default:
265+
return false;
266+
}
267+
}
236268
}

Tests/Store/DoctrineDbalStoreTest.php

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,16 @@
1111

1212
namespace Symfony\Component\Lock\Tests\Store;
1313

14+
use Doctrine\DBAL\Connection;
1415
use Doctrine\DBAL\DriverManager;
16+
use Doctrine\DBAL\Exception\TableNotFoundException;
17+
use Doctrine\DBAL\Platforms\AbstractPlatform;
1518
use Symfony\Component\Lock\Key;
1619
use Symfony\Component\Lock\PersistingStoreInterface;
1720
use Symfony\Component\Lock\Store\DoctrineDbalStore;
1821

22+
class_exists(\Doctrine\DBAL\Platforms\PostgreSqlPlatform::class);
23+
1924
/**
2025
* @author Jérémy Derussé <jeremy@derusse.com>
2126
*
@@ -87,4 +92,126 @@ public function provideDsn()
8792
yield ['sqlite3:///'.$dbFile.'3', $dbFile.'3'];
8893
yield ['sqlite://localhost/:memory:'];
8994
}
95+
96+
/**
97+
* @dataProvider providePlatforms
98+
*/
99+
public function testCreatesTableInTransaction(string $platform)
100+
{
101+
$conn = $this->createMock(Connection::class);
102+
$conn->expects($this->exactly(3))
103+
->method('executeStatement')
104+
->withConsecutive(
105+
[$this->stringContains('INSERT INTO')],
106+
[$this->matches('create sql stmt')],
107+
[$this->stringContains('INSERT INTO')]
108+
)
109+
->will(
110+
$this->onConsecutiveCalls(
111+
$this->throwException(
112+
$this->createMock(TableNotFoundException::class)
113+
),
114+
1,
115+
1
116+
)
117+
);
118+
119+
$conn->method('isTransactionActive')
120+
->willReturn(true);
121+
122+
$platform = $this->createMock($platform);
123+
$platform->method('getCreateTableSQL')
124+
->willReturn(['create sql stmt']);
125+
126+
$conn->method('getDatabasePlatform')
127+
->willReturn($platform);
128+
129+
$store = new DoctrineDbalStore($conn);
130+
131+
$key = new Key(uniqid(__METHOD__, true));
132+
133+
$store->save($key);
134+
}
135+
136+
public function providePlatforms()
137+
{
138+
yield [\Doctrine\DBAL\Platforms\PostgreSQLPlatform::class];
139+
yield [\Doctrine\DBAL\Platforms\PostgreSQL94Platform::class];
140+
yield [\Doctrine\DBAL\Platforms\SqlitePlatform::class];
141+
yield [\Doctrine\DBAL\Platforms\SQLServerPlatform::class];
142+
yield [\Doctrine\DBAL\Platforms\SQLServer2012Platform::class];
143+
}
144+
145+
public function testTableCreationInTransactionNotSupported()
146+
{
147+
$conn = $this->createMock(Connection::class);
148+
$conn->expects($this->exactly(2))
149+
->method('executeStatement')
150+
->withConsecutive(
151+
[$this->stringContains('INSERT INTO')],
152+
[$this->stringContains('INSERT INTO')]
153+
)
154+
->will(
155+
$this->onConsecutiveCalls(
156+
$this->throwException(
157+
$this->createMock(TableNotFoundException::class)
158+
),
159+
1,
160+
1
161+
)
162+
);
163+
164+
$conn->method('isTransactionActive')
165+
->willReturn(true);
166+
167+
$platform = $this->createMock(AbstractPlatform::class);
168+
$platform->method('getCreateTableSQL')
169+
->willReturn(['create sql stmt']);
170+
171+
$conn->expects($this->exactly(2))
172+
->method('getDatabasePlatform');
173+
174+
$store = new DoctrineDbalStore($conn);
175+
176+
$key = new Key(uniqid(__METHOD__, true));
177+
178+
$store->save($key);
179+
}
180+
181+
public function testCreatesTableOutsideTransaction()
182+
{
183+
$conn = $this->createMock(Connection::class);
184+
$conn->expects($this->exactly(3))
185+
->method('executeStatement')
186+
->withConsecutive(
187+
[$this->stringContains('INSERT INTO')],
188+
[$this->matches('create sql stmt')],
189+
[$this->stringContains('INSERT INTO')]
190+
)
191+
->will(
192+
$this->onConsecutiveCalls(
193+
$this->throwException(
194+
$this->createMock(TableNotFoundException::class)
195+
),
196+
1,
197+
1
198+
)
199+
);
200+
201+
$conn->method('isTransactionActive')
202+
->willReturn(false);
203+
204+
$platform = $this->createMock(AbstractPlatform::class);
205+
$platform->method('getCreateTableSQL')
206+
->willReturn(['create sql stmt']);
207+
208+
$conn->method('getDatabasePlatform')
209+
->willReturn($platform);
210+
211+
$store = new DoctrineDbalStore($conn);
212+
213+
$key = new Key(uniqid(__METHOD__, true));
214+
215+
$store->save($key);
216+
}
90217
}

0 commit comments

Comments
 (0)