Skip to content

Commit

Permalink
feature #48059 [HttpFoundation] Create migration for session table wh…
Browse files Browse the repository at this point in the history
…en pdo handler is used (alli83)

This PR was squashed before being merged into the 6.3 branch.

Discussion
----------

[HttpFoundation] Create migration for session table when pdo handler is used

| Q             | A
| ------------- | ---
| Branch?       | 6.3
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Tickets       |
| License       | MIT
| Doc PR        |

The purpose of this PR is to automatically generate the session table with the make migration command in addition to https://symfony.com/doc/current/session/database.html#preparing-the-database-to-store-sessions

Even though  `WellKnownSchemaFilterPass`  is deprecated, atm the session table is blacklisted by the `WellKnownSchemaFilterPass`, that's why I need to set the SchemaAssetFilter to null.

todo:

- [ ] doctrineBundle => doctrine/DoctrineBundle#1569
- [x] Add mention to changelog
- [ ] update documentation

Commits
-------

aebdc58 [HttpFoundation] Create migration for session table when pdo handler is used
  • Loading branch information
nicolas-grekas committed Dec 16, 2022
2 parents 68725da + aebdc58 commit 8e5e268
Show file tree
Hide file tree
Showing 17 changed files with 265 additions and 70 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Bridge\Doctrine\SchemaListener;

use Doctrine\Common\EventSubscriber;
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Exception\TableNotFoundException;
use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;
use Doctrine\ORM\Tools\ToolEvents;

abstract class AbstractSchemaSubscriber implements EventSubscriber
{
abstract public function postGenerateSchema(GenerateSchemaEventArgs $event): void;

public function getSubscribedEvents(): array
{
if (!class_exists(ToolEvents::class)) {
return [];
}

return [
ToolEvents::postGenerateSchema,
];
}

protected function getIsSameDatabaseChecker(Connection $connection): \Closure
{
return static function (\Closure $exec) use ($connection): bool {
$checkTable = 'schema_subscriber_check_'.bin2hex(random_bytes(7));
$connection->executeStatement(sprintf('CREATE TABLE %s (id INTEGER NOT NULL)', $checkTable));

try {
$exec(sprintf('DROP TABLE %s', $checkTable));
} catch (\Exception) {
// ignore
}

try {
$connection->executeStatement(sprintf('DROP TABLE %s', $checkTable));

return false;
} catch (TableNotFoundException) {
return true;
}
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@

namespace Symfony\Bridge\Doctrine\SchemaListener;

use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;
use Doctrine\ORM\Tools\ToolEvents;
use Symfony\Component\Cache\Adapter\DoctrineDbalAdapter;

/**
Expand All @@ -22,7 +20,7 @@
*
* @author Ryan Weaver <ryan@symfonycasts.com>
*/
final class DoctrineDbalCacheAdapterSchemaSubscriber implements EventSubscriber
final class DoctrineDbalCacheAdapterSchemaSubscriber extends AbstractSchemaSubscriber
{
private $dbalAdapters;

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

public function postGenerateSchema(GenerateSchemaEventArgs $event): void
{
$dbalConnection = $event->getEntityManager()->getConnection();
foreach ($this->dbalAdapters as $dbalAdapter) {
$dbalAdapter->configureSchema($event->getSchema(), $dbalConnection);
}
}
$connection = $event->getEntityManager()->getConnection();

public function getSubscribedEvents(): array
{
if (!class_exists(ToolEvents::class)) {
return [];
foreach ($this->dbalAdapters as $dbalAdapter) {
$dbalAdapter->configureSchema($event->getSchema(), $connection, $this->getIsSameDatabaseChecker($connection));
}

return [
ToolEvents::postGenerateSchema,
];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,9 @@

namespace Symfony\Bridge\Doctrine\SchemaListener;

use Doctrine\Common\EventSubscriber;
use Doctrine\DBAL\Event\SchemaCreateTableEventArgs;
use Doctrine\DBAL\Events;
use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;
use Doctrine\ORM\Tools\ToolEvents;
use Symfony\Component\Messenger\Bridge\Doctrine\Transport\DoctrineTransport;
use Symfony\Component\Messenger\Transport\TransportInterface;

Expand All @@ -24,7 +22,7 @@
*
* @author Ryan Weaver <ryan@symfonycasts.com>
*/
final class MessengerTransportDoctrineSchemaSubscriber implements EventSubscriber
final class MessengerTransportDoctrineSchemaSubscriber extends AbstractSchemaSubscriber
{
private const PROCESSING_TABLE_FLAG = self::class.':processing';

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

public function postGenerateSchema(GenerateSchemaEventArgs $event): void
{
$dbalConnection = $event->getEntityManager()->getConnection();
$connection = $event->getEntityManager()->getConnection();

foreach ($this->transports as $transport) {
if (!$transport instanceof DoctrineTransport) {
continue;
}

$transport->configureSchema($event->getSchema(), $dbalConnection);
$transport->configureSchema($event->getSchema(), $connection, $this->getIsSameDatabaseChecker($connection));
}
}

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

public function getSubscribedEvents(): array
{
$subscribedEvents = [];

if (class_exists(ToolEvents::class)) {
$subscribedEvents[] = ToolEvents::postGenerateSchema;
}
$subscribedEvents = parent::getSubscribedEvents();

if (class_exists(Events::class)) {
$subscribedEvents[] = Events::onSchemaCreateTable;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Bridge\Doctrine\SchemaListener;

use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler;

final class PdoSessionHandlerSchemaSubscriber extends AbstractSchemaSubscriber
{
private iterable $pdoSessionHandlers;

/**
* @param iterable<mixed, PdoSessionHandler> $pdoSessionHandlers
*/
public function __construct(iterable $pdoSessionHandlers)
{
$this->pdoSessionHandlers = $pdoSessionHandlers;
}

public function postGenerateSchema(GenerateSchemaEventArgs $event): void
{
$connection = $event->getEntityManager()->getConnection();

foreach ($this->pdoSessionHandlers as $pdoSessionHandler) {
$pdoSessionHandler->configureSchema($event->getSchema(), $this->getIsSameDatabaseChecker($connection));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@

namespace Symfony\Bridge\Doctrine\SchemaListener;

use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;
use Doctrine\ORM\Tools\ToolEvents;
use Symfony\Bridge\Doctrine\Security\RememberMe\DoctrineTokenProvider;
use Symfony\Component\Security\Http\RememberMe\PersistentRememberMeHandler;
use Symfony\Component\Security\Http\RememberMe\RememberMeHandlerInterface;
Expand All @@ -23,7 +21,7 @@
*
* @author Wouter de Jong <wouter@wouterj.nl>
*/
final class RememberMeTokenProviderDoctrineSchemaSubscriber implements EventSubscriber
final class RememberMeTokenProviderDoctrineSchemaSubscriber extends AbstractSchemaSubscriber
{
private iterable $rememberMeHandlers;

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

public function postGenerateSchema(GenerateSchemaEventArgs $event): void
{
$dbalConnection = $event->getEntityManager()->getConnection();
$connection = $event->getEntityManager()->getConnection();

foreach ($this->rememberMeHandlers as $rememberMeHandler) {
if (
$rememberMeHandler instanceof PersistentRememberMeHandler
&& ($tokenProvider = $rememberMeHandler->getTokenProvider()) instanceof DoctrineTokenProvider
) {
$tokenProvider->configureSchema($event->getSchema(), $dbalConnection);
$tokenProvider->configureSchema($event->getSchema(), $connection, $this->getIsSameDatabaseChecker($connection));
}
}
}

public function getSubscribedEvents(): array
{
if (!class_exists(ToolEvents::class)) {
return [];
}

return [
ToolEvents::postGenerateSchema,
];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -188,15 +188,18 @@ public function updateExistingToken(PersistentTokenInterface $token, #[\Sensitiv

/**
* Adds the Table to the Schema if "remember me" uses this Connection.
*
* @param \Closure $isSameDatabase
*/
public function configureSchema(Schema $schema, Connection $forConnection): void
public function configureSchema(Schema $schema, Connection $forConnection/* , \Closure $isSameDatabase */): void
{
// only update the schema for this connection
if ($forConnection !== $this->conn) {
if ($schema->hasTable('rememberme_token')) {
return;
}

if ($schema->hasTable('rememberme_token')) {
$isSameDatabase = 2 < \func_num_args() ? func_get_arg(2) : static fn () => false;

if ($forConnection !== $this->conn && !$isSameDatabase($this->conn->executeStatement(...))) {
return;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Bridge\Doctrine\Tests\SchemaListener;

use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Doctrine\SchemaListener\PdoSessionHandlerSchemaSubscriber;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler;

class PdoSessionHandlerSchemaSubscriberTest extends TestCase
{
public function testPostGenerateSchemaPdo()
{
$schema = new Schema();
$dbalConnection = $this->createMock(Connection::class);
$entityManager = $this->createMock(EntityManagerInterface::class);
$entityManager->expects($this->once())
->method('getConnection')
->willReturn($dbalConnection);
$event = new GenerateSchemaEventArgs($entityManager, $schema);

$pdoSessionHandler = $this->createMock(PdoSessionHandler::class);
$pdoSessionHandler->expects($this->once())
->method('configureSchema')
->with($schema, fn() => true);

$subscriber = new PdoSessionHandlerSchemaSubscriber([$pdoSessionHandler]);
$subscriber->postGenerateSchema($event);
}
}
1 change: 1 addition & 0 deletions src/Symfony/Bridge/Doctrine/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
"symfony/cache": "<5.4",
"symfony/dependency-injection": "<6.2",
"symfony/form": "<5.4",
"symfony/http-foundation": "<6.3",
"symfony/http-kernel": "<6.2",
"symfony/messenger": "<5.4",
"symfony/property-info": "<5.4",
Expand Down
12 changes: 8 additions & 4 deletions src/Symfony/Component/Cache/Adapter/DoctrineDbalAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,14 +98,18 @@ public function createTable(): void
}
}

public function configureSchema(Schema $schema, Connection $forConnection): void
/**
* @param \Closure $isSameDatabase
*/
public function configureSchema(Schema $schema, Connection $forConnection/* , \Closure $isSameDatabase */): void
{
// only update the schema for this connection
if ($forConnection !== $this->conn) {
if ($schema->hasTable($this->table)) {
return;
}

if ($schema->hasTable($this->table)) {
$isSameDatabase = 2 < \func_num_args() ? func_get_arg(2) : static fn () => false;

if ($forConnection !== $this->conn && !$isSameDatabase($this->conn->executeStatement(...))) {
return;
}

Expand Down
5 changes: 5 additions & 0 deletions src/Symfony/Component/HttpFoundation/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
CHANGELOG
=========

6.3
---

* Create migration for session table when pdo handler is used

6.2
---

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,8 @@
*/
class MigratingSessionHandler implements \SessionHandlerInterface, \SessionUpdateTimestampHandlerInterface
{
/**
* @var \SessionHandlerInterface&\SessionUpdateTimestampHandlerInterface
*/
private \SessionHandlerInterface $currentHandler;

/**
* @var \SessionHandlerInterface&\SessionUpdateTimestampHandlerInterface
*/
private \SessionHandlerInterface $writeOnlyHandler;
private \SessionHandlerInterface&\SessionUpdateTimestampHandlerInterface $currentHandler;
private \SessionHandlerInterface&\SessionUpdateTimestampHandlerInterface $writeOnlyHandler;

public function __construct(\SessionHandlerInterface $currentHandler, \SessionHandlerInterface $writeOnlyHandler)
{
Expand Down

0 comments on commit 8e5e268

Please sign in to comment.