Skip to content

Commit 3932974

Browse files
committed
Update dql-custom-walkers.rst
1 parent e19704e commit 3932974

File tree

1 file changed

+77
-2
lines changed

1 file changed

+77
-2
lines changed

docs/en/cookbook/dql-custom-walkers.rst

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ Now this is all awfully technical, so let me come to some use-cases
4040
fast to keep you motivated. Using walker implementation you can for
4141
example:
4242

43-
43+
- Modify the Output walker to get the raw SQL via ``Query->getSQL()``
44+
with interpolated parameters.
4445
- Modify the AST to generate a Count Query to be used with a
4546
paginator for any given DQL query.
4647
- Modify the Output Walker to generate vendor-specific SQL
@@ -50,7 +51,7 @@ example:
5051
- Modify the Output walker to pretty print the SQL for debugging
5152
purposes.
5253

53-
In this cookbook-entry I will show examples of the first two
54+
In this cookbook-entry I will show examples of the first three
5455
points. There are probably much more use-cases.
5556

5657
Generic count query for pagination
@@ -215,3 +216,77 @@ huge benefits with using vendor specific features. This would still
215216
allow you write DQL queries instead of NativeQueries to make use of
216217
vendor specific features.
217218

219+
Modify the Output Walker to get the raw SQL with interpolated parameters
220+
--------------------------------------------------------
221+
222+
.. code-block:: php
223+
224+
<?php
225+
use Doctrine\DBAL\ArrayParameterType;
226+
use Doctrine\DBAL\ParameterType;
227+
use Doctrine\DBAL\Types\BooleanType;
228+
use Doctrine\DBAL\Types\Exception\ValueNotConvertible;
229+
use Doctrine\DBAL\Types\Type;
230+
use Doctrine\ORM\Query\AST;
231+
use Doctrine\ORM\Query\SqlOutputWalker;
232+
233+
class InterpolateParametersSQLOutputWalker extends SqlOutputWalker
234+
{
235+
/** {@inheritdoc} */
236+
public function walkInputParameter(AST\InputParameter $inputParam): string
237+
{
238+
$parameter = $this->getQuery()->getParameter($inputParam->name);
239+
if ($parameter === null) {
240+
return '?';
241+
}
242+
243+
$value = $parameter->getValue();
244+
/** @var ParameterType|ArrayParameterType|int|string $typeName */
245+
/** @see \Doctrine\ORM\Query\ParameterTypeInferer::inferType() */
246+
$typeName = $parameter->getType();
247+
$platform = $this->getConnection()->getDatabasePlatform();
248+
$processParameterType = static fn(ParameterType $type) => static fn($value): string =>
249+
(match ($type) { /** @see Type::getBindingType() */
250+
ParameterType::NULL => 'NULL',
251+
ParameterType::INTEGER => $value,
252+
ParameterType::BOOLEAN => (new BooleanType())->convertToDatabaseValue($value, $platform),
253+
ParameterType::STRING, ParameterType::ASCII => $platform->quoteStringLiteral($value),
254+
default => throw new ValueNotConvertible($value, $type->name)
255+
});
256+
257+
if (is_string($typeName) && Type::hasType($typeName)) {
258+
return Type::getType($typeName)->convertToDatabaseValue($value, $platform);
259+
}
260+
if ($typeName instanceof ParameterType) {
261+
return $processParameterType($typeName)($value);
262+
}
263+
if ($typeName instanceof ArrayParameterType && is_array($value)) {
264+
$type = ArrayParameterType::toElementParameterType($typeName);
265+
return implode(', ', array_map($processParameterType($type), $value));
266+
}
267+
268+
throw new ValueNotConvertible($value, $typeName);
269+
}
270+
}
271+
272+
Then you may get raw SQL with:
273+
274+
.. code-block:: php
275+
276+
<?php
277+
$query
278+
->where('t.int IN (:ints)')->setParameter(':ints', [1, 2])
279+
->orWhere('t.string IN (?0)')->setParameter(0, ['3', '4'])
280+
->orWhere("t.bool = ?1")->setParameter('?1', true)
281+
->orWhere("t.string = :string")->setParameter(':string', 'ABC')
282+
->setHint(\Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER, InterpolateParametersSQLOutputWalker::class)
283+
->getSQL();
284+
285+
The where clause of returned SQL should be like:
286+
287+
.. code-block:: sql
288+
289+
WHERE t0_.int IN (1, 2)
290+
OR t0_.string IN ('3', '4')
291+
OR t0_.bool = 1
292+
OR t0_.string = 'ABC'

0 commit comments

Comments
 (0)