[sql] Doctrine query builder using inner join with conditions

I'd like to construct the following SQL using Doctrine's query builder:

select c.*
from customer c
join phone p
on p.customer_id = c.id
and p.phone = :phone
where c.username = :username

First I tried

$qb->select('c')
    ->innerJoin('c.phones', 'p', Join::ON, $qb->expr()->andx(
        $qb->expr()->eq('p.customerId', 'c.id'),
        $qb->expr()->eq('p.phone', ':phone')
    ))
    ->where('c.username = :username');

But I'm getting the following error

Error: expected end of string, got 'ON'

Then I tried

$qb->select('c')
    ->innerJoin('c.phones', 'p')
    ->where('c.username = :username')
    ->andWhere('p.phone = :phone');

which seems to be working. However, does anyone know what's wrong with the first attempt? I'd like to make the first one work since it resembles more closely to how SQL is structured. Thanks in advance!

Note: I know we can also write native mysql or dql with Doctrine, but I'd prefer query builder.

EDIT: Below is the entire code

namespace Cyan\CustomerBundle\Repository;

use Cyan\CustomerBundle\Entity\Customer;
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Query\Expr\Join;

class CustomerRepository extends EntityRepository
{
    public function findCustomerByPhone($username, $phone)
    {
        $qb = $this->createQueryBuilder('c');

        $qb->select('c')
            ->innerJoin('c.phones', 'p', Join::ON, $qb->expr()->andx(
                $qb->expr()->eq('p.customerId', 'c.id'),
                $qb->expr()->eq('p.phone', ':phone')
            ))
            ->where('c.username = :username');

//        $qb->select('c')
//            ->innerJoin('c.phones', 'p')
//            ->where('c.username = :username')
//            ->andWhere('p.phone = :phone');

        $qb->setParameters(array(
            'username' => $username,
            'phone' => $phone->getPhone(),
        ));

        $query = $qb->getQuery();
        return $query->getResult();
    }
}

This question is related to sql symfony doctrine-orm

The answer is


I'm going to answer my own question.

  1. innerJoin should use the keyword "WITH" instead of "ON" (Doctrine's documentation [13.2.6. Helper methods] is inaccurate; [13.2.5. The Expr class] is correct)
  2. no need to link foreign keys in join condition as they're already specified in the entity mapping.

Therefore, the following works for me

$qb->select('c')
    ->innerJoin('c.phones', 'p', 'WITH', 'p.phone = :phone')
    ->where('c.username = :username');

or

$qb->select('c')
    ->innerJoin('c.phones', 'p', Join::WITH, $qb->expr()->eq('p.phone', ':phone'))
    ->where('c.username = :username');

You can explicitly have a join like this:

$qb->innerJoin('c.phones', 'p', Join::ON, 'c.id = p.customerId');

But you need to use the namespace of the class Join from doctrine:

use Doctrine\ORM\Query\Expr\Join;

Or if you prefere like that:

$qb->innerJoin('c.phones', 'p', Doctrine\ORM\Query\Expr\Join::ON, 'c.id = p.customerId');

Otherwise, Join class won't be detected and your script will crash...

Here the constructor of the innerJoin method:

public function innerJoin($join, $alias, $conditionType = null, $condition = null);

You can find other possibilities (not just join "ON", but also "WITH", etc...) here: http://docs.doctrine-project.org/en/2.0.x/reference/query-builder.html#the-expr-class

EDIT

Think it should be:

$qb->select('c')
    ->innerJoin('c.phones', 'p', Join::ON, 'c.id = p.customerId')
    ->where('c.username = :username')
    ->andWhere('p.phone = :phone');

    $qb->setParameters(array(
        'username' => $username,
        'phone' => $phone->getPhone(),
    ));

Otherwise I think you are performing a mix of ON and WITH, perhaps the problem.


Examples related to sql

Passing multiple values for same variable in stored procedure SQL permissions for roles Generic XSLT Search and Replace template Access And/Or exclusions Pyspark: Filter dataframe based on multiple conditions Subtracting 1 day from a timestamp date PYODBC--Data source name not found and no default driver specified select rows in sql with latest date for each ID repeated multiple times ALTER TABLE DROP COLUMN failed because one or more objects access this column Create Local SQL Server database

Examples related to symfony

Warning: "continue" targeting switch is equivalent to "break". Did you mean to use "continue 2"? Composer require runs out of memory. PHP Fatal error: Allowed memory size of 1610612736 bytes exhausted SQLSTATE[HY000] [1045] Access denied for user 'root'@'localhost' (using password: YES) symfony2 The CSRF token is invalid. Please try to resubmit the form What is the difference between .yaml and .yml extension? How can I use break or continue within for loop in Twig template? Running Composer returns: "Could not open input file: composer.phar" Symfony2 and date_default_timezone_get() - It is not safe to rely on the system's timezone settings Symfony - generate url with parameter in controller Call PHP function from Twig template

Examples related to doctrine-orm

How to sort findAll Doctrine's method? Doctrine query builder using inner join with conditions How to do left join in Doctrine? How to use a findBy method with comparative criteria The EntityManager is closed Doctrine findBy 'does not equal' How to order results with findBy() in Doctrine Select entries between dates in doctrine 2 Get single row result with Doctrine NativeQuery Count Rows in Doctrine QueryBuilder