Есть БД: "ID, данные1, данные2,..., дата создания, дата публикации"
Новые записи ждут, когда модератор прочитает их и выставит дату публикации из NULL в конкретное значение.
Обычный юзер, заходя на страницу, видит список записей отсортированных по дате публикации порядке убывания (новые сверху).
Модератор же, перед этим списком должен видеть все новые записи (с датой публикации = NULL, отсортированные в по дате создания ).
Все это надо сделать в доктрине 2.4.х Никаких native sql - только хардкор, только ORM.
$qb = $this->getEntityManager()->createQueryBuilder();
$qb->select('q')
->from(Question::getClass(), 'q');
Решение:
Заводим кастомную FunctionNode'у.
namespace MyApp\Doctrine\General;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\Parser;
use Doctrine\ORM\Query\SqlWalker;
/**
* DateDiffFunction ::= "ISNULL" "(" ArithmeticPrimary ")"
*/
class IsNullFunctionNode extends FunctionNode
{
private $isnull;
public function parse(Parser $parser)
{
$parser->match(Lexer::T_IDENTIFIER);
$parser->match(Lexer::T_OPEN_PARENTHESIS);
$this->isnull = $parser->ArithmeticPrimary();
$parser->match(Lexer::T_CLOSE_PARENTHESIS);
}
public function getSql(SqlWalker $sqlWalker)
{
return 'ISNULL('.$this->isnull->dispatch($sqlWalker).')';
}
}
Подключаем её в конфиге или инициализаторе доктрины:
$config = new Configuration();
$config->addCustomNumericFunction('ISNULL', 'MyApp\Doctrine\General\IsNullFunctionNode');
В QueryBuilder добавляем HIDDEN селект:
$qb->addSelect('ISNULL(q.publishDate) AS HIDDEN ord');
И туда же сортировки:
$qb->orderBy('ord','DESC')
->addOrderBy('q.publishDate', 'DESC')
->addOrderBy('q.createdDate', 'DESC');
На финише получаем SQL'ку:
SELECT a0_.id AS id0, a0_.created_date AS created_date1, a0_.updated_date AS updated_date2, a0_.publish_date AS publish_date3, ISNULL(a0_.publish_date) AS sclr15
FROM question a0_
ORDER BY sclr15 DESC, a0_.publish_date DESC, a0_.created_date DESC
Конструкция такого вида, работать не будет:
->orderBy('ISNULL(q.createdDate)', 'DESC');
Весь трюк в HIDDEN селекте. HIDDEN - указывает на то, что бы данные собирались но не внедрялись в запрашиваемую сущность. Но это поле можно использовать для сортировки, что и сделано в примере. Еще
пример можно посмотреть тут и
ограниченно вредный пример тут.
That's all folks!