From 990a91c2718d48ece5cf7540512a3c8563802784 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 | 15 +- .../Doctrine/Middleware/Debug/Connection.php | 135 ++++---------- .../Middleware/Debug/DBAL3/Connection.php | 174 ++++++++++++++++++ .../Middleware/Debug/DBAL3/Statement.php | 86 +++++++++ .../Middleware/Debug/DebugDataHolder.php | 4 +- .../Doctrine/Middleware/Debug/Driver.php | 16 +- .../Doctrine/Middleware/Debug/Middleware.php | 14 +- .../Doctrine/Middleware/Debug/Query.php | 30 ++- .../Doctrine/Middleware/Debug/Statement.php | 51 ++--- .../PropertyInfo/DoctrineExtractor.php | 6 +- ...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 | 6 +- ...rTransportDoctrineSchemaSubscriberTest.php | 8 + .../Doctrine/Tests/Types/UlidTypeTest.php | 23 ++- .../Bridge/Doctrine/Types/AbstractUidType.php | 38 +++- 21 files changed, 471 insertions(+), 215 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..7336649ea398e 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': 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..083e25dccc11c 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,29 @@ protected function handleForManager(EntityManagerInterface $entityManager, Envel return $stack->next()->handle($envelope, $stack); } + /** @return void */ private function pingConnection(EntityManagerInterface $entityManager) { $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/DebugDataHolder.php b/src/Symfony/Bridge/Doctrine/Middleware/Debug/DebugDataHolder.php index 2643cc7493830..4e1052a139651 100644 --- a/src/Symfony/Bridge/Doctrine/Middleware/Debug/DebugDataHolder.php +++ b/src/Symfony/Bridge/Doctrine/Middleware/Debug/DebugDataHolder.php @@ -16,7 +16,7 @@ */ class DebugDataHolder { - private $data = []; + private array $data = []; public function addQuery(string $connectionName, Query $query): void { @@ -24,7 +24,7 @@ public function addQuery(string $connectionName, Query $query): void 'sql' => $query->getSql(), 'params' => $query->getParams(), 'types' => $query->getTypes(), - 'executionMS' => [$query, 'getDuration'], // stop() may not be called at this point + 'executionMS' => $query->getDuration(...), // stop() may not be called at this point ]; } 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/Middleware.php b/src/Symfony/Bridge/Doctrine/Middleware/Debug/Middleware.php index 18f6a58d5e7a2..56b03f51335a8 100644 --- a/src/Symfony/Bridge/Doctrine/Middleware/Debug/Middleware.php +++ b/src/Symfony/Bridge/Doctrine/Middleware/Debug/Middleware.php @@ -22,15 +22,11 @@ */ final class Middleware implements MiddlewareInterface { - private $debugDataHolder; - private $stopwatch; - private $connectionName; - - public function __construct(DebugDataHolder $debugDataHolder, ?Stopwatch $stopwatch, string $connectionName = 'default') - { - $this->debugDataHolder = $debugDataHolder; - $this->stopwatch = $stopwatch; - $this->connectionName = $connectionName; + public function __construct( + private DebugDataHolder $debugDataHolder, + private ?Stopwatch $stopwatch, + private string $connectionName = 'default', + ) { } public function wrap(DriverInterface $driver): DriverInterface diff --git a/src/Symfony/Bridge/Doctrine/Middleware/Debug/Query.php b/src/Symfony/Bridge/Doctrine/Middleware/Debug/Query.php index eb835caa41b25..b2668ed1dc366 100644 --- a/src/Symfony/Bridge/Doctrine/Middleware/Debug/Query.php +++ b/src/Symfony/Bridge/Doctrine/Middleware/Debug/Query.php @@ -20,17 +20,17 @@ */ class Query { - private $params = []; - private $types = []; + private array $params = []; - private $start; - private $duration; + /** @var array */ + private array $types = []; - private $sql; + private ?float $start = null; + private ?float $duration = null; - public function __construct(string $sql) - { - $this->sql = $sql; + public function __construct( + private readonly string $sql, + ) { } public function start(): void @@ -45,11 +45,7 @@ public function stop(): void } } - /** - * @param string|int $param - * @param mixed $variable - */ - public function setParam($param, &$variable, int $type): void + public function setParam(string|int $param, mixed &$variable, int $type): void { // Numeric indexes start at 0 in profiler $idx = \is_int($param) ? $param - 1 : $param; @@ -58,11 +54,7 @@ public function setParam($param, &$variable, int $type): void $this->types[$idx] = $type; } - /** - * @param string|int $param - * @param mixed $value - */ - public function setValue($param, $value, int $type): void + public function setValue(string|int $param, mixed $value, ParameterType|int $type): void { // Numeric indexes start at 0 in profiler $idx = \is_int($param) ? $param - 1 : $param; @@ -95,7 +87,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..b64c4fb887dc7 100644 --- a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php +++ b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php @@ -167,7 +167,7 @@ public function getTypes(string $class, string $property, array $context = []) break; case Type::BUILTIN_TYPE_ARRAY: switch ($typeOfField) { - case Types::ARRAY: + case 'array': case 'json_array': // return null if $enumType is set, because we can't determine if collectionKeyType is string or int if ($enumType) { @@ -281,7 +281,7 @@ private function getPhpType(string $doctrineType): ?string case Types::BINARY: return Type::BUILTIN_TYPE_RESOURCE; - case Types::OBJECT: + case 'object': case Types::DATE_MUTABLE: case Types::DATETIME_MUTABLE: case Types::DATETIMETZ_MUTABLE: @@ -294,7 +294,7 @@ private function getPhpType(string $doctrineType): ?string case Types::DATEINTERVAL: return Type::BUILTIN_TYPE_OBJECT; - case Types::ARRAY: + case 'array': case Types::SIMPLE_ARRAY: case 'json_array': 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..2a804512dc383 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineFooType.php +++ b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineFooType.php @@ -46,7 +46,7 @@ public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $pla * * @return mixed */ - public function convertToDatabaseValue($value, AbstractPlatform $platform) + public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string { if (null === $value) { return null; @@ -60,10 +60,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..a16a2cbeb247c 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,30 @@ 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