Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit aebdc58

Browse files
alli83nicolas-grekas
authored andcommitted
[HttpFoundation] Create migration for session table when pdo handler is used
1 parent 233b9eb commit aebdc58

17 files changed

+265
-70
lines changed
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bridge\Doctrine\SchemaListener;
13+
14+
use Doctrine\Common\EventSubscriber;
15+
use Doctrine\DBAL\Connection;
16+
use Doctrine\DBAL\Exception\TableNotFoundException;
17+
use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;
18+
use Doctrine\ORM\Tools\ToolEvents;
19+
20+
abstract class AbstractSchemaSubscriber implements EventSubscriber
21+
{
22+
abstract public function postGenerateSchema(GenerateSchemaEventArgs $event): void;
23+
24+
public function getSubscribedEvents(): array
25+
{
26+
if (!class_exists(ToolEvents::class)) {
27+
return [];
28+
}
29+
30+
return [
31+
ToolEvents::postGenerateSchema,
32+
];
33+
}
34+
35+
protected function getIsSameDatabaseChecker(Connection $connection): \Closure
36+
{
37+
return static function (\Closure $exec) use ($connection): bool {
38+
$checkTable = 'schema_subscriber_check_'.bin2hex(random_bytes(7));
39+
$connection->executeStatement(sprintf('CREATE TABLE %s (id INTEGER NOT NULL)', $checkTable));
40+
41+
try {
42+
$exec(sprintf('DROP TABLE %s', $checkTable));
43+
} catch (\Exception) {
44+
// ignore
45+
}
46+
47+
try {
48+
$connection->executeStatement(sprintf('DROP TABLE %s', $checkTable));
49+
50+
return false;
51+
} catch (TableNotFoundException) {
52+
return true;
53+
}
54+
};
55+
}
56+
}

src/Symfony/Bridge/Doctrine/SchemaListener/DoctrineDbalCacheAdapterSchemaSubscriber.php

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@
1111

1212
namespace Symfony\Bridge\Doctrine\SchemaListener;
1313

14-
use Doctrine\Common\EventSubscriber;
1514
use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;
16-
use Doctrine\ORM\Tools\ToolEvents;
1715
use Symfony\Component\Cache\Adapter\DoctrineDbalAdapter;
1816

1917
/**
@@ -22,7 +20,7 @@
2220
*
2321
* @author Ryan Weaver <[email protected]>
2422
*/
25-
final class DoctrineDbalCacheAdapterSchemaSubscriber implements EventSubscriber
23+
final class DoctrineDbalCacheAdapterSchemaSubscriber extends AbstractSchemaSubscriber
2624
{
2725
private $dbalAdapters;
2826

@@ -36,20 +34,10 @@ public function __construct(iterable $dbalAdapters)
3634

3735
public function postGenerateSchema(GenerateSchemaEventArgs $event): void
3836
{
39-
$dbalConnection = $event->getEntityManager()->getConnection();
40-
foreach ($this->dbalAdapters as $dbalAdapter) {
41-
$dbalAdapter->configureSchema($event->getSchema(), $dbalConnection);
42-
}
43-
}
37+
$connection = $event->getEntityManager()->getConnection();
4438

45-
public function getSubscribedEvents(): array
46-
{
47-
if (!class_exists(ToolEvents::class)) {
48-
return [];
39+
foreach ($this->dbalAdapters as $dbalAdapter) {
40+
$dbalAdapter->configureSchema($event->getSchema(), $connection, $this->getIsSameDatabaseChecker($connection));
4941
}
50-
51-
return [
52-
ToolEvents::postGenerateSchema,
53-
];
5442
}
5543
}

src/Symfony/Bridge/Doctrine/SchemaListener/MessengerTransportDoctrineSchemaSubscriber.php

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,9 @@
1111

1212
namespace Symfony\Bridge\Doctrine\SchemaListener;
1313

14-
use Doctrine\Common\EventSubscriber;
1514
use Doctrine\DBAL\Event\SchemaCreateTableEventArgs;
1615
use Doctrine\DBAL\Events;
1716
use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;
18-
use Doctrine\ORM\Tools\ToolEvents;
1917
use Symfony\Component\Messenger\Bridge\Doctrine\Transport\DoctrineTransport;
2018
use Symfony\Component\Messenger\Transport\TransportInterface;
2119

@@ -24,7 +22,7 @@
2422
*
2523
* @author Ryan Weaver <[email protected]>
2624
*/
27-
final class MessengerTransportDoctrineSchemaSubscriber implements EventSubscriber
25+
final class MessengerTransportDoctrineSchemaSubscriber extends AbstractSchemaSubscriber
2826
{
2927
private const PROCESSING_TABLE_FLAG = self::class.':processing';
3028

@@ -40,13 +38,14 @@ public function __construct(iterable $transports)
4038

4139
public function postGenerateSchema(GenerateSchemaEventArgs $event): void
4240
{
43-
$dbalConnection = $event->getEntityManager()->getConnection();
41+
$connection = $event->getEntityManager()->getConnection();
42+
4443
foreach ($this->transports as $transport) {
4544
if (!$transport instanceof DoctrineTransport) {
4645
continue;
4746
}
4847

49-
$transport->configureSchema($event->getSchema(), $dbalConnection);
48+
$transport->configureSchema($event->getSchema(), $connection, $this->getIsSameDatabaseChecker($connection));
5049
}
5150
}
5251

@@ -89,11 +88,7 @@ public function onSchemaCreateTable(SchemaCreateTableEventArgs $event): void
8988

9089
public function getSubscribedEvents(): array
9190
{
92-
$subscribedEvents = [];
93-
94-
if (class_exists(ToolEvents::class)) {
95-
$subscribedEvents[] = ToolEvents::postGenerateSchema;
96-
}
91+
$subscribedEvents = parent::getSubscribedEvents();
9792

9893
if (class_exists(Events::class)) {
9994
$subscribedEvents[] = Events::onSchemaCreateTable;
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bridge\Doctrine\SchemaListener;
13+
14+
use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;
15+
use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler;
16+
17+
final class PdoSessionHandlerSchemaSubscriber extends AbstractSchemaSubscriber
18+
{
19+
private iterable $pdoSessionHandlers;
20+
21+
/**
22+
* @param iterable<mixed, PdoSessionHandler> $pdoSessionHandlers
23+
*/
24+
public function __construct(iterable $pdoSessionHandlers)
25+
{
26+
$this->pdoSessionHandlers = $pdoSessionHandlers;
27+
}
28+
29+
public function postGenerateSchema(GenerateSchemaEventArgs $event): void
30+
{
31+
$connection = $event->getEntityManager()->getConnection();
32+
33+
foreach ($this->pdoSessionHandlers as $pdoSessionHandler) {
34+
$pdoSessionHandler->configureSchema($event->getSchema(), $this->getIsSameDatabaseChecker($connection));
35+
}
36+
}
37+
}

src/Symfony/Bridge/Doctrine/SchemaListener/RememberMeTokenProviderDoctrineSchemaSubscriber.php

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@
1111

1212
namespace Symfony\Bridge\Doctrine\SchemaListener;
1313

14-
use Doctrine\Common\EventSubscriber;
1514
use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;
16-
use Doctrine\ORM\Tools\ToolEvents;
1715
use Symfony\Bridge\Doctrine\Security\RememberMe\DoctrineTokenProvider;
1816
use Symfony\Component\Security\Http\RememberMe\PersistentRememberMeHandler;
1917
use Symfony\Component\Security\Http\RememberMe\RememberMeHandlerInterface;
@@ -23,7 +21,7 @@
2321
*
2422
* @author Wouter de Jong <[email protected]>
2523
*/
26-
final class RememberMeTokenProviderDoctrineSchemaSubscriber implements EventSubscriber
24+
final class RememberMeTokenProviderDoctrineSchemaSubscriber extends AbstractSchemaSubscriber
2725
{
2826
private iterable $rememberMeHandlers;
2927

@@ -37,26 +35,15 @@ public function __construct(iterable $rememberMeHandlers)
3735

3836
public function postGenerateSchema(GenerateSchemaEventArgs $event): void
3937
{
40-
$dbalConnection = $event->getEntityManager()->getConnection();
38+
$connection = $event->getEntityManager()->getConnection();
4139

4240
foreach ($this->rememberMeHandlers as $rememberMeHandler) {
4341
if (
4442
$rememberMeHandler instanceof PersistentRememberMeHandler
4543
&& ($tokenProvider = $rememberMeHandler->getTokenProvider()) instanceof DoctrineTokenProvider
4644
) {
47-
$tokenProvider->configureSchema($event->getSchema(), $dbalConnection);
45+
$tokenProvider->configureSchema($event->getSchema(), $connection, $this->getIsSameDatabaseChecker($connection));
4846
}
4947
}
5048
}
51-
52-
public function getSubscribedEvents(): array
53-
{
54-
if (!class_exists(ToolEvents::class)) {
55-
return [];
56-
}
57-
58-
return [
59-
ToolEvents::postGenerateSchema,
60-
];
61-
}
6249
}

src/Symfony/Bridge/Doctrine/Security/RememberMe/DoctrineTokenProvider.php

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -188,15 +188,18 @@ public function updateExistingToken(PersistentTokenInterface $token, #[\Sensitiv
188188

189189
/**
190190
* Adds the Table to the Schema if "remember me" uses this Connection.
191+
*
192+
* @param \Closure $isSameDatabase
191193
*/
192-
public function configureSchema(Schema $schema, Connection $forConnection): void
194+
public function configureSchema(Schema $schema, Connection $forConnection/* , \Closure $isSameDatabase */): void
193195
{
194-
// only update the schema for this connection
195-
if ($forConnection !== $this->conn) {
196+
if ($schema->hasTable('rememberme_token')) {
196197
return;
197198
}
198199

199-
if ($schema->hasTable('rememberme_token')) {
200+
$isSameDatabase = 2 < \func_num_args() ? func_get_arg(2) : static fn () => false;
201+
202+
if ($forConnection !== $this->conn && !$isSameDatabase($this->conn->executeStatement(...))) {
200203
return;
201204
}
202205

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Bridge\Doctrine\Tests\SchemaListener;
13+
14+
use Doctrine\DBAL\Connection;
15+
use Doctrine\DBAL\Schema\Schema;
16+
use Doctrine\ORM\EntityManagerInterface;
17+
use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;
18+
use PHPUnit\Framework\TestCase;
19+
use Symfony\Bridge\Doctrine\SchemaListener\PdoSessionHandlerSchemaSubscriber;
20+
use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler;
21+
22+
class PdoSessionHandlerSchemaSubscriberTest extends TestCase
23+
{
24+
public function testPostGenerateSchemaPdo()
25+
{
26+
$schema = new Schema();
27+
$dbalConnection = $this->createMock(Connection::class);
28+
$entityManager = $this->createMock(EntityManagerInterface::class);
29+
$entityManager->expects($this->once())
30+
->method('getConnection')
31+
->willReturn($dbalConnection);
32+
$event = new GenerateSchemaEventArgs($entityManager, $schema);
33+
34+
$pdoSessionHandler = $this->createMock(PdoSessionHandler::class);
35+
$pdoSessionHandler->expects($this->once())
36+
->method('configureSchema')
37+
->with($schema, fn() => true);
38+
39+
$subscriber = new PdoSessionHandlerSchemaSubscriber([$pdoSessionHandler]);
40+
$subscriber->postGenerateSchema($event);
41+
}
42+
}

src/Symfony/Bridge/Doctrine/composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
"symfony/cache": "<5.4",
5757
"symfony/dependency-injection": "<6.2",
5858
"symfony/form": "<5.4",
59+
"symfony/http-foundation": "<6.3",
5960
"symfony/http-kernel": "<6.2",
6061
"symfony/messenger": "<5.4",
6162
"symfony/property-info": "<5.4",

src/Symfony/Component/Cache/Adapter/DoctrineDbalAdapter.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,14 +98,18 @@ public function createTable(): void
9898
}
9999
}
100100

101-
public function configureSchema(Schema $schema, Connection $forConnection): void
101+
/**
102+
* @param \Closure $isSameDatabase
103+
*/
104+
public function configureSchema(Schema $schema, Connection $forConnection/* , \Closure $isSameDatabase */): void
102105
{
103-
// only update the schema for this connection
104-
if ($forConnection !== $this->conn) {
106+
if ($schema->hasTable($this->table)) {
105107
return;
106108
}
107109

108-
if ($schema->hasTable($this->table)) {
110+
$isSameDatabase = 2 < \func_num_args() ? func_get_arg(2) : static fn () => false;
111+
112+
if ($forConnection !== $this->conn && !$isSameDatabase($this->conn->executeStatement(...))) {
109113
return;
110114
}
111115

src/Symfony/Component/HttpFoundation/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
6.3
5+
---
6+
7+
* Create migration for session table when pdo handler is used
8+
49
6.2
510
---
611

src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MigratingSessionHandler.php

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,8 @@
2222
*/
2323
class MigratingSessionHandler implements \SessionHandlerInterface, \SessionUpdateTimestampHandlerInterface
2424
{
25-
/**
26-
* @var \SessionHandlerInterface&\SessionUpdateTimestampHandlerInterface
27-
*/
28-
private \SessionHandlerInterface $currentHandler;
29-
30-
/**
31-
* @var \SessionHandlerInterface&\SessionUpdateTimestampHandlerInterface
32-
*/
33-
private \SessionHandlerInterface $writeOnlyHandler;
25+
private \SessionHandlerInterface&\SessionUpdateTimestampHandlerInterface $currentHandler;
26+
private \SessionHandlerInterface&\SessionUpdateTimestampHandlerInterface $writeOnlyHandler;
3427

3528
public function __construct(\SessionHandlerInterface $currentHandler, \SessionHandlerInterface $writeOnlyHandler)
3629
{

0 commit comments

Comments
 (0)