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

Skip to content

Commit ee96111

Browse files
committed
[Http-Foundation][Session]feat: create automatically session table with pdo connection
1 parent 929d5f4 commit ee96111

File tree

6 files changed

+222
-4
lines changed

6 files changed

+222
-4
lines changed
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
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\ORM\Tools\Event\GenerateSchemaEventArgs;
16+
use Doctrine\ORM\Tools\ToolEvents;
17+
use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler;
18+
use Symfony\Component\HttpFoundation\Session\Storage\Handler\SessionHandlerDecoratorInterface;
19+
20+
class PdoSessionHandlerSchemaSubscriber implements EventSubscriber
21+
{
22+
private $sessionHandler;
23+
24+
/**
25+
* @param $sessionHandler
26+
*/
27+
public function __construct($sessionHandler = null)
28+
{
29+
$this->sessionHandler = $sessionHandler;
30+
}
31+
32+
public function postGenerateSchema(GenerateSchemaEventArgs $event): void
33+
{
34+
$dbalConnection = $event->getEntityManager()->getConnection();
35+
36+
$sessionHandler = $this->sessionHandler;
37+
38+
if (!$sessionHandler instanceof PdoSessionHandler &&
39+
!$sessionHandler instanceof SessionHandlerDecoratorInterface) {
40+
return;
41+
}
42+
43+
if ($sessionHandler instanceof SessionHandlerDecoratorInterface) {
44+
$handlers = $sessionHandler->getHandlers();
45+
46+
foreach ($handlers as $handler) {
47+
if ($handler instanceof PdoSessionHandler) {
48+
$handler->configureSchema($event->getSchema(), $dbalConnection);
49+
}
50+
}
51+
52+
return;
53+
}
54+
55+
$this->sessionHandler->configureSchema($event->getSchema(), $dbalConnection);
56+
}
57+
58+
public function getSubscribedEvents(): array
59+
{
60+
$subscribedEvents = [];
61+
62+
if (class_exists(ToolEvents::class)) {
63+
$subscribedEvents[] = ToolEvents::postGenerateSchema;
64+
}
65+
66+
return $subscribedEvents;
67+
}
68+
}
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, $dbalConnection);
38+
39+
$subscriber = new PdoSessionHandlerSchemaSubscriber($pdoSessionHandler);
40+
$subscriber->postGenerateSchema($event);
41+
}
42+
}

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
/**
1717
* @author Ahmed TAILOULOUTE <[email protected]>
1818
*/
19-
class MarshallingSessionHandler implements \SessionHandlerInterface, \SessionUpdateTimestampHandlerInterface
19+
class MarshallingSessionHandler implements \SessionHandlerInterface, \SessionUpdateTimestampHandlerInterface, SessionHandlerDecoratorInterface
2020
{
2121
private AbstractSessionHandler $handler;
2222
private MarshallerInterface $marshaller;
@@ -73,4 +73,9 @@ public function updateTimestamp(string $sessionId, string $data): bool
7373
{
7474
return $this->handler->updateTimestamp($sessionId, $data);
7575
}
76+
77+
public function getHandlers(): array
78+
{
79+
return [$this->handler];
80+
}
7681
}

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
* @author Ross Motley <[email protected]>
2121
* @author Oliver Radwell <[email protected]>
2222
*/
23-
class MigratingSessionHandler implements \SessionHandlerInterface, \SessionUpdateTimestampHandlerInterface
23+
class MigratingSessionHandler implements \SessionHandlerInterface, \SessionUpdateTimestampHandlerInterface, SessionHandlerDecoratorInterface
2424
{
2525
/**
2626
* @var \SessionHandlerInterface&\SessionUpdateTimestampHandlerInterface
@@ -104,4 +104,9 @@ public function updateTimestamp(string $sessionId, string $sessionData): bool
104104

105105
return $result;
106106
}
107+
108+
public function getHandlers(): array
109+
{
110+
return [$this->currentHandler, $this->writeOnlyHandler];
111+
}
107112
}

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

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@
1111

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

14+
use Doctrine\DBAL\Connection;
15+
use Doctrine\DBAL\Schema\AbstractSchemaManager;
16+
use Doctrine\DBAL\Schema\Schema;
17+
use Doctrine\DBAL\Types\Types;
18+
1419
/**
1520
* Session handler using a PDO connection to read and write data.
1621
*
@@ -175,6 +180,79 @@ public function __construct(\PDO|string $pdoOrDsn = null, array $options = [])
175180
$this->ttl = $options['ttl'] ?? null;
176181
}
177182

183+
private function isInListTablesWithoutFilter(AbstractSchemaManager $schemaManager): bool
184+
{
185+
$tablesName = $schemaManager->listTableNames();
186+
187+
if (\in_array($this->table, $tablesName)) {
188+
return true;
189+
}
190+
191+
return false;
192+
}
193+
194+
public function configureSchema(Schema $schema, Connection $connection): void
195+
{
196+
$configuration = $connection->getConfiguration();
197+
198+
$schemaManager = method_exists(Connection::class, 'createSchemaManager')
199+
? $connection->createSchemaManager()
200+
: $connection->getSchemaManager();
201+
202+
$configuration->setSchemaAssetsFilter(null);
203+
$isTableFound = $this->isInListTablesWithoutFilter($schemaManager);
204+
205+
if ($isTableFound) {
206+
return;
207+
}
208+
209+
$this->addTableToSchema($schema);
210+
}
211+
212+
private function addTableToSchema(Schema $schema)
213+
{
214+
$this->getConnection();
215+
216+
$table = $schema->createTable($this->table);
217+
switch ($this->driver) {
218+
case 'mysql':
219+
$table->addColumn($this->idCol, Types::BINARY)->setLength(128)->setNotnull(true);
220+
$table->addColumn($this->dataCol, Types::BLOB)->setNotnull(true);
221+
$table->addColumn($this->lifetimeCol, Types::INTEGER)->setUnsigned(true)->setNotnull(true);
222+
$table->addColumn($this->timeCol, Types::INTEGER)->setUnsigned(true)->setNotnull(true);
223+
$table->addOption('collate', 'utf8mb4_bin');
224+
$table->addOption('engine', 'InnoDB');
225+
break;
226+
case 'sqlite':
227+
$table->addColumn($this->idCol, Types::TEXT)->setNotnull(true);
228+
$table->addColumn($this->dataCol, Types::BLOB)->setNotnull(true);
229+
$table->addColumn($this->lifetimeCol, Types::INTEGER)->setNotnull(true);
230+
$table->addColumn($this->timeCol, Types::INTEGER)->setNotnull(true);
231+
break;
232+
case 'pgsql':
233+
$table->addColumn($this->idCol, Types::STRING)->setLength(128)->setNotnull(true);
234+
$table->addColumn($this->dataCol, Types::BINARY)->setNotnull(true);
235+
$table->addColumn($this->lifetimeCol, Types::INTEGER)->setNotnull(true);
236+
$table->addColumn($this->timeCol, Types::INTEGER)->setNotnull(true);
237+
break;
238+
case 'oci':
239+
$table->addColumn($this->idCol, Types::STRING)->setLength(128)->setNotnull(true);
240+
$table->addColumn($this->dataCol, Types::BLOB)->setNotnull(true);
241+
$table->addColumn($this->lifetimeCol, Types::INTEGER)->setNotnull(true);
242+
$table->addColumn($this->timeCol, Types::INTEGER)->setNotnull(true);
243+
break;
244+
case 'sqlsrv':
245+
$table->addColumn($this->idCol, Types::TEXT)->setLength(128)->setNotnull(true);
246+
$table->addColumn($this->dataCol, Types::BLOB)->setNotnull(true);
247+
$table->addColumn($this->lifetimeCol, Types::INTEGER)->setUnsigned(true)->setNotnull(true);
248+
$table->addColumn($this->timeCol, Types::INTEGER)->setUnsigned(true)->setNotnull(true);
249+
break;
250+
default:
251+
throw new \DomainException(sprintf('Creating the session table is currently not implemented for PDO driver "%s".', $this->driver));
252+
}
253+
$table->setPrimaryKey([$this->idCol]);
254+
}
255+
178256
/**
179257
* Creates the table to store sessions which can be called once for setup.
180258
*
@@ -441,8 +519,8 @@ private function buildDsnFromUrl(string $dsnOrUrl): string
441519
return $dsn;
442520
}
443521
}
444-
// If "unix_socket" is not in the query, we continue with the same process as pgsql
445-
// no break
522+
// If "unix_socket" is not in the query, we continue with the same process as pgsql
523+
// no break
446524
case 'pgsql':
447525
$dsn ??= 'pgsql:';
448526

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
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\Component\HttpFoundation\Session\Storage\Handler;
13+
14+
interface SessionHandlerDecoratorInterface
15+
{
16+
/**
17+
* @return \SessionHandlerInterface[]
18+
*/
19+
public function getHandlers(): array;
20+
}

0 commit comments

Comments
 (0)