Skip to content

Commit bf481f1

Browse files
committed
automatically updating Doctrine Schema from Messenger
1 parent c30d6f9 commit bf481f1

File tree

6 files changed

+183
-2
lines changed

6 files changed

+183
-2
lines changed

src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/ConnectionTest.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Doctrine\DBAL\Platforms\AbstractPlatform;
1717
use Doctrine\DBAL\Query\QueryBuilder;
1818
use Doctrine\DBAL\Schema\AbstractSchemaManager;
19+
use Doctrine\DBAL\Schema\Schema;
1920
use Doctrine\DBAL\Schema\SchemaConfig;
2021
use Doctrine\DBAL\Schema\Synchronizer\SchemaSynchronizer;
2122
use PHPUnit\Framework\TestCase;
@@ -343,4 +344,37 @@ public function testFindAll()
343344
$this->assertEquals('{"message":"Hi again"}', $doctrineEnvelopes[1]['body']);
344345
$this->assertEquals(['type' => DummyMessage::class], $doctrineEnvelopes[1]['headers']);
345346
}
347+
348+
public function testConfigureSchema()
349+
{
350+
$driverConnection = $this->getDBALConnectionMock();
351+
$schema = new Schema();
352+
353+
$connection = new Connection(['table_name' => 'queue_table'], $driverConnection);
354+
$connection->configureSchema($schema, $driverConnection);
355+
$this->assertTrue($schema->hasTable('queue_table'));
356+
}
357+
358+
public function testConfigureSchemaDifferentDbalConnection()
359+
{
360+
$driverConnection = $this->getDBALConnectionMock();
361+
$driverConnection2 = $this->getDBALConnectionMock();
362+
$schema = new Schema();
363+
364+
$connection = new Connection([], $driverConnection);
365+
$connection->configureSchema($schema, $driverConnection2);
366+
$this->assertFalse($schema->hasTable('messenger_messages'));
367+
}
368+
369+
public function testConfigureSchemaTableExists()
370+
{
371+
$driverConnection = $this->getDBALConnectionMock();
372+
$schema = new Schema();
373+
$schema->createTable('messenger_messages');
374+
375+
$connection = new Connection([], $driverConnection);
376+
$connection->configureSchema($schema, $driverConnection);
377+
$table = $schema->getTable('messenger_messages');
378+
$this->assertEmpty($table->getColumns(), 'The table was not overwritten');
379+
}
346380
}

src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/DoctrineTransportTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
namespace Symfony\Component\Messenger\Bridge\Doctrine\Tests\Transport;
1313

14+
use Doctrine\DBAL\Connection as DbalConnection;
15+
use Doctrine\DBAL\Schema\Schema;
1416
use PHPUnit\Framework\TestCase;
1517
use Symfony\Component\Messenger\Bridge\Doctrine\Tests\Fixtures\DummyMessage;
1618
use Symfony\Component\Messenger\Bridge\Doctrine\Transport\Connection;
@@ -50,6 +52,23 @@ public function testReceivesMessages()
5052
$this->assertSame($decodedMessage, $envelopes[0]->getMessage());
5153
}
5254

55+
public function testConfigureSchema()
56+
{
57+
$transport = $this->getTransport(
58+
null,
59+
$connection = $this->createMock(Connection::class)
60+
);
61+
62+
$schema = new Schema();
63+
$dbalConnection = $this->createMock(DbalConnection::class);
64+
65+
$connection->expects($this->once())
66+
->method('configureSchema')
67+
->with($schema, $dbalConnection);
68+
69+
$transport->configureSchema($schema, $dbalConnection);
70+
}
71+
5372
private function getTransport(SerializerInterface $serializer = null, Connection $connection = null): DoctrineTransport
5473
{
5574
$serializer = $serializer ?: $this->createMock(SerializerInterface::class);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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\Messenger\Bridge\Doctrine\Tests\Transport;
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\Component\Messenger\Bridge\Doctrine\Transport\DoctrineTransport;
20+
use Symfony\Component\Messenger\Bridge\Doctrine\Transport\MessengerTransportDoctrineSchemaSubscriber;
21+
use Symfony\Component\Messenger\Transport\TransportInterface;
22+
23+
class MessengerTransportDoctrineSchemaSubscriberTest extends TestCase
24+
{
25+
public function testPostGenerateSchema()
26+
{
27+
$schema = new Schema();
28+
$dbalConnection = $this->createMock(Connection::class);
29+
$entityManager = $this->createMock(EntityManagerInterface::class);
30+
$entityManager->expects($this->once())
31+
->method('getConnection')
32+
->willReturn($dbalConnection);
33+
$event = new GenerateSchemaEventArgs($entityManager, $schema);
34+
35+
$doctrineTransport = $this->createMock(DoctrineTransport::class);
36+
$doctrineTransport->expects($this->once())
37+
->method('configureSchema')
38+
->with($schema, $dbalConnection);
39+
$otherTransport = $this->createMock(TransportInterface::class);
40+
$otherTransport->expects($this->never())
41+
->method($this->anything());
42+
43+
$subscriber = new MessengerTransportDoctrineSchemaSubscriber([$doctrineTransport, $otherTransport]);
44+
$subscriber->postGenerateSchema($event);
45+
}
46+
}

src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/Connection.php

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Doctrine\DBAL\Schema\Schema;
2020
use Doctrine\DBAL\Schema\Synchronizer\SchemaSynchronizer;
2121
use Doctrine\DBAL\Schema\Synchronizer\SingleDatabaseSynchronizer;
22+
use Doctrine\DBAL\Schema\Table;
2223
use Doctrine\DBAL\Types\Type;
2324
use Doctrine\DBAL\Types\Types;
2425
use Symfony\Component\Messenger\Exception\InvalidArgumentException;
@@ -290,6 +291,20 @@ public function find($id): ?array
290291
return false === $data ? null : $this->decodeEnvelopeHeaders($data);
291292
}
292293

294+
public function configureSchema(Schema $schema, DBALConnection $dbalConnection): void
295+
{
296+
// only update the schema for this connection
297+
if ($dbalConnection !== $this->driverConnection) {
298+
return;
299+
}
300+
301+
if ($schema->hasTable($this->configuration['table_name'])) {
302+
return;
303+
}
304+
305+
$this->addTableToSchema($schema);
306+
}
307+
293308
private function createAvailableMessagesQueryBuilder(): QueryBuilder
294309
{
295310
$now = new \DateTime();
@@ -341,6 +356,13 @@ private function executeQuery(string $sql, array $parameters = [], array $types
341356
private function getSchema(): Schema
342357
{
343358
$schema = new Schema([], [], $this->driverConnection->getSchemaManager()->createSchemaConfig());
359+
$this->addTableToSchema($schema);
360+
361+
return $schema;
362+
}
363+
364+
private function addTableToSchema(Schema $schema): void
365+
{
344366
$table = $schema->createTable($this->configuration['table_name']);
345367
$table->addColumn('id', self::$useDeprecatedConstants ? Type::BIGINT : Types::BIGINT)
346368
->setAutoincrement(true)
@@ -361,8 +383,6 @@ private function getSchema(): Schema
361383
$table->addIndex(['queue_name']);
362384
$table->addIndex(['available_at']);
363385
$table->addIndex(['delivered_at']);
364-
365-
return $schema;
366386
}
367387

368388
private function decodeEnvelopeHeaders(array $doctrineEnvelope): array

src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/DoctrineTransport.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
namespace Symfony\Component\Messenger\Bridge\Doctrine\Transport;
1313

14+
use Doctrine\DBAL\Connection as DbalConnection;
15+
use Doctrine\DBAL\Schema\Schema;
1416
use Symfony\Component\Messenger\Envelope;
1517
use Symfony\Component\Messenger\Transport\Receiver\ListableReceiverInterface;
1618
use Symfony\Component\Messenger\Transport\Receiver\MessageCountAwareInterface;
@@ -98,6 +100,14 @@ public function setup(): void
98100
$this->connection->setup();
99101
}
100102

103+
/**
104+
* Adds the Table to the Schema if this transport uses this connection.
105+
*/
106+
public function configureSchema(Schema $schema, DbalConnection $dbalConnection): void
107+
{
108+
$this->connection->configureSchema($schema, $dbalConnection);
109+
}
110+
101111
private function getReceiver(): DoctrineReceiver
102112
{
103113
return $this->receiver = new DoctrineReceiver($this->connection, $this->serializer);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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\Messenger\Bridge\Doctrine\Transport;
13+
14+
use Doctrine\Common\EventSubscriber;
15+
use Doctrine\ORM\Tools\Event\GenerateSchemaEventArgs;
16+
use Doctrine\ORM\Tools\ToolEvents;
17+
use Symfony\Component\Messenger\Transport\TransportInterface;
18+
19+
/**
20+
* Automatically adds any required database tables to the Doctrine Schema
21+
*
22+
* @author Ryan Weaver <ryan@symfonycasts.com>
23+
*/
24+
final class MessengerTransportDoctrineSchemaSubscriber implements EventSubscriber
25+
{
26+
private $transports;
27+
28+
/**
29+
* @param iterable|TransportInterface[] $transports
30+
*/
31+
public function __construct(iterable $transports)
32+
{
33+
$this->transports = $transports;
34+
}
35+
36+
public function postGenerateSchema(GenerateSchemaEventArgs $event)
37+
{
38+
$dbalConnection = $event->getEntityManager()->getConnection();
39+
foreach ($this->transports as $transport) {
40+
if (!$transport instanceof DoctrineTransport) {
41+
continue;
42+
}
43+
44+
$transport->configureSchema($event->getSchema(), $dbalConnection);
45+
}
46+
}
47+
48+
public function getSubscribedEvents(): array
49+
{
50+
return [ToolEvents::postGenerateSchema];
51+
}
52+
}

0 commit comments

Comments
 (0)