Skip to content

Commit

Permalink
[Http-Foundation][Session]feat: create automatically session table wi…
Browse files Browse the repository at this point in the history
…th pdo connection
  • Loading branch information
alli83 committed Oct 31, 2022
1 parent 929d5f4 commit 734cf60
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?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\Exception;
use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;
use Doctrine\ORM\Tools\ToolEvents;
use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler;

class PdoSessionHandlerSchemaSubscriber implements EventSubscriber
{
private PdoSessionHandler $pdoSessionHandler;

public function __construct(PdoSessionHandler $pdoSessionHandler)
{
$this->pdoSessionHandler = $pdoSessionHandler;
}

/**
* @throws Exception
*/
public function postGenerateSchema(GenerateSchemaEventArgs $event): void
{
$dbalConnection = $event->getEntityManager()->getConnection();
$this->pdoSessionHandler->configureSchema($event->getSchema(), $dbalConnection);
}

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

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

return $subscribedEvents;
}
}
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, $dbalConnection);

$subscriber = new PdoSessionHandlerSchemaSubscriber($pdoSessionHandler);
$subscriber->postGenerateSchema($event);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@

namespace Symfony\Component\HttpFoundation\Session\Storage\Handler;

use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Exception;
use Doctrine\DBAL\Schema\AbstractSchemaManager;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\DBAL\Schema\SchemaException;
use Doctrine\DBAL\Types\Types;

/**
* Session handler using a PDO connection to read and write data.
*
Expand Down Expand Up @@ -175,6 +182,88 @@ public function __construct(\PDO|string $pdoOrDsn = null, array $options = [])
$this->ttl = $options['ttl'] ?? null;
}

/**
* @throws Exception
*/
private function isInListTablesWithoutFilter(AbstractSchemaManager $schemaManager): bool
{
$tablesName = $schemaManager->listTableNames();

if (\in_array($this->table, $tablesName)) {
return true;
}

return false;
}

/**
* @throws Exception
*/
public function configureSchema(Schema $schema, Connection $connection): void
{
$configuration = $connection->getConfiguration();

$schemaManager = method_exists(Connection::class, 'createSchemaManager')
? $connection->createSchemaManager()
: $connection->getSchemaManager();

$configuration->setSchemaAssetsFilter(null);
$isTableFound = $this->isInListTablesWithoutFilter($schemaManager);

if ($isTableFound) {
return;
}

$this->addTableToSchema($schema);
}

/**
* @throws SchemaException
*/
private function addTableToSchema(Schema $schema)
{
$this->getConnection();

$table = $schema->createTable($this->table);
switch ($this->driver) {
case 'mysql':
$table->addColumn($this->idCol, Types::BINARY)->setLength(128)->setNotnull(true);
$table->addColumn($this->dataCol, Types::BLOB)->setNotnull(true);
$table->addColumn($this->lifetimeCol, Types::INTEGER)->setUnsigned(true)->setNotnull(true);
$table->addColumn($this->timeCol, Types::INTEGER)->setUnsigned(true)->setNotnull(true);
$table->addOption('collate', 'utf8mb4_bin');
$table->addOption('engine', 'InnoDB');
break;
case 'sqlite':
$table->addColumn($this->idCol, Types::TEXT)->setNotnull(true);
$table->addColumn($this->dataCol, Types::BLOB)->setNotnull(true);
$table->addColumn($this->lifetimeCol, Types::INTEGER)->setNotnull(true);
$table->addColumn($this->timeCol, Types::INTEGER)->setNotnull(true);
break;
case 'pgsql':
$table->addColumn($this->idCol, Types::STRING)->setLength(128)->setNotnull(true);
$table->addColumn($this->dataCol, Types::BINARY)->setNotnull(true);
$table->addColumn($this->lifetimeCol, Types::INTEGER)->setNotnull(true);
$table->addColumn($this->timeCol, Types::INTEGER)->setNotnull(true);
break;
case 'oci':
$table->addColumn($this->idCol, Types::STRING)->setLength(128)->setNotnull(true);
$table->addColumn($this->dataCol, Types::BLOB)->setNotnull(true);
$table->addColumn($this->lifetimeCol, Types::INTEGER)->setNotnull(true);
$table->addColumn($this->timeCol, Types::INTEGER)->setNotnull(true);
break;
case 'sqlsrv':
$table->addColumn($this->idCol, Types::TEXT)->setLength(128)->setNotnull(true);
$table->addColumn($this->dataCol, Types::BLOB)->setNotnull(true);
$table->addColumn($this->lifetimeCol, Types::INTEGER)->setUnsigned(true)->setNotnull(true);
$table->addColumn($this->timeCol, Types::INTEGER)->setUnsigned(true)->setNotnull(true);
break;
default:
throw new \DomainException(sprintf('Creating the session table is currently not implemented for PDO driver "%s".', $this->driver));
}
$table->setPrimaryKey([$this->idCol]);
}

/**
* Creates the table to store sessions which can be called once for setup.
*
Expand Down Expand Up @@ -441,8 +530,8 @@ private function buildDsnFromUrl(string $dsnOrUrl): string
return $dsn;
}
}
// If "unix_socket" is not in the query, we continue with the same process as pgsql
// no break
// If "unix_socket" is not in the query, we continue with the same process as pgsql
// no break
case 'pgsql':
$dsn ??= 'pgsql:';

Expand Down

0 comments on commit 734cf60

Please sign in to comment.