From 50c0fbc79b4e86d1a500b27d4d519f0ec3b33cae Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Fri, 13 Oct 2023 10:59:07 +0200 Subject: [PATCH] Fix DBAL 4 compatibility --- .../Doctrine/Form/DoctrineOrmTypeGuesser.php | 2 +- .../DoctrinePingConnectionMiddleware.php | 16 +- .../Doctrine/Middleware/Debug/Connection.php | 135 ++++---------- .../Middleware/Debug/DBAL3/Connection.php | 174 ++++++++++++++++++ .../Middleware/Debug/DBAL3/Statement.php | 86 +++++++++ .../Doctrine/Middleware/Debug/Driver.php | 16 +- .../Doctrine/Middleware/Debug/Query.php | 16 +- .../Doctrine/Middleware/Debug/Statement.php | 51 ++--- .../PropertyInfo/DoctrineExtractor.php | 10 +- ...octrineDataCollectorWithDebugStackTest.php | 7 + .../Tests/Fixtures/SingleIntIdEntity.php | 5 +- .../Tests/Fixtures/Type/StringWrapperType.php | 8 +- .../Doctrine/Tests/Logger/DbalLoggerTest.php | 8 + .../DoctrinePingConnectionMiddlewareTest.php | 40 ++-- .../Tests/Middleware/Debug/MiddlewareTest.php | 10 +- .../PropertyInfo/Fixtures/DoctrineFooType.php | 8 +- ...rTransportDoctrineSchemaSubscriberTest.php | 8 + .../Doctrine/Tests/Types/UlidTypeTest.php | 23 ++- .../Bridge/Doctrine/Types/AbstractUidType.php | 40 +++- 19 files changed, 466 insertions(+), 197 deletions(-) create mode 100644 src/Symfony/Bridge/Doctrine/Middleware/Debug/DBAL3/Connection.php create mode 100644 src/Symfony/Bridge/Doctrine/Middleware/Debug/DBAL3/Statement.php diff --git a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php index 231b50640f040..6386318ef97d9 100644 --- a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php +++ b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php @@ -52,7 +52,7 @@ public function guessType(string $class, string $property) } switch ($metadata->getTypeOfField($property)) { - case Types::ARRAY: + case 'array': // DBAL < 4 case Types::SIMPLE_ARRAY: return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\CollectionType', [], Guess::MEDIUM_CONFIDENCE); case Types::BOOLEAN: diff --git a/src/Symfony/Bridge/Doctrine/Messenger/DoctrinePingConnectionMiddleware.php b/src/Symfony/Bridge/Doctrine/Messenger/DoctrinePingConnectionMiddleware.php index de925284d09dc..5f8d9496348c8 100644 --- a/src/Symfony/Bridge/Doctrine/Messenger/DoctrinePingConnectionMiddleware.php +++ b/src/Symfony/Bridge/Doctrine/Messenger/DoctrinePingConnectionMiddleware.php @@ -11,6 +11,7 @@ namespace Symfony\Bridge\Doctrine\Messenger; +use Doctrine\DBAL\Connection; use Doctrine\DBAL\Exception as DBALException; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Messenger\Envelope; @@ -33,19 +34,28 @@ protected function handleForManager(EntityManagerInterface $entityManager, Envel return $stack->next()->handle($envelope, $stack); } - private function pingConnection(EntityManagerInterface $entityManager) + private function pingConnection(EntityManagerInterface $entityManager): void { $connection = $entityManager->getConnection(); try { - $connection->executeQuery($connection->getDatabasePlatform()->getDummySelectSQL()); + $this->executeDummySql($connection); } catch (DBALException $e) { $connection->close(); - $connection->connect(); + // Attempt to reestablish the lazy connection by sending another query. + $this->executeDummySql($connection); } if (!$entityManager->isOpen()) { $this->managerRegistry->resetManager($this->entityManagerName); } } + + /** + * @throws DBALException + */ + private function executeDummySql(Connection $connection): void + { + $connection->executeQuery($connection->getDatabasePlatform()->getDummySelectSQL()); + } } diff --git a/src/Symfony/Bridge/Doctrine/Middleware/Debug/Connection.php b/src/Symfony/Bridge/Doctrine/Middleware/Debug/Connection.php index e768407bdd137..a0d642dd7d250 100644 --- a/src/Symfony/Bridge/Doctrine/Middleware/Debug/Connection.php +++ b/src/Symfony/Bridge/Doctrine/Middleware/Debug/Connection.php @@ -14,31 +14,26 @@ use Doctrine\DBAL\Driver\Connection as ConnectionInterface; use Doctrine\DBAL\Driver\Middleware\AbstractConnectionMiddleware; use Doctrine\DBAL\Driver\Result; -use Doctrine\DBAL\Driver\Statement as DriverStatement; use Symfony\Component\Stopwatch\Stopwatch; /** * @author Laurent VOULLEMIER + * @author Alexander M. Turek * * @internal */ final class Connection extends AbstractConnectionMiddleware { - private $nestingLevel = 0; - private $debugDataHolder; - private $stopwatch; - private $connectionName; - - public function __construct(ConnectionInterface $connection, DebugDataHolder $debugDataHolder, ?Stopwatch $stopwatch, string $connectionName) - { + public function __construct( + ConnectionInterface $connection, + private DebugDataHolder $debugDataHolder, + private ?Stopwatch $stopwatch, + private string $connectionName, + ) { parent::__construct($connection); - - $this->debugDataHolder = $debugDataHolder; - $this->stopwatch = $stopwatch; - $this->connectionName = $connectionName; } - public function prepare(string $sql): DriverStatement + public function prepare(string $sql): Statement { return new Statement( parent::prepare($sql), @@ -53,135 +48,79 @@ public function query(string $sql): Result { $this->debugDataHolder->addQuery($this->connectionName, $query = new Query($sql)); - if (null !== $this->stopwatch) { - $this->stopwatch->start('doctrine', 'doctrine'); - } - + $this->stopwatch?->start('doctrine', 'doctrine'); $query->start(); try { - $result = parent::query($sql); + return parent::query($sql); } finally { $query->stop(); - - if (null !== $this->stopwatch) { - $this->stopwatch->stop('doctrine'); - } + $this->stopwatch?->stop('doctrine'); } - - return $result; } public function exec(string $sql): int { $this->debugDataHolder->addQuery($this->connectionName, $query = new Query($sql)); - if (null !== $this->stopwatch) { - $this->stopwatch->start('doctrine', 'doctrine'); - } - + $this->stopwatch?->start('doctrine', 'doctrine'); $query->start(); try { $affectedRows = parent::exec($sql); } finally { $query->stop(); - - if (null !== $this->stopwatch) { - $this->stopwatch->stop('doctrine'); - } + $this->stopwatch?->stop('doctrine'); } return $affectedRows; } - public function beginTransaction(): bool + public function beginTransaction(): void { - $query = null; - if (1 === ++$this->nestingLevel) { - $this->debugDataHolder->addQuery($this->connectionName, $query = new Query('"START TRANSACTION"')); - } - - if (null !== $this->stopwatch) { - $this->stopwatch->start('doctrine', 'doctrine'); - } + $query = new Query('"START TRANSACTION"'); + $this->debugDataHolder->addQuery($this->connectionName, $query); - if (null !== $query) { - $query->start(); - } + $this->stopwatch?->start('doctrine', 'doctrine'); + $query->start(); try { - $ret = parent::beginTransaction(); + parent::beginTransaction(); } finally { - if (null !== $query) { - $query->stop(); - } - - if (null !== $this->stopwatch) { - $this->stopwatch->stop('doctrine'); - } + $query->stop(); + $this->stopwatch?->stop('doctrine'); } - - return $ret; } - public function commit(): bool + public function commit(): void { - $query = null; - if (1 === $this->nestingLevel--) { - $this->debugDataHolder->addQuery($this->connectionName, $query = new Query('"COMMIT"')); - } + $query = new Query('"COMMIT"'); + $this->debugDataHolder->addQuery($this->connectionName, $query); - if (null !== $this->stopwatch) { - $this->stopwatch->start('doctrine', 'doctrine'); - } - - if (null !== $query) { - $query->start(); - } + $this->stopwatch?->start('doctrine', 'doctrine'); + $query->start(); try { - $ret = parent::commit(); + parent::commit(); } finally { - if (null !== $query) { - $query->stop(); - } - - if (null !== $this->stopwatch) { - $this->stopwatch->stop('doctrine'); - } + $query->stop(); + $this->stopwatch?->stop('doctrine'); } - - return $ret; } - public function rollBack(): bool + public function rollBack(): void { - $query = null; - if (1 === $this->nestingLevel--) { - $this->debugDataHolder->addQuery($this->connectionName, $query = new Query('"ROLLBACK"')); - } - - if (null !== $this->stopwatch) { - $this->stopwatch->start('doctrine', 'doctrine'); - } + $query = new Query('"ROLLBACK"'); + $this->debugDataHolder->addQuery($this->connectionName, $query); - if (null !== $query) { - $query->start(); - } + $this->stopwatch?->start('doctrine', 'doctrine'); + $query->start(); try { - $ret = parent::rollBack(); + parent::rollBack(); } finally { - if (null !== $query) { - $query->stop(); - } - - if (null !== $this->stopwatch) { - $this->stopwatch->stop('doctrine'); - } + $query->stop(); + $this->stopwatch?->stop('doctrine'); } - - return $ret; } } diff --git a/src/Symfony/Bridge/Doctrine/Middleware/Debug/DBAL3/Connection.php b/src/Symfony/Bridge/Doctrine/Middleware/Debug/DBAL3/Connection.php new file mode 100644 index 0000000000000..1bcb6c22e0c3d --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Middleware/Debug/DBAL3/Connection.php @@ -0,0 +1,174 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Doctrine\Middleware\Debug\DBAL3; + +use Doctrine\DBAL\Driver\Connection as ConnectionInterface; +use Doctrine\DBAL\Driver\Middleware\AbstractConnectionMiddleware; +use Doctrine\DBAL\Driver\Result; +use Doctrine\DBAL\Driver\Statement as StatementInterface; +use Symfony\Bridge\Doctrine\Middleware\Debug\DebugDataHolder; +use Symfony\Bridge\Doctrine\Middleware\Debug\Query; +use Symfony\Component\Stopwatch\Stopwatch; + +/** + * @author Laurent VOULLEMIER + * + * @internal + */ +final class Connection extends AbstractConnectionMiddleware +{ + /** @var int */ + private $nestingLevel = 0; + private $debugDataHolder; + private $stopwatch; + private $connectionName; + + public function __construct( + ConnectionInterface $connection, + DebugDataHolder $debugDataHolder, + ?Stopwatch $stopwatch, + string $connectionName + ) { + $this->connectionName = $connectionName; + $this->stopwatch = $stopwatch; + $this->debugDataHolder = $debugDataHolder; + + parent::__construct($connection); + } + + public function prepare(string $sql): StatementInterface + { + return new Statement( + parent::prepare($sql), + $this->debugDataHolder, + $this->connectionName, + $sql, + $this->stopwatch, + ); + } + + public function query(string $sql): Result + { + $this->debugDataHolder->addQuery($this->connectionName, $query = new Query($sql)); + + if ($this->stopwatch) { + $this->stopwatch->start('doctrine', 'doctrine'); + } + $query->start(); + + try { + return parent::query($sql); + } finally { + $query->stop(); + if ($this->stopwatch) { + $this->stopwatch->stop('doctrine'); + } + } + } + + public function exec(string $sql): int + { + $this->debugDataHolder->addQuery($this->connectionName, $query = new Query($sql)); + + if ($this->stopwatch) { + $this->stopwatch->start('doctrine', 'doctrine'); + } + $query->start(); + + try { + return parent::exec($sql); + } finally { + $query->stop(); + if ($this->stopwatch) { + $this->stopwatch->stop('doctrine'); + } + } + } + + public function beginTransaction(): bool + { + $query = null; + if (1 === ++$this->nestingLevel) { + $this->debugDataHolder->addQuery($this->connectionName, $query = new Query('"START TRANSACTION"')); + } + + if ($this->stopwatch) { + $this->stopwatch->start('doctrine', 'doctrine'); + } + if ($query) { + $query->start(); + } + + try { + return parent::beginTransaction(); + } finally { + if ($query) { + $query->stop(); + } + if ($this->stopwatch) { + $this->stopwatch->stop('doctrine'); + } + } + } + + public function commit(): bool + { + $query = null; + if (1 === $this->nestingLevel--) { + $this->debugDataHolder->addQuery($this->connectionName, $query = new Query('"COMMIT"')); + } + + if ($this->stopwatch) { + $this->stopwatch->start('doctrine', 'doctrine'); + } + if ($query) { + $query->start(); + } + + try { + return parent::commit(); + } finally { + if ($query) { + $query->stop(); + } + if ($this->stopwatch) { + $this->stopwatch->stop('doctrine'); + } + } + } + + public function rollBack(): bool + { + $query = null; + if (1 === $this->nestingLevel--) { + $this->debugDataHolder->addQuery($this->connectionName, $query = new Query('"ROLLBACK"')); + } + + if ($this->stopwatch) { + $this->stopwatch->start('doctrine', 'doctrine'); + } + if ($query) { + $query->start(); + } + + try { + return parent::rollBack(); + } finally { + if ($query) { + $query->stop(); + } + if ($this->stopwatch) { + $this->stopwatch->stop('doctrine'); + } + } + } +} diff --git a/src/Symfony/Bridge/Doctrine/Middleware/Debug/DBAL3/Statement.php b/src/Symfony/Bridge/Doctrine/Middleware/Debug/DBAL3/Statement.php new file mode 100644 index 0000000000000..16217c2f46a51 --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Middleware/Debug/DBAL3/Statement.php @@ -0,0 +1,86 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Doctrine\Middleware\Debug\DBAL3; + +use Doctrine\DBAL\Driver\Middleware\AbstractStatementMiddleware; +use Doctrine\DBAL\Driver\Result as ResultInterface; +use Doctrine\DBAL\Driver\Statement as StatementInterface; +use Doctrine\DBAL\ParameterType; +use Symfony\Bridge\Doctrine\Middleware\Debug\DebugDataHolder; +use Symfony\Bridge\Doctrine\Middleware\Debug\Query; +use Symfony\Component\Stopwatch\Stopwatch; + +/** + * @author Laurent VOULLEMIER + * + * @internal + */ +final class Statement extends AbstractStatementMiddleware +{ + private $query; + private $debugDataHolder; + private $connectionName; + private $stopwatch; + + public function __construct( + StatementInterface $statement, + DebugDataHolder $debugDataHolder, + string $connectionName, + string $sql, + Stopwatch $stopwatch = null + ) { + $this->stopwatch = $stopwatch; + $this->connectionName = $connectionName; + $this->debugDataHolder = $debugDataHolder; + $this->query = new Query($sql); + + parent::__construct($statement); + } + + public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null): bool + { + $this->query->setParam($param, $variable, $type); + + return parent::bindParam($param, $variable, $type, ...\array_slice(\func_get_args(), 3)); + } + + public function bindValue($param, $value, $type = ParameterType::STRING): bool + { + $this->query->setValue($param, $value, $type); + + return parent::bindValue($param, $value, $type); + } + + public function execute($params = null): ResultInterface + { + if (null !== $params) { + $this->query->setValues($params); + } + + // clone to prevent variables by reference to change + $this->debugDataHolder->addQuery($this->connectionName, $query = clone $this->query); + + if ($this->stopwatch) { + $this->stopwatch->start('doctrine', 'doctrine'); + } + $query->start(); + + try { + return parent::execute($params); + } finally { + $query->stop(); + if ($this->stopwatch) { + $this->stopwatch->stop('doctrine'); + } + } + } +} diff --git a/src/Symfony/Bridge/Doctrine/Middleware/Debug/Driver.php b/src/Symfony/Bridge/Doctrine/Middleware/Debug/Driver.php index 7f7fdd3bf0d8d..090b1643f6ad6 100644 --- a/src/Symfony/Bridge/Doctrine/Middleware/Debug/Driver.php +++ b/src/Symfony/Bridge/Doctrine/Middleware/Debug/Driver.php @@ -12,6 +12,7 @@ namespace Symfony\Bridge\Doctrine\Middleware\Debug; use Doctrine\DBAL\Driver as DriverInterface; +use Doctrine\DBAL\Driver\Connection as ConnectionInterface; use Doctrine\DBAL\Driver\Middleware\AbstractDriverMiddleware; use Symfony\Component\Stopwatch\Stopwatch; @@ -35,10 +36,21 @@ public function __construct(DriverInterface $driver, DebugDataHolder $debugDataH $this->connectionName = $connectionName; } - public function connect(array $params): Connection + public function connect(array $params): ConnectionInterface { + $connection = parent::connect($params); + + if ('void' !== (string) (new \ReflectionMethod(DriverInterface\Connection::class, 'commit'))->getReturnType()) { + return new DBAL3\Connection( + $connection, + $this->debugDataHolder, + $this->stopwatch, + $this->connectionName + ); + } + return new Connection( - parent::connect($params), + $connection, $this->debugDataHolder, $this->stopwatch, $this->connectionName diff --git a/src/Symfony/Bridge/Doctrine/Middleware/Debug/Query.php b/src/Symfony/Bridge/Doctrine/Middleware/Debug/Query.php index eb835caa41b25..6ab402e1b7779 100644 --- a/src/Symfony/Bridge/Doctrine/Middleware/Debug/Query.php +++ b/src/Symfony/Bridge/Doctrine/Middleware/Debug/Query.php @@ -46,10 +46,11 @@ public function stop(): void } /** - * @param string|int $param - * @param mixed $variable + * @param string|int $param + * @param mixed $variable + * @param int|ParameterType $type */ - public function setParam($param, &$variable, int $type): void + public function setParam($param, &$variable, $type): void { // Numeric indexes start at 0 in profiler $idx = \is_int($param) ? $param - 1 : $param; @@ -59,10 +60,11 @@ public function setParam($param, &$variable, int $type): void } /** - * @param string|int $param - * @param mixed $value + * @param string|int $param + * @param mixed $value + * @param int|ParameterType $type */ - public function setValue($param, $value, int $type): void + public function setValue($param, $value, $type): void { // Numeric indexes start at 0 in profiler $idx = \is_int($param) ? $param - 1 : $param; @@ -95,7 +97,7 @@ public function getParams(): array } /** - * @return array + * @return array */ public function getTypes(): array { diff --git a/src/Symfony/Bridge/Doctrine/Middleware/Debug/Statement.php b/src/Symfony/Bridge/Doctrine/Middleware/Debug/Statement.php index a40cdaa9695ba..3f4ba10fc2138 100644 --- a/src/Symfony/Bridge/Doctrine/Middleware/Debug/Statement.php +++ b/src/Symfony/Bridge/Doctrine/Middleware/Debug/Statement.php @@ -19,65 +19,46 @@ /** * @author Laurent VOULLEMIER + * @author Alexander M. Turek * * @internal */ final class Statement extends AbstractStatementMiddleware { - private $debugDataHolder; - private $connectionName; - private $query; - private $stopwatch; - - public function __construct(StatementInterface $statement, DebugDataHolder $debugDataHolder, string $connectionName, string $sql, Stopwatch $stopwatch = null) - { + private Query $query; + + public function __construct( + StatementInterface $statement, + private DebugDataHolder $debugDataHolder, + private string $connectionName, + string $sql, + private ?Stopwatch $stopwatch = null, + ) { parent::__construct($statement); - $this->debugDataHolder = $debugDataHolder; - $this->connectionName = $connectionName; $this->query = new Query($sql); - $this->stopwatch = $stopwatch; - } - - public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null): bool - { - $this->query->setParam($param, $variable, $type); - - return parent::bindParam($param, $variable, $type, ...\array_slice(\func_get_args(), 3)); } - public function bindValue($param, $value, $type = ParameterType::STRING): bool + public function bindValue(int|string $param, mixed $value, ParameterType $type): void { $this->query->setValue($param, $value, $type); - return parent::bindValue($param, $value, $type); + parent::bindValue($param, $value, $type); } - public function execute($params = null): ResultInterface + public function execute(): ResultInterface { - if (null !== $params) { - $this->query->setValues($params); - } - // clone to prevent variables by reference to change $this->debugDataHolder->addQuery($this->connectionName, $query = clone $this->query); - if ($this->stopwatch) { - $this->stopwatch->start('doctrine', 'doctrine'); - } - + $this->stopwatch?->start('doctrine', 'doctrine'); $query->start(); try { - $result = parent::execute($params); + return parent::execute(); } finally { $query->stop(); - - if ($this->stopwatch) { - $this->stopwatch->stop('doctrine'); - } + $this->stopwatch?->stop('doctrine'); } - - return $result; } } diff --git a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php index ccd53c1ebe7c6..f33a62cb6257c 100644 --- a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php +++ b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php @@ -167,8 +167,8 @@ public function getTypes(string $class, string $property, array $context = []) break; case Type::BUILTIN_TYPE_ARRAY: switch ($typeOfField) { - case Types::ARRAY: - case 'json_array': + case 'array': // DBAL < 4 + case 'json_array': // DBAL < 3 // return null if $enumType is set, because we can't determine if collectionKeyType is string or int if ($enumType) { return null; @@ -281,7 +281,7 @@ private function getPhpType(string $doctrineType): ?string case Types::BINARY: return Type::BUILTIN_TYPE_RESOURCE; - case Types::OBJECT: + case 'object': // DBAL < 4 case Types::DATE_MUTABLE: case Types::DATETIME_MUTABLE: case Types::DATETIMETZ_MUTABLE: @@ -294,9 +294,9 @@ private function getPhpType(string $doctrineType): ?string case Types::DATEINTERVAL: return Type::BUILTIN_TYPE_OBJECT; - case Types::ARRAY: + case 'array': // DBAL < 4 case Types::SIMPLE_ARRAY: - case 'json_array': + case 'json_array': // DBAL < 3 return Type::BUILTIN_TYPE_ARRAY; } diff --git a/src/Symfony/Bridge/Doctrine/Tests/DataCollector/DoctrineDataCollectorWithDebugStackTest.php b/src/Symfony/Bridge/Doctrine/Tests/DataCollector/DoctrineDataCollectorWithDebugStackTest.php index 64bee1203b781..690c5aa6f9b8d 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/DataCollector/DoctrineDataCollectorWithDebugStackTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/DataCollector/DoctrineDataCollectorWithDebugStackTest.php @@ -32,6 +32,13 @@ class DoctrineDataCollectorWithDebugStackTest extends TestCase { use DoctrineDataCollectorTestTrait; + public static function setUpBeforeClass(): void + { + if (!class_exists(DebugStack::class)) { + self::markTestSkipped('This test requires DBAL < 4.'); + } + } + public function testReset() { $queries = [ diff --git a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/SingleIntIdEntity.php b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/SingleIntIdEntity.php index 94b47da855a37..85c1c0cc20ea6 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/SingleIntIdEntity.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/SingleIntIdEntity.php @@ -11,6 +11,7 @@ namespace Symfony\Bridge\Doctrine\Tests\Fixtures; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping\Column; use Doctrine\ORM\Mapping\Entity; use Doctrine\ORM\Mapping\Id; @@ -27,8 +28,8 @@ class SingleIntIdEntity #[Column(type: 'string', nullable: true)] public $name; - /** @Column(type="array", nullable=true) */ - #[Column(type: 'array', nullable: true)] + /** @Column(type="json", nullable=true) */ + #[Column(type: Types::JSON, nullable: true)] public $phoneNumbers = []; public function __construct($id, $name) diff --git a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Type/StringWrapperType.php b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Type/StringWrapperType.php index d01148f3b018c..33481663b6152 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Type/StringWrapperType.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Type/StringWrapperType.php @@ -18,20 +18,16 @@ class StringWrapperType extends StringType { /** * {@inheritdoc} - * - * @return mixed */ - public function convertToDatabaseValue($value, AbstractPlatform $platform) + public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string { return $value instanceof StringWrapper ? $value->getString() : null; } /** * {@inheritdoc} - * - * @return mixed */ - public function convertToPHPValue($value, AbstractPlatform $platform) + public function convertToPHPValue($value, AbstractPlatform $platform): StringWrapper { return new StringWrapper($value); } diff --git a/src/Symfony/Bridge/Doctrine/Tests/Logger/DbalLoggerTest.php b/src/Symfony/Bridge/Doctrine/Tests/Logger/DbalLoggerTest.php index 2e9ed80e3115a..b43bb93d7dd52 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Logger/DbalLoggerTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Logger/DbalLoggerTest.php @@ -11,6 +11,7 @@ namespace Symfony\Bridge\Doctrine\Tests\Logger; +use Doctrine\DBAL\Logging\SQLLogger; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; use Symfony\Bridge\Doctrine\Logger\DbalLogger; @@ -20,6 +21,13 @@ */ class DbalLoggerTest extends TestCase { + public static function setUpBeforeClass(): void + { + if (!class_exists(SQLLogger::class)) { + self::markTestSkipped('This test requires DBAL < 4.'); + } + } + /** * @dataProvider getLogFixtures */ diff --git a/src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrinePingConnectionMiddlewareTest.php b/src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrinePingConnectionMiddlewareTest.php index 6c7bf67bc08af..a478f72266ffb 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrinePingConnectionMiddlewareTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrinePingConnectionMiddlewareTest.php @@ -13,8 +13,11 @@ use Doctrine\DBAL\Connection; use Doctrine\DBAL\Exception as DBALException; +use Doctrine\DBAL\Platforms\AbstractPlatform; +use Doctrine\DBAL\Result; use Doctrine\ORM\EntityManagerInterface; use Doctrine\Persistence\ManagerRegistry; +use PHPUnit\Framework\MockObject\MockObject; use Symfony\Bridge\Doctrine\Messenger\DoctrinePingConnectionMiddleware; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException; @@ -47,16 +50,24 @@ protected function setUp(): void public function testMiddlewarePingOk() { - $this->connection->expects($this->once()) - ->method('getDatabasePlatform') - ->will($this->throwException(new DBALException())); + $this->connection->method('getDatabasePlatform') + ->willReturn($this->mockPlatform()); + + $this->connection->expects($this->exactly(2)) + ->method('executeQuery') + ->willReturnCallback(function () { + static $counter = 0; + + if (1 === ++$counter) { + throw $this->createMock(DBALException::class); + } + + return $this->createMock(Result::class); + }); $this->connection->expects($this->once()) ->method('close') ; - $this->connection->expects($this->once()) - ->method('connect') - ; $envelope = new Envelope(new \stdClass(), [ new ConsumedByWorkerStamp(), @@ -66,9 +77,8 @@ public function testMiddlewarePingOk() public function testMiddlewarePingResetEntityManager() { - $this->connection->expects($this->once()) - ->method('getDatabasePlatform') - ->will($this->throwException(new DBALException())); + $this->connection->method('getDatabasePlatform') + ->willReturn($this->mockPlatform()); $this->entityManager->expects($this->once()) ->method('isOpen') @@ -112,11 +122,17 @@ public function testMiddlewareNoPingInNonWorkerContext() $this->connection->expects($this->never()) ->method('close') ; - $this->connection->expects($this->never()) - ->method('connect') - ; $envelope = new Envelope(new \stdClass()); $this->middleware->handle($envelope, $this->getStackMock()); } + + /** @return AbstractPlatform&MockObject */ + private function mockPlatform(): AbstractPlatform + { + $platform = $this->createMock(AbstractPlatform::class); + $platform->method('getDummySelectSQL')->willReturn('SELECT 1'); + + return $platform; + } } diff --git a/src/Symfony/Bridge/Doctrine/Tests/Middleware/Debug/MiddlewareTest.php b/src/Symfony/Bridge/Doctrine/Tests/Middleware/Debug/MiddlewareTest.php index 4e546b20890c6..e59428783e4dd 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Middleware/Debug/MiddlewareTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Middleware/Debug/MiddlewareTest.php @@ -178,13 +178,13 @@ public static function provideEndTransactionMethod(): array { return [ 'commit' => [ - static function (Connection $conn): bool { + static function (Connection $conn): ?bool { return $conn->commit(); }, '"COMMIT"', ], 'rollback' => [ - static function (Connection $conn): bool { + static function (Connection $conn): ?bool { return $conn->rollBack(); }, '"ROLLBACK"', @@ -236,7 +236,7 @@ public static function provideExecuteAndEndTransactionMethods(): array static function (Connection $conn, string $sql) { return $conn->executeStatement($sql); }, - static function (Connection $conn): bool { + static function (Connection $conn): ?bool { return $conn->commit(); }, ], @@ -244,7 +244,7 @@ static function (Connection $conn): bool { static function (Connection $conn, string $sql): Result { return $conn->executeQuery($sql); }, - static function (Connection $conn): bool { + static function (Connection $conn): ?bool { return $conn->rollBack(); }, ], @@ -252,7 +252,7 @@ static function (Connection $conn): bool { static function (Connection $conn, string $sql): Result { return $conn->prepare($sql)->executeQuery(); }, - static function (Connection $conn): bool { + static function (Connection $conn): ?bool { return $conn->commit(); }, ], diff --git a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineFooType.php b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineFooType.php index 7c09108fde562..cc2e8154a7c41 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineFooType.php +++ b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineFooType.php @@ -43,10 +43,8 @@ public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $pla /** * {@inheritdoc} - * - * @return mixed */ - public function convertToDatabaseValue($value, AbstractPlatform $platform) + public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string { if (null === $value) { return null; @@ -60,10 +58,8 @@ public function convertToDatabaseValue($value, AbstractPlatform $platform) /** * {@inheritdoc} - * - * @return mixed */ - public function convertToPHPValue($value, AbstractPlatform $platform) + public function convertToPHPValue($value, AbstractPlatform $platform): ?Foo { if (null === $value) { return null; diff --git a/src/Symfony/Bridge/Doctrine/Tests/SchemaListener/MessengerTransportDoctrineSchemaSubscriberTest.php b/src/Symfony/Bridge/Doctrine/Tests/SchemaListener/MessengerTransportDoctrineSchemaSubscriberTest.php index ff4ab2c27a19c..f846a4f38225a 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/SchemaListener/MessengerTransportDoctrineSchemaSubscriberTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/SchemaListener/MessengerTransportDoctrineSchemaSubscriberTest.php @@ -49,6 +49,10 @@ public function testPostGenerateSchema() public function testOnSchemaCreateTable() { + if (!class_exists(SchemaCreateTableEventArgs::class)) { + self::markTestSkipped('This test requires DBAL < 4.'); + } + $platform = $this->createMock(AbstractPlatform::class); $table = new Table('queue_table'); $event = new SchemaCreateTableEventArgs($table, [], [], $platform); @@ -80,6 +84,10 @@ public function testOnSchemaCreateTable() public function testOnSchemaCreateTableNoExtraSql() { + if (!class_exists(SchemaCreateTableEventArgs::class)) { + self::markTestSkipped('This test requires DBAL < 4.'); + } + $platform = $this->createMock(AbstractPlatform::class); $table = new Table('queue_table'); $event = new SchemaCreateTableEventArgs($table, [], [], $platform); diff --git a/src/Symfony/Bridge/Doctrine/Tests/Types/UlidTypeTest.php b/src/Symfony/Bridge/Doctrine/Tests/Types/UlidTypeTest.php index c1db2bbe70124..6f78bf3ecce92 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Types/UlidTypeTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Types/UlidTypeTest.php @@ -15,7 +15,7 @@ use Doctrine\DBAL\Platforms\MariaDBPlatform; use Doctrine\DBAL\Platforms\MySQLPlatform; use Doctrine\DBAL\Platforms\PostgreSQLPlatform; -use Doctrine\DBAL\Platforms\SqlitePlatform; +use Doctrine\DBAL\Platforms\SQLitePlatform; use Doctrine\DBAL\Types\ConversionException; use Doctrine\DBAL\Types\Type; use PHPUnit\Framework\TestCase; @@ -26,6 +26,9 @@ // DBAL 2 compatibility class_exists('Doctrine\DBAL\Platforms\PostgreSqlPlatform'); +// DBAL 3 compatibility +class_exists('Doctrine\DBAL\Platforms\SqlitePlatform'); + final class UlidTypeTest extends TestCase { private const DUMMY_ULID = '01EEDQEK6ZAZE93J8KG5B4MBJC'; @@ -85,25 +88,25 @@ public function testNotSupportedTypeConversionForDatabaseValue() { $this->expectException(ConversionException::class); - $this->type->convertToDatabaseValue(new \stdClass(), new SqlitePlatform()); + $this->type->convertToDatabaseValue(new \stdClass(), new SQLitePlatform()); } public function testNullConversionForDatabaseValue() { - $this->assertNull($this->type->convertToDatabaseValue(null, new SqlitePlatform())); + $this->assertNull($this->type->convertToDatabaseValue(null, new SQLitePlatform())); } public function testUlidInterfaceConvertsToPHPValue() { $ulid = $this->createMock(AbstractUid::class); - $actual = $this->type->convertToPHPValue($ulid, new SqlitePlatform()); + $actual = $this->type->convertToPHPValue($ulid, new SQLitePlatform()); $this->assertSame($ulid, $actual); } public function testUlidConvertsToPHPValue() { - $ulid = $this->type->convertToPHPValue(self::DUMMY_ULID, new SqlitePlatform()); + $ulid = $this->type->convertToPHPValue(self::DUMMY_ULID, new SQLitePlatform()); $this->assertInstanceOf(Ulid::class, $ulid); $this->assertEquals(self::DUMMY_ULID, $ulid->__toString()); @@ -113,19 +116,19 @@ public function testInvalidUlidConversionForPHPValue() { $this->expectException(ConversionException::class); - $this->type->convertToPHPValue('abcdefg', new SqlitePlatform()); + $this->type->convertToPHPValue('abcdefg', new SQLitePlatform()); } public function testNullConversionForPHPValue() { - $this->assertNull($this->type->convertToPHPValue(null, new SqlitePlatform())); + $this->assertNull($this->type->convertToPHPValue(null, new SQLitePlatform())); } public function testReturnValueIfUlidForPHPValue() { $ulid = new Ulid(); - $this->assertSame($ulid, $this->type->convertToPHPValue($ulid, new SqlitePlatform())); + $this->assertSame($ulid, $this->type->convertToPHPValue($ulid, new SQLitePlatform())); } public function testGetName() @@ -144,7 +147,7 @@ public function testGetGuidTypeDeclarationSQL(AbstractPlatform $platform, string public static function provideSqlDeclarations(): \Generator { yield [new PostgreSQLPlatform(), 'UUID']; - yield [new SqlitePlatform(), 'BLOB']; + yield [new SQLitePlatform(), 'BLOB']; yield [new MySQLPlatform(), 'BINARY(16)']; if (class_exists(MariaDBPlatform::class)) { @@ -154,6 +157,6 @@ public static function provideSqlDeclarations(): \Generator public function testRequiresSQLCommentHint() { - $this->assertTrue($this->type->requiresSQLCommentHint(new SqlitePlatform())); + $this->assertTrue($this->type->requiresSQLCommentHint(new SQLitePlatform())); } } diff --git a/src/Symfony/Bridge/Doctrine/Types/AbstractUidType.php b/src/Symfony/Bridge/Doctrine/Types/AbstractUidType.php index 003093aec8845..fa1a72fa4eb33 100644 --- a/src/Symfony/Bridge/Doctrine/Types/AbstractUidType.php +++ b/src/Symfony/Bridge/Doctrine/Types/AbstractUidType.php @@ -13,6 +13,8 @@ use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Types\ConversionException; +use Doctrine\DBAL\Types\Exception\InvalidType; +use Doctrine\DBAL\Types\Exception\ValueNotConvertible; use Doctrine\DBAL\Types\Type; use Symfony\Component\Uid\AbstractUid; @@ -33,7 +35,7 @@ public function getSQLDeclaration(array $column, AbstractPlatform $platform): st } return $platform->getBinaryTypeDeclarationSQL([ - 'length' => '16', + 'length' => 16, 'fixed' => true, ]); } @@ -50,13 +52,13 @@ public function convertToPHPValue($value, AbstractPlatform $platform): ?Abstract } if (!\is_string($value)) { - throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'string', AbstractUid::class]); + $this->throwInvalidType($value); } try { return $this->getUidClass()::fromString($value); } catch (\InvalidArgumentException $e) { - throw ConversionException::conversionFailed($value, $this->getName(), $e); + $this->throwValueNotConvertible($value, $e); } } @@ -78,13 +80,13 @@ public function convertToDatabaseValue($value, AbstractPlatform $platform): ?str } if (!\is_string($value)) { - throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'string', AbstractUid::class]); + $this->throwInvalidType($value); } try { return $this->getUidClass()::fromString($value)->$toString(); } catch (\InvalidArgumentException $e) { - throw ConversionException::conversionFailed($value, $this->getName()); + $this->throwValueNotConvertible($value, $e); } } @@ -105,4 +107,32 @@ private function hasNativeGuidType(AbstractPlatform $platform): bool return $platform->getGuidTypeDeclarationSQL([]) !== $platform->$method(['fixed' => true, 'length' => 36]); } + + /** + * @param mixed $value + * + * @return never + */ + private function throwInvalidType($value): void + { + if (!class_exists(InvalidType::class)) { + throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'string', AbstractUid::class]); + } + + throw InvalidType::new($value, $this->getName(), ['null', 'string', AbstractUid::class]); + } + + /** + * @param mixed $value + * + * @return never + */ + private function throwValueNotConvertible($value, \Throwable $previous): void + { + if (!class_exists(ValueNotConvertible::class)) { + throw ConversionException::conversionFailed($value, $this->getName(), $previous); + } + + throw ValueNotConvertible::new($value, $this->getName(), null, $previous); + } } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy