Skip to content

Commit 8c8868d

Browse files
Keep scopes and other builder properties from base query (#33)
Initialize scopes, macro's, onDelete callback and eager loads from base query on QueryBuilder
1 parent bad99b7 commit 8c8868d

File tree

3 files changed

+68
-11
lines changed

3 files changed

+68
-11
lines changed

src/QueryBuilder.php

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,9 @@ class QueryBuilder extends Builder
2828

2929
public function __construct(Builder $builder, ?Request $request = null)
3030
{
31-
parent::__construct($builder->getQuery());
31+
parent::__construct(clone $builder->getQuery());
3232

33-
$this->setModel($builder->getModel());
34-
35-
foreach ($this->getModel()->getGlobalScopes() as $identifier => $scope) {
36-
$this->withGlobalScope($identifier, $scope);
37-
}
33+
$this->initializeFromBuilder($builder);
3834

3935
$this->request = $request ?? request();
4036

@@ -43,6 +39,28 @@ public function __construct(Builder $builder, ?Request $request = null)
4339
}
4440
}
4541

42+
/**
43+
* Add the model, scopes, eager loaded relationships, local macro's and onDelete callback
44+
* from the $builder to this query builder.
45+
*
46+
* @param \Illuminate\Database\Eloquent\Builder $builder
47+
*/
48+
protected function initializeFromBuilder(Builder $builder)
49+
{
50+
$this->setModel($builder->getModel())
51+
->setEagerLoads($builder->getEagerLoads());
52+
53+
$builder->macro('getProtected', function (Builder $builder, string $property) {
54+
return $builder->{$property};
55+
});
56+
57+
$this->scopes = $builder->getProtected('scopes');
58+
59+
$this->localMacros = $builder->getProtected('localMacros');
60+
61+
$this->onDelete = $builder->getProtected('onDelete');
62+
}
63+
4664
/**
4765
* Create a new QueryBuilder for a request and model.
4866
*

tests/Models/RelatedModel.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use Illuminate\Database\Eloquent\Model;
66
use Illuminate\Database\Eloquent\Relations\HasMany;
7+
use Illuminate\Database\Eloquent\Relations\BelongsTo;
78

89
class RelatedModel extends Model
910
{

tests/QueryBuilderTest.php

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,53 @@ public function it_can_query_soft_deletes()
5050
/** @test */
5151
public function it_can_query_global_scopes()
5252
{
53-
$queryBuilder = QueryBuilder::for(ScopeModel::class);
54-
5553
ScopeModel::create(['name' => 'John Doe']);
5654
ScopeModel::create(['name' => 'test']);
5755

58-
// Global scope ignores models with name "test"
59-
$this->assertCount(1, $queryBuilder->get());
56+
// Global scope on ScopeModel excludes models named 'test'
57+
$this->assertCount(1, QueryBuilder::for(ScopeModel::class)->get());
58+
59+
$this->assertCount(2, QueryBuilder::for(ScopeModel::query()->withoutGlobalScopes())->get());
60+
61+
$this->assertCount(2, QueryBuilder::for(ScopeModel::class)->withoutGlobalScopes()->get());
62+
}
63+
64+
/** @test */
65+
public function it_keeps_eager_loaded_relationships_from_the_base_query()
66+
{
67+
TestModel::create(['name' => 'John Doe']);
68+
69+
$baseQuery = TestModel::with('relatedModels');
70+
$queryBuilder = QueryBuilder::for($baseQuery);
71+
72+
$this->assertTrue($baseQuery->first()->relationLoaded('relatedModels'));
73+
$this->assertTrue($queryBuilder->first()->relationLoaded('relatedModels'));
74+
}
75+
76+
/** @test */
77+
public function it_keeps_local_macros_added_to_the_base_query()
78+
{
79+
$baseQuery = TestModel::query();
80+
81+
$baseQuery->macro('customMacro', function ($builder) {
82+
return $builder->where('name', 'Foo');
83+
});
84+
85+
$queryBuilder = QueryBuilder::for($baseQuery);
86+
87+
$this->assertEquals($baseQuery->customMacro()->toSql(), $queryBuilder->customMacro()->toSql());
88+
}
89+
90+
/** @test */
91+
public function it_keeps_the_on_delete_callback_added_to_the_base_query()
92+
{
93+
$baseQuery = TestModel::query();
94+
95+
$baseQuery->onDelete(function () {
96+
return 'onDelete called';
97+
});
6098

61-
$this->assertCount(2, $queryBuilder->withoutGlobalScopes()->get());
99+
$this->assertEquals('onDelete called', QueryBuilder::for($baseQuery)->delete());
62100
}
63101

64102
/** @test */

0 commit comments

Comments
 (0)