Skip to content

Commit

Permalink
Fix whereIn() with global scopes
Browse files Browse the repository at this point in the history
  • Loading branch information
staudenmeir committed Oct 20, 2018
1 parent 0245c61 commit 854594f
Show file tree
Hide file tree
Showing 4 changed files with 16 additions and 89 deletions.
70 changes: 6 additions & 64 deletions src/Illuminate/Database/Query/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -825,24 +825,15 @@ public function whereIn($column, $values, $boolean = 'and', $not = false)
{
$type = $not ? 'NotIn' : 'In';

if ($values instanceof EloquentBuilder) {
$values = $values->getQuery();
}

// If the value is a query builder instance we will assume the developer wants to
// look for any values that exists within this given query. So we will add the
// query accordingly so that this query is properly executed when it is run.
if ($values instanceof self) {
return $this->whereInExistingQuery(
$column, $values, $boolean, $not
);
}
if ($values instanceof self || $values instanceof EloquentBuilder || $values instanceof Closure) {
[$query, $bindings] = $this->createSub($values);

$values = [new Expression($query)];

// If the value of the where in clause is actually a Closure, we will assume that
// the developer is using a full sub-select for this "in" statement, and will
// execute those Closures, then we can re-construct the entire sub-selects.
if ($values instanceof Closure) {
return $this->whereInSub($column, $values, $boolean, $not);
$this->addBinding($bindings, 'where');
}

// Next, if the value is Arrayable we need to cast it to its raw array form so we
Expand All @@ -857,11 +848,7 @@ public function whereIn($column, $values, $boolean = 'and', $not = false)
// Finally we'll add a binding for each values unless that value is an expression
// in which case we will just skip over it since it will be the query as a raw
// string and not as a parameterized place-holder to be replaced by the PDO.
foreach ($values as $value) {
if (! $value instanceof Expression) {
$this->addBinding($value, 'where');
}
}
$this->addBinding($this->cleanBindings($values), 'where');

return $this;
}
Expand Down Expand Up @@ -903,51 +890,6 @@ public function orWhereNotIn($column, $values)
return $this->whereNotIn($column, $values, 'or');
}

/**
* Add a where in with a sub-select to the query.
*
* @param string $column
* @param \Closure $callback
* @param string $boolean
* @param bool $not
* @return $this
*/
protected function whereInSub($column, Closure $callback, $boolean, $not)
{
$type = $not ? 'NotInSub' : 'InSub';

// To create the exists sub-select, we will actually create a query and call the
// provided callback with the query so the developer may set any of the query
// conditions they want for the in clause, then we'll put it in this array.
call_user_func($callback, $query = $this->forSubQuery());

$this->wheres[] = compact('type', 'column', 'query', 'boolean');

$this->addBinding($query->getBindings(), 'where');

return $this;
}

/**
* Add an external sub-select to the query.
*
* @param string $column
* @param \Illuminate\Database\Query\Builder|static $query
* @param string $boolean
* @param bool $not
* @return $this
*/
protected function whereInExistingQuery($column, $query, $boolean, $not)
{
$type = $not ? 'NotInSub' : 'InSub';

$this->wheres[] = compact('type', 'column', 'query', 'boolean');

$this->addBinding($query->getBindings(), 'where');

return $this;
}

/**
* Add a "where null" clause to the query.
*
Expand Down
24 changes: 0 additions & 24 deletions src/Illuminate/Database/Query/Grammars/Grammar.php
Original file line number Diff line number Diff line change
Expand Up @@ -273,30 +273,6 @@ protected function whereNotIn(Builder $query, $where)
return '1 = 1';
}

/**
* Compile a where in sub-select clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereInSub(Builder $query, $where)
{
return $this->wrap($where['column']).' in ('.$this->compileSelect($where['query']).')';
}

/**
* Compile a where not in sub-select clause.
*
* @param \Illuminate\Database\Query\Builder $query
* @param array $where
* @return string
*/
protected function whereNotInSub(Builder $query, $where)
{
return $this->wrap($where['column']).' not in ('.$this->compileSelect($where['query']).')';
}

/**
* Compile a "where null" clause.
*
Expand Down
2 changes: 1 addition & 1 deletion src/Illuminate/Database/Query/JoinClause.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public function __construct(Builder $parentQuery, $type, $table)
*
* will produce the following SQL:
*
* on `contacts`.`user_id` = `users`.`id` and `contacts`.`info_id` = `info`.`id`
* on `contacts`.`user_id` = `users`.`id` and `contacts`.`info_id` = `info`.`id`
*
* @param \Closure|string $first
* @param string|null $operator
Expand Down
9 changes: 9 additions & 0 deletions tests/Database/DatabaseEloquentBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -989,6 +989,15 @@ public function testWhereKeyNotMethodWithCollection()
$builder->whereKeyNot($collection);
}

public function testWhereIn()
{
$model = new EloquentBuilderTestNestedStub;
$this->mockConnectionForModel($model, '');
$query = $model->newQuery()->withoutGlobalScopes()->whereIn('foo', $model->newQuery()->select('id'));
$expected = 'select * from "table" where "foo" in (select "id" from "table" where "table"."deleted_at" is null)';
$this->assertEquals($expected, $query->toSql());
}

public function testLatestWithoutColumnWithCreatedAt()
{
$model = $this->getMockModel();
Expand Down

0 comments on commit 854594f

Please sign in to comment.