diff --git a/UPGRADE.md b/UPGRADE.md index c5c9f854b97..6736e87e941 100644 --- a/UPGRADE.md +++ b/UPGRADE.md @@ -1,5 +1,16 @@ # Upgrade to 4.0 +## BC BREAK: Internal structure of `Doctrine\ORM\Query\ParserResult` changed + +The internal structure of `Doctrine\ORM\Query\ParserResult` changed. Thus, it is no longer possible to unserialize cached parser result instances that +were created and serialized with the previous major version of the ORM. + +You need to clear your query cache when upgrading to the new major version. + +## BC BREAK: `Doctrine\ORM\Query\ParserResult` no longer holds `AbstractSqlExecutor`, `Doctrine\ORM\Query\Exec\SingleSelectExecutor` is removed + +This finishes the refactoring started in https://github.com/doctrine/orm/pull/11188: `ParserResult` has to be provided with an `Doctrine\ORM\Query\Exec\SqlFinalizer`. The `SingleSelectExecutor` is removed since it has been replaced by `SingleSelectSqlFinalizer`. + ## BC BREAK: throw on `nullable` on columns that end up being used in a primary key Specifying `nullable` on join columns that are part of a primary key is diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index a122b7caca2..a97ca680785 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -2280,12 +2280,6 @@ parameters: count: 1 path: src/Query/Exec/MultiTableUpdateExecutor.php - - - message: '#^Parameter \#1 \$sql of method Doctrine\\DBAL\\Connection\:\:executeQuery\(\) expects string, list\\|string given\.$#' - identifier: argument.type - count: 1 - path: src/Query/Exec/SingleSelectExecutor.php - - message: '#^Method Doctrine\\ORM\\Query\\Exec\\SingleTableDeleteUpdateExecutor\:\:execute\(\) should return int but returns int\|string\.$#' identifier: return.type diff --git a/src/Query/Exec/SingleSelectExecutor.php b/src/Query/Exec/SingleSelectExecutor.php deleted file mode 100644 index 5445edb9994..00000000000 --- a/src/Query/Exec/SingleSelectExecutor.php +++ /dev/null @@ -1,31 +0,0 @@ -sqlStatements = $sqlWalker->walkSelectStatement($AST); - } - - /** - * {@inheritDoc} - */ - public function execute(Connection $conn, array $params, array $types): Result - { - return $conn->executeQuery($this->sqlStatements, $params, $types, $this->queryCacheProfile); - } -} diff --git a/src/Query/ParserResult.php b/src/Query/ParserResult.php index 34225e046e4..936ab49a05b 100644 --- a/src/Query/ParserResult.php +++ b/src/Query/ParserResult.php @@ -9,8 +9,6 @@ use Doctrine\ORM\Query\Exec\SqlFinalizer; use LogicException; -use function sprintf; - /** * Encapsulates the resulting components from a DQL query parsing process that * can be serialized. @@ -19,11 +17,6 @@ */ class ParserResult { - /** - * The SQL executor used for executing the SQL. - */ - private AbstractSqlExecutor|null $sqlExecutor = null; - /** * The SQL executor used for executing the SQL. */ @@ -68,33 +61,6 @@ public function setResultSetMapping(ResultSetMapping $rsm): void $this->resultSetMapping = $rsm; } - /** - * Sets the SQL executor that should be used for this ParserResult. - * - * @deprecated - */ - public function setSqlExecutor(AbstractSqlExecutor $executor): void - { - $this->sqlExecutor = $executor; - } - - /** - * Gets the SQL executor used by this ParserResult. - * - * @deprecated - */ - public function getSqlExecutor(): AbstractSqlExecutor - { - if ($this->sqlExecutor === null) { - throw new LogicException(sprintf( - 'Executor not set yet. Call %s::setSqlExecutor() first.', - self::class, - )); - } - - return $this->sqlExecutor; - } - public function setSqlFinalizer(SqlFinalizer $finalizer): void { $this->sqlFinalizer = $finalizer; @@ -102,15 +68,11 @@ public function setSqlFinalizer(SqlFinalizer $finalizer): void public function prepareSqlExecutor(Query $query): AbstractSqlExecutor { - if ($this->sqlFinalizer !== null) { - return $this->sqlFinalizer->createExecutor($query); - } - - if ($this->sqlExecutor !== null) { - return $this->sqlExecutor; + if ($this->sqlFinalizer === null) { + throw new LogicException('No SqlFinalizer has been set; this ParserResult is incomplete.'); } - throw new LogicException('This ParserResult lacks both the SqlFinalizer as well as the (legacy) SqlExecutor'); + return $this->sqlFinalizer->createExecutor($query); } /** diff --git a/tests/Tests/ORM/Functional/ParserResultSerializationTest.php b/tests/Tests/ORM/Functional/ParserResultSerializationTest.php index ed21cd93d0b..95e4785e8ee 100644 --- a/tests/Tests/ORM/Functional/ParserResultSerializationTest.php +++ b/tests/Tests/ORM/Functional/ParserResultSerializationTest.php @@ -8,7 +8,6 @@ use Doctrine\ORM\Query; use Doctrine\ORM\Query\Exec\FinalizedSelectExecutor; use Doctrine\ORM\Query\Exec\PreparedExecutorFinalizer; -use Doctrine\ORM\Query\Exec\SingleSelectExecutor; use Doctrine\ORM\Query\ParserResult; use Doctrine\ORM\Query\ResultSetMapping; use Doctrine\Tests\OrmFunctionalTestCase; @@ -18,8 +17,6 @@ use Symfony\Component\VarExporter\Instantiator; use Symfony\Component\VarExporter\VarExporter; -use function file_get_contents; -use function rtrim; use function serialize; use function unserialize; @@ -69,24 +66,6 @@ static function (ParserResult $parserResult): ParserResult { ]; } - #[DataProvider('provideSerializedSingleSelectResults')] - public function testUnserializeSingleSelectResult(string $serialized): void - { - $unserialized = unserialize($serialized); - - $this->assertInstanceOf(ParserResult::class, $unserialized); - $this->assertInstanceOf(ResultSetMapping::class, $unserialized->getResultSetMapping()); - $this->assertEquals(['name' => [0]], $unserialized->getParameterMappings()); - $this->assertInstanceOf(SingleSelectExecutor::class, $unserialized->getSqlExecutor()); - $this->assertIsString($unserialized->getSqlExecutor()->getSqlStatements()); - } - - /** @return Generator */ - public static function provideSerializedSingleSelectResults(): Generator - { - yield '2.17.0' => [rtrim(file_get_contents(__DIR__ . '/ParserResults/single_select_2_17_0.txt'), "\n")]; - } - public function testSymfony44ProvidedData(): void { $sqlExecutor = new FinalizedSelectExecutor('test'); diff --git a/tests/Tests/ORM/Functional/ParserResults/single_select_2_17_0.txt b/tests/Tests/ORM/Functional/ParserResults/single_select_2_17_0.txt deleted file mode 100644 index aa854bfab92..00000000000 Binary files a/tests/Tests/ORM/Functional/ParserResults/single_select_2_17_0.txt and /dev/null differ diff --git a/tests/Tests/ORM/Functional/QueryCacheTest.php b/tests/Tests/ORM/Functional/QueryCacheTest.php index d5290add28b..fab3122ceee 100644 --- a/tests/Tests/ORM/Functional/QueryCacheTest.php +++ b/tests/Tests/ORM/Functional/QueryCacheTest.php @@ -7,6 +7,7 @@ use Doctrine\DBAL\Connection; use Doctrine\ORM\Query; use Doctrine\ORM\Query\Exec\AbstractSqlExecutor; +use Doctrine\ORM\Query\Exec\SqlFinalizer; use Doctrine\ORM\Query\ParserResult; use Doctrine\Tests\OrmFunctionalTestCase; use PHPUnit\Framework\Attributes\Depends; @@ -130,8 +131,11 @@ public function execute(Connection $conn, array $params, array $types): int } }; + $sqlFinalizerMock = $this->createMock(SqlFinalizer::class); + $sqlFinalizerMock->method('createExecutor')->with($query)->willReturn($sqlExecutorStub); + $parserResultMock = new ParserResult(); - $parserResultMock->setSqlExecutor($sqlExecutorStub); + $parserResultMock->setSqlFinalizer($sqlFinalizerMock); $cache = $this->createMock(CacheItemPoolInterface::class); diff --git a/tests/Tests/ORM/Query/ParserResultTest.php b/tests/Tests/ORM/Query/ParserResultTest.php index b18d0830574..918b356827b 100644 --- a/tests/Tests/ORM/Query/ParserResultTest.php +++ b/tests/Tests/ORM/Query/ParserResultTest.php @@ -4,10 +4,8 @@ namespace Doctrine\Tests\ORM\Query; -use Doctrine\ORM\Query\Exec\AbstractSqlExecutor; use Doctrine\ORM\Query\ParserResult; use Doctrine\ORM\Query\ResultSetMapping; -use LogicException; use PHPUnit\Framework\TestCase; class ParserResultTest extends TestCase @@ -25,23 +23,6 @@ public function testGetRsm(): void self::assertInstanceOf(ResultSetMapping::class, $this->parserResult->getResultSetMapping()); } - public function testItThrowsWhenAttemptingToAccessTheExecutorBeforeItIsSet(): void - { - $this->expectException(LogicException::class); - $this->expectExceptionMessage( - 'Executor not set yet. Call Doctrine\ORM\Query\ParserResult::setSqlExecutor() first.', - ); - - $this->parserResult->getSqlExecutor(); - } - - public function testSetGetSqlExecutor(): void - { - $executor = $this->createMock(AbstractSqlExecutor::class); - $this->parserResult->setSqlExecutor($executor); - self::assertSame($executor, $this->parserResult->getSqlExecutor()); - } - public function testGetSqlParameterPosition(): void { $this->parserResult->addParameterMapping(1, 1);