Commit e88d2213 authored by Taylor Otwell's avatar Taylor Otwell

added support for complex joins on query builder.

parent 326b5929
...@@ -147,9 +147,28 @@ class Query { ...@@ -147,9 +147,28 @@ class Query {
* @param string $type * @param string $type
* @return Query * @return Query
*/ */
public function join($table, $column1, $operator, $column2, $type = 'INNER') public function join($table, $column1, $operator = null, $column2 = null, $type = 'INNER')
{ {
$this->joins[] = compact('type', 'table', 'column1', 'operator', 'column2'); // If the "column" is really an instance of a Closure, the developer is
// trying to create a join with a complex "ON" clause. So, we will add
// the join, and then call the Closure with the join.
if ($column1 instanceof Closure)
{
$this->joins[] = new Query\Join($type, $table);
call_user_func($column1, end($this->joins));
}
// If the column is just a string, we can assume that the join just
// has a simple on clause, and we'll create the join instance and
// add the clause automatically for the develoepr.
else
{
$join = new Query\Join($type, $table);
$join->on($column1, $operator, $column2);
$this->joins[] = $join;
}
return $this; return $this;
} }
......
...@@ -23,7 +23,7 @@ class Grammar extends \Laravel\Database\Grammar { ...@@ -23,7 +23,7 @@ class Grammar extends \Laravel\Database\Grammar {
*/ */
public function select(Query $query) public function select(Query $query)
{ {
return $this->concatenate($this->components($query)); die(var_dump($this->concatenate($this->components($query))));
} }
/** /**
...@@ -36,12 +36,11 @@ class Grammar extends \Laravel\Database\Grammar { ...@@ -36,12 +36,11 @@ class Grammar extends \Laravel\Database\Grammar {
{ {
// Each portion of the statement is compiled by a function corresponding // Each portion of the statement is compiled by a function corresponding
// to an item in the components array. This lets us to keep the creation // to an item in the components array. This lets us to keep the creation
// of the query very granular, and allows for the flexible customization // of the query very granular and very flexible.
// of the query building process by each database system's grammar.
// //
// Note that each component also corresponds to a public property on the // Note that each component also connects to a public property on the
// query instance, allowing us to pass the appropriate data into each of // query instance, allowing us to pass the correct data into each
// the compiler functions. // of the compiler functions.
foreach ($this->components as $component) foreach ($this->components as $component)
{ {
if ( ! is_null($query->$component)) if ( ! is_null($query->$component))
...@@ -75,10 +74,6 @@ class Grammar extends \Laravel\Database\Grammar { ...@@ -75,10 +74,6 @@ class Grammar extends \Laravel\Database\Grammar {
*/ */
protected function selects(Query $query) protected function selects(Query $query)
{ {
// Sometimes developers may set a "select" clause on the same query
// that is performing in aggregate look-up, like during pagination.
// So we will not generate the select clause if an aggregate is
// present so the aggregates work.
if ( ! is_null($query->aggregate)) return; if ( ! is_null($query->aggregate)) return;
$select = ($query->distinct) ? 'SELECT DISTINCT ' : 'SELECT '; $select = ($query->distinct) ? 'SELECT DISTINCT ' : 'SELECT ';
...@@ -129,15 +124,40 @@ class Grammar extends \Laravel\Database\Grammar { ...@@ -129,15 +124,40 @@ class Grammar extends \Laravel\Database\Grammar {
// set of joins in valid SQL that can appended to the query. // set of joins in valid SQL that can appended to the query.
foreach ($query->joins as $join) foreach ($query->joins as $join)
{ {
$table = $this->wrap_table($join['table']); $table = $this->wrap_table($join->table);
$column1 = $this->wrap($join['column1']); $clauses = array();
$column2 = $this->wrap($join['column2']); // Each JOIN statement may have multiple clauses, so we will
// iterate through each clause creating the conditions then
// we will concatenate them all together.
foreach ($join->clauses as $clause)
{
extract($clause);
$column1 = $this->wrap($column1);
$column2 = $this->wrap($column2);
$clauses[] = "{$connector} {$column1} {$operator} {$column2}";
}
// The first clause will have a connector on the front,
// but it is not needed on the first condition, so we
// will strip it off of the condition before adding
// it to the array of joins.
$search = array('AND ', 'OR ');
$clauses[0] = str_replace($search, '', $clauses[0]);
$clauses = implode(' ', $clauses);
$sql[] = "{$join['type']} JOIN {$table} ON {$column1} {$join['operator']} {$column2}"; $sql[] = "{$join->type} JOIN {$table} ON {$clauses}";
} }
// Finally, we should have an array of JOIN clauses
// that we can implode together and return as the
// complete SQL for the JOIN of the query.
return implode(' ', $sql); return implode(' ', $sql);
} }
...@@ -180,10 +200,6 @@ class Grammar extends \Laravel\Database\Grammar { ...@@ -180,10 +200,6 @@ class Grammar extends \Laravel\Database\Grammar {
*/ */
protected function where_nested($where) protected function where_nested($where)
{ {
// To generate a nested WHERE clause, we'll just feed the query
// back into the "wheres" method. Once we have the clause, we
// will strip off the first six characters to get rid of the
// leading WHERE keyword.
return '('.substr($this->wheres($where['query']), 6).')'; return '('.substr($this->wheres($where['query']), 6).')';
} }
......
<?php namespace Laravel\Database\Query;
class Join {
/**
* The type of join being performed.
*
* @var string
*/
public $type;
/**
* The table the join clause is joining to.
*
* @var string
*/
public $table;
/**
* The ON clauses for the join.
*
* @var array
*/
public $clauses = array();
/**
* Create a new query join instance.
*
* @param string $type
* @param string $table
* @return void
*/
public function __construct($type, $table)
{
$this->type = $type;
$this->table = $table;
}
/**
* Add an ON clause to the join.
*
* @param string $column1
* @param string $operator
* @param string $column2
* @param string $connector
* @return Join
*/
public function on($column1, $operator, $column2, $connector = 'AND')
{
$this->clauses[] = compact('column1', 'operator', 'column2', 'connector');
return $this;
}
/**
* Add an OR ON clause to the join.
*
* @param string $column1
* @param string $operator
* @param string $column2
* @return Join
*/
public function or_on($column1, $operator, $column2)
{
return $this->on($column1, $operator, $column2, 'OR');
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment