Skip to content

Commit cfd3fff

Browse files
Merge branch 'v3'
2 parents 01694d1 + 7d0035d commit cfd3fff

File tree

9 files changed

+212
-78
lines changed

9 files changed

+212
-78
lines changed

src/AllowedFilter.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public function filter(QueryBuilder $query, $value)
4646
return;
4747
}
4848

49-
($this->filterClass)($query, $valueToFilter, $this->internalName);
49+
($this->filterClass)($query->getEloquentBuilder(), $valueToFilter, $this->internalName);
5050
}
5151

5252
public static function exact(

src/AllowedInclude.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,13 @@ public static function count(string $name, ?string $internalName = null): Collec
6161

6262
public function include(QueryBuilder $query): void
6363
{
64-
($this->includeClass)($query, $this->internalName);
64+
if (property_exists($this->includeClass, 'getRequestedFieldsForRelatedTable')) {
65+
$this->includeClass->getRequestedFieldsForRelatedTable = function (...$args) use ($query) {
66+
return $query->getRequestedFieldsForRelatedTable(...$args);
67+
};
68+
}
69+
70+
($this->includeClass)($query->getEloquentBuilder(), $this->internalName);
6571
}
6672

6773
public function getName(): string

src/AllowedSort.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public function sort(QueryBuilder $query, ?bool $descending = null): void
4141
{
4242
$descending = $descending ?? ($this->defaultDirection === SortDirection::DESCENDING);
4343

44-
($this->sortClass)($query, $descending, $this->internalName);
44+
($this->sortClass)($query->getEloquentBuilder(), $descending, $this->internalName);
4545
}
4646

4747
public static function field(string $name, ?string $internalName = null): self

src/Exceptions/InvalidSubject.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace Spatie\QueryBuilder\Exceptions;
4+
5+
use InvalidArgumentException;
6+
7+
class InvalidSubject extends InvalidArgumentException
8+
{
9+
public static function make($subject)
10+
{
11+
return new static(
12+
sprintf(
13+
'Subject %s is invalid.',
14+
is_object($subject)
15+
? sprintf('class `%s`', get_class($subject))
16+
: sprintf('type `%s`', gettype($subject))
17+
)
18+
);
19+
}
20+
}

src/Includes/IncludedRelationship.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@
22

33
namespace Spatie\QueryBuilder\Includes;
44

5+
use Closure;
56
use Illuminate\Database\Eloquent\Builder;
67
use Illuminate\Support\Collection;
78

89
class IncludedRelationship implements IncludeInterface
910
{
11+
/** @var Closure|null */
12+
public $getRequestedFieldsForRelatedTable;
13+
1014
public function __invoke(Builder $query, string $relationship)
1115
{
1216
$relatedTables = collect(explode('.', $relationship));
@@ -15,7 +19,9 @@ public function __invoke(Builder $query, string $relationship)
1519
->mapWithKeys(function ($table, $key) use ($query, $relatedTables) {
1620
$fullRelationName = $relatedTables->slice(0, $key + 1)->implode('.');
1721

18-
$fields = $query->getRequestedFieldsForRelatedTable($fullRelationName);
22+
if ($this->getRequestedFieldsForRelatedTable) {
23+
$fields = ($this->getRequestedFieldsForRelatedTable)($fullRelationName);
24+
}
1925

2026
if (empty($fields)) {
2127
return [$fullRelationName];

src/QueryBuilder.php

Lines changed: 97 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2,94 +2,143 @@
22

33
namespace Spatie\QueryBuilder;
44

5-
use Illuminate\Database\Eloquent\Builder;
5+
use ArrayAccess;
6+
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
7+
use Illuminate\Database\Eloquent\Model;
8+
use Illuminate\Database\Eloquent\Relations\Relation;
69
use Illuminate\Http\Request;
10+
use Illuminate\Support\Collection;
11+
use Illuminate\Support\Traits\ForwardsCalls;
712
use Spatie\QueryBuilder\Concerns\AddsFieldsToQuery;
813
use Spatie\QueryBuilder\Concerns\AddsIncludesToQuery;
914
use Spatie\QueryBuilder\Concerns\AppendsAttributesToResults;
1015
use Spatie\QueryBuilder\Concerns\FiltersQuery;
1116
use Spatie\QueryBuilder\Concerns\SortsQuery;
17+
use Spatie\QueryBuilder\Exceptions\InvalidSubject;
1218

13-
class QueryBuilder extends Builder
19+
/**
20+
* @mixin EloquentBuilder
21+
*/
22+
class QueryBuilder implements ArrayAccess
1423
{
1524
use FiltersQuery,
1625
SortsQuery,
1726
AddsIncludesToQuery,
1827
AddsFieldsToQuery,
19-
AppendsAttributesToResults;
28+
AppendsAttributesToResults,
29+
ForwardsCalls;
2030

21-
/** @var \Spatie\QueryBuilder\QueryBuilderRequest */
31+
/** @var QueryBuilderRequest */
2232
protected $request;
2333

24-
/**
25-
* QueryBuilder constructor.
26-
*
27-
* @param \Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Relations\Relation $builder
28-
* @param null|\Illuminate\Http\Request $request
29-
*/
30-
public function __construct($builder, ?Request $request = null)
34+
/** @var EloquentBuilder|Relation */
35+
protected $subject;
36+
37+
public function __construct($subject, ?Request $request = null)
38+
{
39+
$this->initializeSubject($subject)
40+
->initializeRequest($request ?? app(Request::class));
41+
}
42+
43+
protected function initializeSubject($subject): self
3144
{
32-
parent::__construct(clone $builder->getQuery());
45+
throw_unless(
46+
$subject instanceof EloquentBuilder || $subject instanceof Relation,
47+
InvalidSubject::make($subject)
48+
);
49+
50+
$this->subject = $subject;
3351

34-
$this->initializeFromBuilder($builder);
52+
return $this;
53+
}
3554

55+
protected function initializeRequest(?Request $request = null): self
56+
{
3657
$this->request = $request
3758
? QueryBuilderRequest::fromRequest($request)
3859
: app(QueryBuilderRequest::class);
60+
61+
return $this;
3962
}
4063

41-
/**
42-
* Create a new QueryBuilder for a request and model.
43-
*
44-
* @param string|\Illuminate\Database\Eloquent\Builder|\Illuminate\Database\Eloquent\Relations\Relation $baseQuery Model class or base query builder
45-
* @param \Illuminate\Http\Request $request
46-
*
47-
* @return \Spatie\QueryBuilder\QueryBuilder
48-
*/
49-
public static function for($baseQuery, ?Request $request = null): self
64+
public function getEloquentBuilder(): EloquentBuilder
5065
{
51-
if (is_string($baseQuery)) {
52-
/** @var Builder $baseQuery */
53-
$baseQuery = $baseQuery::query();
66+
if ($this->subject instanceof EloquentBuilder) {
67+
return $this->subject;
5468
}
5569

56-
return new static($baseQuery, $request ?? app(Request::class));
70+
if ($this->subject instanceof Relation) {
71+
return $this->subject->getQuery();
72+
}
73+
74+
throw InvalidSubject::make($this->subject);
75+
}
76+
77+
public function getSubject()
78+
{
79+
return $this->subject;
5780
}
5881

5982
/**
60-
* {@inheritdoc}
83+
* @param EloquentBuilder|Relation|string $subject
84+
* @param Request|null $request
85+
* @return static
6186
*/
62-
public function get($columns = ['*'])
87+
public static function for($subject, ?Request $request = null): self
6388
{
64-
$results = parent::get($columns);
89+
if (is_subclass_of($subject, Model::class)) {
90+
$subject = $subject::query();
91+
}
92+
93+
return new static($subject, $request);
94+
}
6595

66-
if ($this->request->appends()->isNotEmpty()) {
67-
$results = $this->addAppendsToResults($results);
96+
public function __call($name, $arguments)
97+
{
98+
$result = $this->forwardCallTo($this->subject, $name, $arguments);
99+
100+
if ($result === $this->subject) {
101+
return $this;
102+
}
103+
104+
if ($result instanceof Model) {
105+
$this->addAppendsToResults(collect([$result]));
106+
}
107+
108+
if ($result instanceof Collection) {
109+
$this->addAppendsToResults($result);
68110
}
69111

70-
return $results;
112+
return $result;
71113
}
72114

73-
/**
74-
* Add the model, scopes, eager loaded relationships, local macro's and onDelete callback
75-
* from the $builder to this query builder.
76-
*
77-
* @param \Illuminate\Database\Eloquent\Builder $builder
78-
*/
79-
protected function initializeFromBuilder(Builder $builder)
115+
public function __get($name)
80116
{
81-
$this
82-
->setModel($builder->getModel())
83-
->setEagerLoads($builder->getEagerLoads());
117+
return $this->subject->{$name};
118+
}
84119

85-
$builder->macro('getProtected', function (Builder $builder, string $property) {
86-
return $builder->{$property};
87-
});
120+
public function __set($name, $value)
121+
{
122+
$this->subject->{$name} = $value;
123+
}
88124

89-
$this->scopes = $builder->getProtected('scopes');
125+
public function offsetExists($offset)
126+
{
127+
return isset($this->subject[$offset]);
128+
}
90129

91-
$this->localMacros = $builder->getProtected('localMacros');
130+
public function offsetGet($offset)
131+
{
132+
return $this->subject[$offset];
133+
}
92134

93-
$this->onDelete = $builder->getProtected('onDelete');
135+
public function offsetSet($offset, $value)
136+
{
137+
$this->subject[$offset] = $value;
138+
}
139+
140+
public function offsetUnset($offset)
141+
{
142+
unset($this->subject[$offset]);
94143
}
95144
}

0 commit comments

Comments
 (0)