added support for complex joins on query builder.
This commit is contained in:
parent
326b5929e9
commit
e88d2213ab
|
@ -147,9 +147,28 @@ public function select($columns = array('*'))
|
||||||
* @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 {
|
||||||
*/
|
*/
|
||||||
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 @@ final protected function components($query)
|
||||||
{
|
{
|
||||||
// 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 @@ final protected function concatenate($components)
|
||||||
*/
|
*/
|
||||||
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 @@ protected function joins(Query $query)
|
||||||
// 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);
|
||||||
|
|
||||||
$sql[] = "{$join['type']} JOIN {$table} ON {$column1} {$join['operator']} {$column2}";
|
$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 {$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 @@ final protected function wheres(Query $query)
|
||||||
*/
|
*/
|
||||||
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).')';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
<?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');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue