我找到了一些你肯定不喜欢的解决方案,但它确实有效。
基本上存在三个问题:
1. DOCTRINE 中不能有 WHERE (col1, col2)
2.您不能将数组数组作为参数传递(构建对)
3. 没有比较就不能有 where 表达式。
但是请检查我的解决方法。
扩展类:
/*
* This file is part of the Acme package.
*
* (c) Denis V.
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Acme\Bundle\AcmeBundle\Query;
use Doctrine\ORM\Query\AST\Functions\FunctionNode,
Doctrine\ORM\Query\Lexer,
Doctrine\ORM\Query\Parser,
Doctrine\ORM\Query\SqlWalker;
/**
* Class Pairs
*
* @author Denis V.
*
* @package Acme\Bundle\AcmeBundle\Query
*/
class Pairs extends FunctionNode
{
public $cols = array();
public $pathExp = array();
/**
* {@inheritdoc}
*/
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$lexer = $parser->getLexer();
// first Path Expression is mandatory
$this->pathExp = array();
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->cols[] = $parser->SingleValuedPathExpression();
while ($lexer->isNextToken(Lexer::T_COMMA)) {
$parser->match(Lexer::T_COMMA);
$this->cols[] = $parser->SingleValuedPathExpression();
}
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
$j = 1;
while ($lexer->isNextToken(Lexer::T_COMMA)) {
$parser->match(Lexer::T_COMMA);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->pathExp[$j] = array($parser->StringPrimary());
while ($lexer->isNextToken(Lexer::T_COMMA)) {
$parser->match(Lexer::T_COMMA);
$this->pathExp[$j][] = $parser->StringPrimary();
}
// commented out as it should be possible to accept array parameters
//if (count($this->cols) != count($this->pathExp[$j])) {
// $parser->semanticalError('Number of columns must be the same as number of compared values');
//}
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
$j++;
}
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
/**
* {@inheritdoc}
*/
public function getSql(SqlWalker $sqlWalker)
{
$fields = array();
foreach ($this->cols as $col) {
$fields[] = $col->dispatch($sqlWalker);
}
$result = sprintf('(%s)', implode(', ', $fields));
$result .= ' IN ';
$expr = array();
foreach ($this->pathExp as $pathExp) {
$fields = array();
foreach ($pathExp as $item) {
$fields[] = $item->dispatch($sqlWalker);
}
$expr[] = sprintf('(%s)', implode(', ', $fields));
}
$result .= sprintf('(%s)', implode(', ', $expr));
return $result;
}
}
现在您可以执行以下操作(假设您在实体存储库中):
$qb = $this
->createQueryBuilder('c')
->where('PAIRS((c.c1, c.c2), (:pair)) != \'dummy\'')
->setParameter('pair', array('val1', 'val2'));
$q = $qb->getQuery();
return $q;
您可能会注意到代码中有!= 'dummy'。这是因为你不能在没有比较的情况下传递 WHERE 表达式。我检查了一下,它实际上与 MySQL 一起工作。但您可以使用自定义 SqlWalker 将其删除。
要传递更多对,您需要使用循环,因为您不能将数组数组作为单个参数传递。
类似这样的:
$dqlParts = array();
foreach ($pairs as $i => $pair) {
$dqlParts[] = sprintf('(?%d)', $i);
$qb->setParameter($i, $pair);
}
$dqlPartsStr = implode(', ', $dqlParts);
然后在你的 DQL 中使用这个 $dqlPartsStr(注意:最后一个代码块是在 StackOverflow 上编写的,没有经过测试)。
我知道,这看起来更像是一个 hack,但这是您在 Doctrine2 中所能做的所有事情。如果您有任何问题,请告诉我。