diff --git a/lib/Doctrine/ORM/QueryBuilder.php b/lib/Doctrine/ORM/QueryBuilder.php index 70b55f17d5c..93b4bb10477 100644 --- a/lib/Doctrine/ORM/QueryBuilder.php +++ b/lib/Doctrine/ORM/QueryBuilder.php @@ -118,6 +118,13 @@ class QueryBuilder */ private $joinRootAliases = []; + /** + * The map of query hints. + * + * @var array + */ + private $_hints = []; + /** * Whether to use second level cache, if available. * @@ -264,6 +271,55 @@ public function setCacheMode($cacheMode) return $this; } + /** + * Sets a query hint. + * + * @param string $name The name of the hint. + * @param mixed $value The value of the hint. + * + * @return self + */ + public function setHint($name, $value) + { + $this->_hints[$name] = $value; + + return $this; + } + + /** + * Gets the value of a query hint. If the hint name is not recognized, FALSE is returned. + * + * @param string $name The name of the hint. + * + * @return mixed The value of the hint or FALSE, if the hint name is not recognized. + */ + public function getHint($name) + { + return $this->_hints[$name] ?? false; + } + + /** + * Check if the query has a hint + * + * @param string $name The name of the hint + * + * @return bool False if the query does not have any hint + */ + public function hasHint($name) + { + return isset($this->_hints[$name]); + } + + /** + * Return the key value map of query hints that are currently set. + * + * @return array + */ + public function getHints() + { + return $this->_hints; + } + /** * Gets the type of the currently built query. * @@ -370,6 +426,12 @@ public function getQuery() $query->setCacheRegion($this->cacheRegion); } + if ($this->_hints) { + foreach ($this->_hints as $name => $value) { + $query->setHint($name, $value); + } + } + return $query; } diff --git a/tests/Doctrine/Tests/ORM/QueryBuilderTest.php b/tests/Doctrine/Tests/ORM/QueryBuilderTest.php index 7da2c663caa..7ee3e830bc5 100644 --- a/tests/Doctrine/Tests/ORM/QueryBuilderTest.php +++ b/tests/Doctrine/Tests/ORM/QueryBuilderTest.php @@ -1115,6 +1115,47 @@ public function testSecondLevelCacheQueryBuilderOptions() $this->assertEquals(Cache::MODE_REFRESH, $query->getCacheMode()); } + public function testQueryHints() + { + $defaultQueryBuilder = $this->_em->createQueryBuilder() + ->select('s') + ->from(State::class, 's'); + + $this->assertFalse($defaultQueryBuilder->hasHint('foo')); + $this->assertFalse($defaultQueryBuilder->getHint('foo')); + $this->assertEquals([], $defaultQueryBuilder->getHints()); + + $defaultQuery = $defaultQueryBuilder->getQuery(); + + $this->assertFalse($defaultQuery->hasHint('foo')); + + $builder = $this->_em->createQueryBuilder() + ->select('s') + ->from(State::class, 's') + ->setHint('foo', 'bar') + ->setHint('foo_reg', $value = new \stdClass()) + ; + + $this->assertTrue($builder->hasHint('foo')); + $this->assertTrue($builder->hasHint('foo_reg')); + $this->assertFalse($builder->hasHint('fool')); + $this->assertEquals(['foo' => 'bar', 'foo_reg' => $value], $builder->getHints()); + + $this->assertEquals('bar', $builder->getHint('foo')); + $this->assertEquals($value, $builder->getHint('foo_reg')); + $this->assertFalse($builder->getHint('fool')); + + $query = $builder->getQuery(); + + $this->assertTrue($query->hasHint('foo')); + $this->assertTrue($query->hasHint('foo_reg')); + $this->assertFalse($query->hasHint('fool')); + + $this->assertEquals('bar', $query->getHint('foo')); + $this->assertEquals($value, $query->getHint('foo_reg')); + $this->assertFalse($query->getHint('fool')); + } + /** * @group DDC-2253 */