From 3932974a7e33c7c7d6807046688998c87cbe558a Mon Sep 17 00:00:00 2001 From: n0099 Date: Sun, 1 Jun 2025 17:05:18 +0000 Subject: [PATCH 1/7] Update dql-custom-walkers.rst --- docs/en/cookbook/dql-custom-walkers.rst | 79 ++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 2 deletions(-) diff --git a/docs/en/cookbook/dql-custom-walkers.rst b/docs/en/cookbook/dql-custom-walkers.rst index 4320856eb49..f2b07145bf6 100644 --- a/docs/en/cookbook/dql-custom-walkers.rst +++ b/docs/en/cookbook/dql-custom-walkers.rst @@ -40,7 +40,8 @@ Now this is all awfully technical, so let me come to some use-cases fast to keep you motivated. Using walker implementation you can for example: - +- Modify the Output walker to get the raw SQL via ``Query->getSQL()`` + with interpolated parameters. - Modify the AST to generate a Count Query to be used with a paginator for any given DQL query. - Modify the Output Walker to generate vendor-specific SQL @@ -50,7 +51,7 @@ example: - Modify the Output walker to pretty print the SQL for debugging purposes. -In this cookbook-entry I will show examples of the first two +In this cookbook-entry I will show examples of the first three points. There are probably much more use-cases. Generic count query for pagination @@ -215,3 +216,77 @@ huge benefits with using vendor specific features. This would still allow you write DQL queries instead of NativeQueries to make use of vendor specific features. +Modify the Output Walker to get the raw SQL with interpolated parameters +-------------------------------------------------------- + +.. code-block:: php + + getQuery()->getParameter($inputParam->name); + if ($parameter === null) { + return '?'; + } + + $value = $parameter->getValue(); + /** @var ParameterType|ArrayParameterType|int|string $typeName */ + /** @see \Doctrine\ORM\Query\ParameterTypeInferer::inferType() */ + $typeName = $parameter->getType(); + $platform = $this->getConnection()->getDatabasePlatform(); + $processParameterType = static fn(ParameterType $type) => static fn($value): string => + (match ($type) { /** @see Type::getBindingType() */ + ParameterType::NULL => 'NULL', + ParameterType::INTEGER => $value, + ParameterType::BOOLEAN => (new BooleanType())->convertToDatabaseValue($value, $platform), + ParameterType::STRING, ParameterType::ASCII => $platform->quoteStringLiteral($value), + default => throw new ValueNotConvertible($value, $type->name) + }); + + if (is_string($typeName) && Type::hasType($typeName)) { + return Type::getType($typeName)->convertToDatabaseValue($value, $platform); + } + if ($typeName instanceof ParameterType) { + return $processParameterType($typeName)($value); + } + if ($typeName instanceof ArrayParameterType && is_array($value)) { + $type = ArrayParameterType::toElementParameterType($typeName); + return implode(', ', array_map($processParameterType($type), $value)); + } + + throw new ValueNotConvertible($value, $typeName); + } + } + +Then you may get raw SQL with: + +.. code-block:: php + + where('t.int IN (:ints)')->setParameter(':ints', [1, 2]) + ->orWhere('t.string IN (?0)')->setParameter(0, ['3', '4']) + ->orWhere("t.bool = ?1")->setParameter('?1', true) + ->orWhere("t.string = :string")->setParameter(':string', 'ABC') + ->setHint(\Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER, InterpolateParametersSQLOutputWalker::class) + ->getSQL(); + +The where clause of returned SQL should be like: + +.. code-block:: sql + + WHERE t0_.int IN (1, 2) + OR t0_.string IN ('3', '4') + OR t0_.bool = 1 + OR t0_.string = 'ABC' From 705d23dd0231e1b4038860534cf42c3e1135c2af Mon Sep 17 00:00:00 2001 From: n0099 Date: Wed, 8 Oct 2025 10:50:46 +0000 Subject: [PATCH 2/7] Add summary about `InterpolateParametersSQLOutputWalker` --- docs/en/cookbook/dql-custom-walkers.rst | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/en/cookbook/dql-custom-walkers.rst b/docs/en/cookbook/dql-custom-walkers.rst index f2b07145bf6..6f535aa58a8 100644 --- a/docs/en/cookbook/dql-custom-walkers.rst +++ b/docs/en/cookbook/dql-custom-walkers.rst @@ -219,6 +219,14 @@ vendor specific features. Modify the Output Walker to get the raw SQL with interpolated parameters -------------------------------------------------------- +Sometimes we may want to log or trace the raw SQL being generated from its DQL, +``$query->getSQL()`` will give us the prepared statment being passed to database +with all values of SQL params being replaced by positional ``?`` or named ``:name`` +as params are innerpolated into prepared statment by the database while executing the SQL. +``$query->getParameters()`` will give us details about SQL params that we've provided. +So we can create an output walker to interpolate all SQL params that will be +passed into prepared statement in PHP before database handle them internally: + .. code-block:: php setHint(\Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER, InterpolateParametersSQLOutputWalker::class) ->getSQL(); -The where clause of returned SQL should be like: +The where clause of the returned SQL should be like: .. code-block:: sql From 644e27db4d1dff3d6303a923b7fe08b5e55d01d4 Mon Sep 17 00:00:00 2001 From: n0099 Date: Wed, 8 Oct 2025 13:24:06 +0000 Subject: [PATCH 3/7] Update docs/en/cookbook/dql-custom-walkers.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Grégoire Paris --- docs/en/cookbook/dql-custom-walkers.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/cookbook/dql-custom-walkers.rst b/docs/en/cookbook/dql-custom-walkers.rst index 6f535aa58a8..d30f36feed4 100644 --- a/docs/en/cookbook/dql-custom-walkers.rst +++ b/docs/en/cookbook/dql-custom-walkers.rst @@ -216,7 +216,7 @@ huge benefits with using vendor specific features. This would still allow you write DQL queries instead of NativeQueries to make use of vendor specific features. -Modify the Output Walker to get the raw SQL with interpolated parameters +Modifying the Output Walker to get the raw SQL with interpolated parameters -------------------------------------------------------- Sometimes we may want to log or trace the raw SQL being generated from its DQL, From a9f785967852ca10f8e290b109149f0303d0aaf8 Mon Sep 17 00:00:00 2001 From: n0099 Date: Wed, 8 Oct 2025 13:25:07 +0000 Subject: [PATCH 4/7] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Grégoire Paris --- docs/en/cookbook/dql-custom-walkers.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/en/cookbook/dql-custom-walkers.rst b/docs/en/cookbook/dql-custom-walkers.rst index d30f36feed4..5616ea8867a 100644 --- a/docs/en/cookbook/dql-custom-walkers.rst +++ b/docs/en/cookbook/dql-custom-walkers.rst @@ -217,12 +217,12 @@ allow you write DQL queries instead of NativeQueries to make use of vendor specific features. Modifying the Output Walker to get the raw SQL with interpolated parameters --------------------------------------------------------- +--------------------------------------------------------------------------- Sometimes we may want to log or trace the raw SQL being generated from its DQL, -``$query->getSQL()`` will give us the prepared statment being passed to database +``$query->getSQL()`` will give us the prepared statement being passed to database with all values of SQL params being replaced by positional ``?`` or named ``:name`` -as params are innerpolated into prepared statment by the database while executing the SQL. +as parameters are interpolated into prepared statements by the database while executing the SQL. ``$query->getParameters()`` will give us details about SQL params that we've provided. So we can create an output walker to interpolate all SQL params that will be passed into prepared statement in PHP before database handle them internally: From 38dd0cc6eb75de9f3d6de13c59be3a21e3e8a3e2 Mon Sep 17 00:00:00 2001 From: n0099 Date: Wed, 8 Oct 2025 13:26:24 +0000 Subject: [PATCH 5/7] s/params/parameters/g --- docs/en/cookbook/dql-custom-walkers.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/en/cookbook/dql-custom-walkers.rst b/docs/en/cookbook/dql-custom-walkers.rst index 5616ea8867a..48b6684e5e4 100644 --- a/docs/en/cookbook/dql-custom-walkers.rst +++ b/docs/en/cookbook/dql-custom-walkers.rst @@ -221,10 +221,10 @@ Modifying the Output Walker to get the raw SQL with interpolated parameters Sometimes we may want to log or trace the raw SQL being generated from its DQL, ``$query->getSQL()`` will give us the prepared statement being passed to database -with all values of SQL params being replaced by positional ``?`` or named ``:name`` +with all values of SQL parameters being replaced by positional ``?`` or named ``:name`` as parameters are interpolated into prepared statements by the database while executing the SQL. -``$query->getParameters()`` will give us details about SQL params that we've provided. -So we can create an output walker to interpolate all SQL params that will be +``$query->getParameters()`` will give us details about SQL parameters that we've provided. +So we can create an output walker to interpolate all SQL parameters that will be passed into prepared statement in PHP before database handle them internally: .. code-block:: php From 1cc805fde5811781e7c694a5c2cac21d8cbe3e4d Mon Sep 17 00:00:00 2001 From: n0099 Date: Wed, 8 Oct 2025 13:36:44 +0000 Subject: [PATCH 6/7] Create InterpolateParametersSQLOutputWalker.php --- .../InterpolateParametersSQLOutputWalker.php | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 docs/en/cookbook/dql-custom-walkers/InterpolateParametersSQLOutputWalker.php diff --git a/docs/en/cookbook/dql-custom-walkers/InterpolateParametersSQLOutputWalker.php b/docs/en/cookbook/dql-custom-walkers/InterpolateParametersSQLOutputWalker.php new file mode 100644 index 00000000000..c6e5ed4a3bc --- /dev/null +++ b/docs/en/cookbook/dql-custom-walkers/InterpolateParametersSQLOutputWalker.php @@ -0,0 +1,47 @@ +getQuery()->getParameter($inputParam->name); + if ($parameter === null) { + return '?'; + } + + $value = $parameter->getValue(); + /** @var ParameterType|ArrayParameterType|int|string $typeName */ + /** @see \Doctrine\ORM\Query\ParameterTypeInferer::inferType() */ + $typeName = $parameter->getType(); + $platform = $this->getConnection()->getDatabasePlatform(); + $processParameterType = static fn(ParameterType $type) => static fn($value): string => + (match ($type) { /** @see Type::getBindingType() */ + ParameterType::NULL => 'NULL', + ParameterType::INTEGER => $value, + ParameterType::BOOLEAN => (new BooleanType())->convertToDatabaseValue($value, $platform), + ParameterType::STRING, ParameterType::ASCII => $platform->quoteStringLiteral($value), + default => throw new ValueNotConvertible($value, $type->name) + }); + + if (is_string($typeName) && Type::hasType($typeName)) { + return Type::getType($typeName)->convertToDatabaseValue($value, $platform); + } + if ($typeName instanceof ParameterType) { + return $processParameterType($typeName)($value); + } + if ($typeName instanceof ArrayParameterType && is_array($value)) { + $type = ArrayParameterType::toElementParameterType($typeName); + return implode(', ', array_map($processParameterType($type), $value)); + } + + throw new ValueNotConvertible($value, $typeName); + } +} From 407487c672b9847bbf013ca6c29e261a5f605a8c Mon Sep 17 00:00:00 2001 From: n0099 Date: Wed, 8 Oct 2025 13:37:17 +0000 Subject: [PATCH 7/7] Update dql-custom-walkers.rst --- docs/en/cookbook/dql-custom-walkers.rst | 51 +------------------------ 1 file changed, 2 insertions(+), 49 deletions(-) diff --git a/docs/en/cookbook/dql-custom-walkers.rst b/docs/en/cookbook/dql-custom-walkers.rst index 48b6684e5e4..80e0100dd4d 100644 --- a/docs/en/cookbook/dql-custom-walkers.rst +++ b/docs/en/cookbook/dql-custom-walkers.rst @@ -227,55 +227,8 @@ as parameters are interpolated into prepared statements by the database while ex So we can create an output walker to interpolate all SQL parameters that will be passed into prepared statement in PHP before database handle them internally: -.. code-block:: php - - getQuery()->getParameter($inputParam->name); - if ($parameter === null) { - return '?'; - } - - $value = $parameter->getValue(); - /** @var ParameterType|ArrayParameterType|int|string $typeName */ - /** @see \Doctrine\ORM\Query\ParameterTypeInferer::inferType() */ - $typeName = $parameter->getType(); - $platform = $this->getConnection()->getDatabasePlatform(); - $processParameterType = static fn(ParameterType $type) => static fn($value): string => - (match ($type) { /** @see Type::getBindingType() */ - ParameterType::NULL => 'NULL', - ParameterType::INTEGER => $value, - ParameterType::BOOLEAN => (new BooleanType())->convertToDatabaseValue($value, $platform), - ParameterType::STRING, ParameterType::ASCII => $platform->quoteStringLiteral($value), - default => throw new ValueNotConvertible($value, $type->name) - }); - - if (is_string($typeName) && Type::hasType($typeName)) { - return Type::getType($typeName)->convertToDatabaseValue($value, $platform); - } - if ($typeName instanceof ParameterType) { - return $processParameterType($typeName)($value); - } - if ($typeName instanceof ArrayParameterType && is_array($value)) { - $type = ArrayParameterType::toElementParameterType($typeName); - return implode(', ', array_map($processParameterType($type), $value)); - } - - throw new ValueNotConvertible($value, $typeName); - } - } +.. literalinclude:: dql-custom-walkers/InterpolateParametersSQLOutputWalker.php + :language: php Then you may get the raw SQL with this output walker: