1
0
mirror of synced 2025-02-02 13:31:45 +03:00

Note: this will still lead to the UnitOfWork#getSingleIdentifierValue() still being

called when not specifying the type of a DQL parameter being bound via
`Doctrine\ORM\Query#setParameter()`:

```php
$query->setParameter('foo', $theValue, $theType);
```

A full parameter bind is required in order to gain back performance:

```php
$query->setParameter('foo', $theValue, $theType);
```

This is up for discussion with patch reviewers.
This commit is contained in:
Marco Pivetta 2018-12-16 16:20:26 +01:00
parent 960a437d46
commit 23af164d7a
4 changed files with 63 additions and 23 deletions

View File

@ -72,7 +72,7 @@ abstract class AbstractQuery
/**
* The parameter map of this query.
*
* @var \Doctrine\Common\Collections\ArrayCollection
* @var ArrayCollection|Parameter[]
*/
protected $parameters;
@ -306,7 +306,7 @@ abstract class AbstractQuery
/**
* Get all defined parameters.
*
* @return \Doctrine\Common\Collections\ArrayCollection The defined query parameters.
* @return ArrayCollection The defined query parameters.
*/
public function getParameters()
{
@ -336,7 +336,7 @@ abstract class AbstractQuery
/**
* Sets a collection of query parameters.
*
* @param \Doctrine\Common\Collections\ArrayCollection|array $parameters
* @param ArrayCollection|mixed[] $parameters
*
* @return static This query instance.
*/

View File

@ -19,15 +19,18 @@
namespace Doctrine\ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\DBAL\LockMode;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Query\Exec\AbstractSqlExecutor;
use Doctrine\ORM\Query\Parameter;
use Doctrine\ORM\Query\ParameterTypeInferer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\ParserResult;
use Doctrine\ORM\Query\QueryException;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Query\ParameterTypeInferer;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Utility\HierarchyDiscriminatorResolver;
use function array_keys;
use function assert;
/**
* A Query object represents a DQL query.
@ -387,26 +390,13 @@ final class Query extends AbstractQuery
$types = [];
foreach ($this->parameters as $parameter) {
$key = $parameter->getName();
$value = $parameter->getValue();
$rsm = $this->getResultSetMapping();
$key = $parameter->getName();
if ( ! isset($paramMappings[$key])) {
throw QueryException::unknownParameter($key);
}
if (isset($rsm->metadataParameterMapping[$key]) && $value instanceof ClassMetadata) {
$value = $value->getMetadataValue($rsm->metadataParameterMapping[$key]);
}
if (isset($rsm->discriminatorParameters[$key]) && $value instanceof ClassMetadata) {
$value = array_keys(HierarchyDiscriminatorResolver::resolveDiscriminatorsForClass($value, $this->_em));
}
$value = $this->processParameterValue($value);
$type = ($parameter->getValue() === $value)
? $parameter->getType()
: ParameterTypeInferer::inferType($value);
[$value, $type] = $this->resolveParameterValue($parameter);
foreach ($paramMappings[$key] as $position) {
$types[$position] = $type;
@ -439,6 +429,38 @@ final class Query extends AbstractQuery
return [$sqlParams, $types];
}
/** @return mixed[] tuple of (value, type) */
private function resolveParameterValue(Parameter $parameter) : array
{
if ($parameter->typeWasSpecified()) {
return [$parameter->getValue(), $parameter->getType()];
}
$key = $parameter->getName();
$originalValue = $parameter->getValue();
$value = $originalValue;
$rsm = $this->getResultSetMapping();
assert($rsm !== null);
if ($value instanceof ClassMetadata && isset($rsm->metadataParameterMapping[$key])) {
$value = $value->getMetadataValue($rsm->metadataParameterMapping[$key]);
}
if ($value instanceof ClassMetadata && isset($rsm->discriminatorParameters[$key])) {
$value = array_keys(HierarchyDiscriminatorResolver::resolveDiscriminatorsForClass($value, $this->_em));
}
$processedValue = $this->processParameterValue($value);
return [
$processedValue,
$originalValue === $processedValue
? $parameter->getType()
: ParameterTypeInferer::inferType($processedValue),
];
}
/**
* Defines a cache driver to be used for caching queries.
*

View File

@ -19,6 +19,8 @@
namespace Doctrine\ORM\Query;
use function trim;
/**
* Defines a Query Parameter.
*
@ -49,6 +51,13 @@ class Parameter
*/
private $type;
/**
* Whether the parameter type was explicitly specified or not
*
* @var bool
*/
private $typeSpecified;
/**
* Constructor.
*
@ -58,7 +67,8 @@ class Parameter
*/
public function __construct($name, $value, $type = null)
{
$this->name = trim($name, ':');
$this->name = trim($name, ':');
$this->typeSpecified = $type !== null;
$this->setValue($value, $type);
}
@ -104,4 +114,9 @@ class Parameter
$this->value = $value;
$this->type = $type ?: ParameterTypeInferer::inferType($value);
}
public function typeWasSpecified() : bool
{
return $this->typeSpecified;
}
}

View File

@ -609,8 +609,11 @@ class QueryBuilderTest extends OrmTestCase
->setParameter('id', 1);
$parameter = new Parameter('id', 1, ParameterTypeInferer::inferType(1));
$inferred = $qb->getParameter('id');
$this->assertEquals($parameter, $qb->getParameter('id'));
self::assertSame($parameter->getValue(), $inferred->getValue());
self::assertSame($parameter->getType(), $inferred->getType());
self::assertFalse($inferred->typeWasSpecified());
}
public function testSetParameters()