Skip to content

Commit

Permalink
Added joinWhere, leftJoinWhere for building where clauses with bindings.
Browse files Browse the repository at this point in the history
  • Loading branch information
taylorotwell committed Nov 2, 2013
1 parent 9a8faca commit a644ea0
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 13 deletions.
61 changes: 52 additions & 9 deletions src/Illuminate/Database/Query/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -221,37 +221,53 @@ public function from($table)
* @param string $table
* @param string $first
* @param string $operator
* @param string $second
* @param string $two
* @param string $type
* @param bool $where
* @return \Illuminate\Database\Query\Builder|static
*/
public function join($table, $first, $operator = null, $second = null, $type = 'inner')
public function join($table, $one, $operator = null, $two = null, $type = 'inner', $where = false)
{
// If the first "column" of the join is really a Closure instance the developer
// is trying to build a join with a complex "on" clause containing more than
// one condition, so we'll add the join and call a Closure with the query.
if ($first instanceof Closure)
if ($one instanceof Closure)
{
$this->joins[] = new JoinClause($type, $table);
$this->joins[] = new JoinClause($this, $type, $table);

call_user_func($first, end($this->joins));
call_user_func($one, end($this->joins));
}

// If the column is simply a string, we can assume the join simply has a basic
// "on" clause with a single condition. So we will just build the join with
// this simple join clauses attached to it. There is not a join callback.
else
{
$join = new JoinClause($type, $table);

$join->on($first, $operator, $second);
$join = new JoinClause($this, $type, $table);

$this->joins[] = $join;
$this->joins[] = $join->on(
$one, $operator, $two, 'and', $where
);
}

return $this;
}

/**
* Add a "join where" clause to the query.
*
* @param string $table
* @param string $first
* @param string $operator
* @param string $two
* @param string $type
* @return \Illuminate\Database\Query\Builder|static
*/
public function joinWhere($table, $one, $operator, $two, $type = 'inner')
{
return $this->join($table, $one, $operator, $two, $type, true);
}

/**
* Add a left join to the query.
*
Expand All @@ -266,6 +282,20 @@ public function leftJoin($table, $first, $operator = null, $second = null)
return $this->join($table, $first, $operator, $second, 'left');
}

/**
* Add a "join where" clause to the query.
*
* @param string $table
* @param string $first
* @param string $operator
* @param string $two
* @return \Illuminate\Database\Query\Builder|static
*/
public function leftJoinWhere($table, $one, $operator, $two)
{
return $this->joinWhere($table, $one, $operator, $two, 'left');
}

/**
* Add a basic where clause to the query.
*
Expand Down Expand Up @@ -1645,6 +1675,19 @@ public function setBindings(array $bindings)
return $this;
}

/**
* Add a binding to the query.
*
* @param mixed $value
* @return \Illuminate\Database\Query\Builder
*/
public function addBinding($value)
{
$this->bindings[] = $value;

return $this;
}

/**
* Merge an array of bindings into our bindings.
*
Expand Down
2 changes: 1 addition & 1 deletion src/Illuminate/Database/Query/Grammars/Grammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ protected function compileJoinConstraint(array $clause)
{
$first = $this->wrap($clause['first']);

$second = $this->wrap($clause['second']);
$second = $clause['where'] ? '?' : $this->wrap($clause['second']);

return "{$clause['boolean']} $first {$clause['operator']} $second";
}
Expand Down
46 changes: 43 additions & 3 deletions src/Illuminate/Database/Query/JoinClause.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

class JoinClause {

/**
* The query builder instance.
*
* @var \Illuminate\Database\Query\Builder
*/
public $query;

/**
* The type of join being performed.
*
Expand All @@ -26,13 +33,15 @@ class JoinClause {
/**
* Create a new join clause instance.
*
* @param \Illuminate\Database\Query\Builder $query
* @param string $type
* @param string $table
* @return void
*/
public function __construct($type, $table)
public function __construct(Builder $query, $type, $table)
{
$this->type = $type;
$this->query = $query;
$this->table = $table;
}

Expand All @@ -43,11 +52,14 @@ public function __construct($type, $table)
* @param string $operator
* @param string $second
* @param string $boolean
* @param bool $where
* @return \Illuminate\Database\Query\JoinClause
*/
public function on($first, $operator, $second, $boolean = 'and')
public function on($first, $operator, $second, $boolean = 'and', $where = false)
{
$this->clauses[] = compact('first', 'operator', 'second', 'boolean');
$this->clauses[] = compact('first', 'operator', 'second', 'boolean', 'where');

if ($where) $this->query->addBinding($second);

return $this;
}
Expand All @@ -65,4 +77,32 @@ public function orOn($first, $operator, $second)
return $this->on($first, $operator, $second, 'or');
}

/**
* Add an "on where" clause to the join.
*
* @param string $first
* @param string $operator
* @param string $second
* @param string $boolean
* @return \Illuminate\Database\Query\JoinClause
*/
public function where($first, $operator, $second, $boolean = 'and')
{
return $this->on($first, $operator, $second, $boolean, true);
}

/**
* Add an "or on where" clause to the join.
*
* @param string $first
* @param string $operator
* @param string $second
* @param string $boolean
* @return \Illuminate\Database\Query\JoinClause
*/
public function orWhere($first, $operator, $second)
{
return $this->on($first, $operator, $second, 'or', true);
}

}
13 changes: 13 additions & 0 deletions tests/Database/DatabaseQueryBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,11 @@ public function testBasicJoins()
$builder = $this->getBuilder();
$builder->select('*')->from('users')->join('contacts', 'users.id', '=', 'contacts.id')->leftJoin('photos', 'users.id', '=', 'photos.id');
$this->assertEquals('select * from "users" inner join "contacts" on "users"."id" = "contacts"."id" left join "photos" on "users"."id" = "photos"."id"', $builder->toSql());

$builder = $this->getBuilder();
$builder->select('*')->from('users')->leftJoinWhere('photos', 'users.id', '=', 'bar')->joinWhere('photos', 'users.id', '=', 'foo');
$this->assertEquals('select * from "users" left join "photos" on "users"."id" = ? inner join "photos" on "users"."id" = ?', $builder->toSql());
$this->assertEquals(array('bar', 'foo'), $builder->getBindings());
}


Expand All @@ -399,6 +404,14 @@ public function testComplexJoin()
$j->on('users.id', '=', 'contacts.id')->orOn('users.name', '=', 'contacts.name');
});
$this->assertEquals('select * from "users" inner join "contacts" on "users"."id" = "contacts"."id" or "users"."name" = "contacts"."name"', $builder->toSql());

$builder = $this->getBuilder();
$builder->select('*')->from('users')->join('contacts', function($j)
{
$j->where('users.id', '=', 'foo')->orWhere('users.name', '=', 'bar');
});
$this->assertEquals('select * from "users" inner join "contacts" on "users"."id" = ? or "users"."name" = ?', $builder->toSql());
$this->assertEquals(array('foo', 'bar'), $builder->getBindings());
}


Expand Down

0 comments on commit a644ea0

Please sign in to comment.