Skip to content

Commit

Permalink
Fix HasManyThrough existence queries with same parent and through par…
Browse files Browse the repository at this point in the history
…ent table (#26676)
  • Loading branch information
staudenmeir authored and taylorotwell committed Nov 30, 2018
1 parent fdc00c1 commit d0cf02d
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 1 deletion.
29 changes: 28 additions & 1 deletion src/Illuminate/Database/Eloquent/Relations/HasManyThrough.php
Original file line number Diff line number Diff line change
Expand Up @@ -480,10 +480,14 @@ protected function prepareQueryBuilder($columns = ['*'])
*/
public function getRelationExistenceQuery(Builder $query, Builder $parentQuery, $columns = ['*'])
{
if ($parentQuery->getQuery()->from == $query->getQuery()->from) {
if ($parentQuery->getQuery()->from === $query->getQuery()->from) {
return $this->getRelationExistenceQueryForSelfRelation($query, $parentQuery, $columns);
}

if ($parentQuery->getQuery()->from === $this->throughParent->getTable()) {
return $this->getRelationExistenceQueryForThroughSelfRelation($query, $parentQuery, $columns);
}

$this->performJoin($query);

return $query->select($columns)->whereColumn(
Expand Down Expand Up @@ -516,6 +520,29 @@ public function getRelationExistenceQueryForSelfRelation(Builder $query, Builder
);
}

/**
* Add the constraints for a relationship query on the same table as the through parent.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @param \Illuminate\Database\Eloquent\Builder $parentQuery
* @param array|mixed $columns
* @return \Illuminate\Database\Eloquent\Builder
*/
public function getRelationExistenceQueryForThroughSelfRelation(Builder $query, Builder $parentQuery, $columns = ['*'])
{
$table = $this->throughParent->getTable().' as '.$hash = $this->getRelationCountHash();

$query->join($table, $hash.'.'.$this->secondLocalKey, '=', $this->getQualifiedFarKeyName());

if ($this->throughParentSoftDeletes()) {
$query->whereNull($hash.'.'.$this->throughParent->getDeletedAtColumn());
}

return $query->select($columns)->whereColumn(
$parentQuery->getQuery()->from.'.'.$this->localKey, '=', $hash.'.'.$this->firstKey
);
}

/**
* Get a relationship join table hash.
*
Expand Down
46 changes: 46 additions & 0 deletions tests/Integration/Database/EloquentHasManyThroughTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Tests\Integration\Database\DatabaseTestCase;

/**
Expand All @@ -27,6 +28,17 @@ public function setUp()
$table->integer('owner_id')->nullable();
$table->string('owner_slug')->nullable();
});

Schema::create('categories', function ($table) {
$table->increments('id');
$table->integer('parent_id')->nullable();
$table->softDeletes();
});

Schema::create('products', function ($table) {
$table->increments('id');
$table->integer('category_id');
});
}

public function test_basic_create_and_retrieve()
Expand Down Expand Up @@ -83,6 +95,21 @@ public function test_has_self_custom_owner_key()

$this->assertEquals(1, $users->count());
}

public function test_has_same_parent_and_through_parent_table()
{
Category::create();
Category::create();
Category::create(['parent_id' => 1]);
Category::create(['parent_id' => 2])->delete();

Product::create(['category_id' => 3]);
Product::create(['category_id' => 4]);

$categories = Category::has('subProducts')->get();

$this->assertEquals([1], $categories->pluck('id')->all());
}
}

class User extends Model
Expand Down Expand Up @@ -129,3 +156,22 @@ class Team extends Model
public $timestamps = false;
protected $guarded = [];
}

class Category extends Model
{
use SoftDeletes;

public $timestamps = false;
protected $guarded = [];

public function subProducts()
{
return $this->hasManyThrough(Product::class, self::class, 'parent_id');
}
}

class Product extends Model
{
public $timestamps = false;
protected $guarded = [];
}

0 comments on commit d0cf02d

Please sign in to comment.