Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using `DATE()` in Doctrine Querybuilder

I need to get all rows where DATE(a.when) matches the string 2014-09-30.

$builder = $this->em->createQueryBuilder();
$builder->select('a')
        ->from('Entity\Appointment', 'a')
        ->andWhere('a.when = :date')
        ->setParameter('date', $date);

a.when is a full DATETIME; :date is only a string (in DATE format).

The following and variations didn't work:

        ->andWhere('DATE(a.when) = :date')

Error: Expected known function, got 'DATE'

What's the correct usage here?

like image 292
Daniel W. Avatar asked Sep 23 '14 14:09

Daniel W.


3 Answers

This actually is a very common question. It turns out that not all sql databases support a DATE function, so the good people in charge of Doctrine decided not to support it nativelly.

Kind of wish they did because it would have saved a bunch of people a fair amount of effort.

So add this rather magical class to your project:

namespace Cerad\Bundle\CoreBundle\Doctrine\DQL;

use Doctrine\ORM\Query\Lexer;
use Doctrine\ORM\Query\AST\Functions\FunctionNode;

class Date extends FunctionNode
{
    public $date;

    public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker)
    {
        return "DATE(" . $sqlWalker->walkArithmeticPrimary($this->date) . ")";
    }
    public function parse(\Doctrine\ORM\Query\Parser $parser)
    {
        $parser->match(Lexer::T_IDENTIFIER);
        $parser->match(Lexer::T_OPEN_PARENTHESIS);

        $this->date = $parser->ArithmeticPrimary();

        $parser->match(Lexer::T_CLOSE_PARENTHESIS);
    }
}

Then wire it up in the doctrine section of your app/config.yml:

doctrine:
  orm:
  default_entity_manager:       default
  auto_generate_proxy_classes: %kernel.debug%

  entity_managers:

    default:
      connection: default
      ...
      dql:
        datetime_functions:
          date:  Cerad\Bundle\CoreBundle\Doctrine\DQL\Date

http://doctrine-orm.readthedocs.org/en/latest/cookbook/dql-user-defined-functions.html http://symfony.com/doc/current/cookbook/doctrine/custom_dql_functions.html http://symfony.com/doc/current/reference/configuration/doctrine.html

There are other bundles out there with more sql functions. Oddly enough, the first time I looked a few years ago, none of them had Date defined. So I just made my own.

====================================================================

Update 01

I did not check the tags carefully and assumed that this was a Symfony 2 application. The Date class stays the same. You wire it up by getting the doctrine configuration object.

$config = new \Doctrine\ORM\Configuration();
$config->addCustomDatetimeFunction('DATE', 'blahblah\Date');

Check the Doctrine link for details.

like image 87
Cerad Avatar answered Oct 10 '22 03:10

Cerad


A different approach using $qb->expr()->between() in the same andWhere:


    $builder = $this->em->createQueryBuilder(); $builder->select('a')
                ->from('Entity\Appointment', 'a')
                ->andWhere($qb->expr()->between('a.when', ':date_start', ':date_end'))
                ->setParameter('date_start', $date->format('Y-m-d 00:00:00'))
                ->setParameter('date_end',   $date->format('Y-m-d 23:59:59'));

like image 33
Leandro Neves Avatar answered Oct 10 '22 05:10

Leandro Neves


Thanks to andy, using this now:

$builder = $this->em->createQueryBuilder();
$builder->select('a')
        ->from('Entity\Appointment', 'a')
        ->andWhere('a.when >= :date_start')
        ->andWhere('a.when <= :date_end')
        ->setParameter('date_start', $date->format('Y-m-d 00:00:00'))
        ->setParameter('date_end',   $date->format('Y-m-d 23:59:59'));
like image 15
Daniel W. Avatar answered Oct 10 '22 04:10

Daniel W.