Search code examples
symfonydql

DQL - leftJoin() error: Expected Literal, got 'JOIN'


This code:

$builder->select('p')
    ->from('ProProposalBundle:Proposal', 'p')
    ->leftJoin('ProProposalBundle:Proposal:Vote', 'v')
    ->leftJoin('ProUserBundle:User', 'u')
    ->andWhere('v.proposal = p')
    ->andWhere('v.user = u')
    ->andWhere('v.decision = "in_favor" OR v.decision = "against"')
    ->andWhere('u = :user')
    ->setParameter('user', $options['user'])
    ->andWhere('p.community = :community')
    ->setParameter('community', $community)
    ->andWhere('p.archived = :archived')
    ->setParameter('archived', $options['archived'])
    ->leftJoin('p.convocation', 'c')
    ->andWhere("p.convocation IS NULL OR c.status = '" . Convocation::STATUS_PENDING . "'");

    return $builder->getQuery()->execute();

is returning an error:

[Syntax Error] line 0, col 106: Error: Expected Literal, got 'JOIN'

This is the formed query:

SELECT p FROM ProProposalBundle:Proposal p LEFT JOIN ProProposalBundle:Proposal:Vote v LEFT JOIN ProUserBundle:User u LEFT JOIN p.convocation c WHERE v.proposal = p AND v.user = u AND (v.decision = "in_favor" OR v.decision = "against") AND u = :user AND p.community = :community AND (p.convocation IS NULL OR c.status = 'pending') ORDER BY p.created desc

LEFT JOIN is missing the ON or WITH condition. The question is: what am I doing wrong with DQL query? Am I wrong with leftJoin() method?


Solution

  • Doctrine ORM needs you to tell which relation is joined, not the entity itself (you did it well with p.convocation) :

    $builder->select('p')
        ->from('ProProposalBundle:Proposal', 'p')
        ->leftJoin('ProProposalBundle:Proposal\Vote', 'v', 'WITH', 'v.proposal = p AND v.user = :user AND (v.decision = :in_favor OR v.decision = :against)')
        ->setParameter('user', $options['user'])
        ->setParameter('in_favor', 'in_favor')
        ->setParameter('against', 'against')
        ->andWhere('p.community = :community')
        ->setParameter('community', $community)
        ->andWhere('p.archived = :archived')
        ->setParameter('archived', $options['archived'])
        ->leftJoin('p.convocation', 'c')
        ->andWhere("p.convocation IS NULL OR c.status = :pending")
        ->setParameter('pending', Convocation::STATUS_PENDING);
    
    return $builder->getQuery()->execute();
    

    edit: I inversed Vote relation as you commented and removed useless WHERE clauses (Doctrine automatically resolves JOIN ON clause. I also transferred some WHERE clauses about joins in the optional params (WITH in DQL).

    edit2: Without relation between Proposal and Vote, not sure it works.

    edit3: Best practice is to use setParameter for all values in WHERE clauses.