How should I go about ordering by a discriminator column in a doctrine repository query?
I have a pretty straight forward setup, I have different types of payment detai
Can your try to use TYPE()
or INSTANCE OF
?
related: https://groups.google.com/forum/#!topic/doctrine-user/JtCbwuN-37o
However, this topic doesn't say if it is implemented or not. At the time it was written someone said order by wouldn't work.
$dql = 'SELECT pd
from
AccountingBundle:PaymentDetail pd
JOIN ClientProductBundle:ClientProduct cp
WITH cp.payment_detail_id = pd.id
WHERE
cp.payment_detail_id = pd.id
and cp.client_contact_id = :client_contact_id
GROUP BY pd.id
ORDER BY TYPE(pd)';
Even though TYPE is not implemented yet into the core of doctrine it's still possible to implement it as a custom user function.
Someone already did an amazing job and implemented it for us. Just in case the resource will be removed in the future, here is a slightly adjusted version for php7+:
<?php
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\QueryException;
use Doctrine\ORM\Query\SqlWalker;
class TypeFunction extends FunctionNode
{
/**
* @var string
*/
public $dqlAlias;
public function getSql(SqlWalker $sqlWalker): string
{
/** @var ClassMetadataInfo $class */
$class = $sqlWalker->getQueryComponent($this->dqlAlias)['metadata'];
$tableAlias = $sqlWalker->getSQLTableAlias($class->getTableName(), $this->dqlAlias);
if (!isset($class->discriminatorColumn['name'])) {
$message = 'TYPE() only supports entities with a discriminator column.';
throw QueryException::semanticalError($message);
}
return $tableAlias . '.' . $class->discriminatorColumn['name'];
}
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->dqlAlias = $parser->IdentificationVariable();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
}
Now you can order by the discriminator column by doing something like:
SELECT e, TYPE(e) AS HIDDEN my_type FROM Entity e ORDER BY my_type DESC;
It seems like the simplest solution (so far) is to add another field to the base class and copy the discriminator column value.
The aforementioned TYPE(q)
works only in WHERE clause.