Skip to content

Commit d0247d6

Browse files
Support Laravel 12 and spatie query builder 6
1 parent 69b91e9 commit d0247d6

File tree

10 files changed

+98
-91
lines changed

10 files changed

+98
-91
lines changed

.github/workflows/test.yml

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,9 @@ jobs:
1111
strategy:
1212
fail-fast: false
1313
matrix:
14-
php: [8.1, 8.2, 8.3]
15-
laravel: [10.*, 11.*]
14+
php: [8.2, 8.3, 8.4]
15+
laravel: [10.*, 11.*, 12.*]
1616
dependency-version: [prefer-lowest, prefer-stable]
17-
exclude:
18-
- php: 8.1
19-
laravel: 11.*
2017

2118
name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.dependency-version }}
2219

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,6 @@ composer.phar
33
composer.lock
44
vendor
55
.php_cs.cache
6-
.phpunit.result.cache
6+
.phpunit.result.cache
7+
.phpunit.cache
8+
.claude

composer.json

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,17 @@
77
}
88
},
99
"require": {
10-
"php": "^8.1",
11-
"illuminate/container": "^10.0|^11.0",
12-
"illuminate/database": "^10.0|^11.0",
13-
"illuminate/support": "^10.0|^11.0",
14-
"spatie/laravel-query-builder": "^5.0"
10+
"php": "^8.2|^8.3|^8.4",
11+
"illuminate/container": "^10.0|^11.0|^12.0",
12+
"illuminate/database": "^10.0|^11.0|^12.0",
13+
"illuminate/support": "^10.0|^11.0|^12.0",
14+
"spatie/laravel-query-builder": "^6.0"
1515
},
1616
"require-dev": {
17-
"phpunit/phpunit": "^9.0",
18-
"laravel/laravel": "^10.0|^11.0",
17+
"phpunit/phpunit": "^10.0|^11.0",
18+
"laravel/laravel": "^10.0|^11.0|^12.0",
1919
"mockery/mockery": "^1.5",
20-
"makeabledk/laravel-factory-enhanced": "^5.0",
20+
"makeabledk/laravel-factory-enhanced": "^6.0",
2121
"fakerphp/faker": "^1.18"
2222
},
2323
"autoload-dev": {

phpunit.xml

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,15 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<phpunit backupGlobals="false"
3-
backupStaticAttributes="false"
4-
bootstrap="vendor/autoload.php"
5-
colors="true"
6-
convertErrorsToExceptions="true"
7-
convertNoticesToExceptions="true"
8-
convertWarningsToExceptions="true"
9-
processIsolation="false"
10-
stopOnFailure="false"
11-
verbose="true"
12-
>
13-
<testsuites>
14-
<testsuite name="Package Test Suite">
15-
<directory suffix="Test.php">./tests/</directory>
16-
</testsuite>
17-
</testsuites>
18-
<php>
19-
<ini name="display_errors" value="1" />
20-
<server name="APP_ENV" value="testing" />
21-
<server name="APP_DEBUG" value="true" />
22-
<server name="DB_CONNECTION" value="sqlite" />
23-
<server name="DB_DATABASE" value=":memory:" />
24-
</php>
2+
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" backupGlobals="false" bootstrap="vendor/autoload.php" colors="true" processIsolation="false" stopOnFailure="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.5/phpunit.xsd" cacheDirectory=".phpunit.cache" backupStaticProperties="false">
3+
<testsuites>
4+
<testsuite name="Package Test Suite">
5+
<directory suffix="Test.php">./tests/</directory>
6+
</testsuite>
7+
</testsuites>
8+
<php>
9+
<ini name="display_errors" value="1"/>
10+
<server name="APP_ENV" value="testing"/>
11+
<server name="APP_DEBUG" value="true"/>
12+
<server name="DB_CONNECTION" value="sqlite"/>
13+
<server name="DB_DATABASE" value=":memory:"/>
14+
</php>
2515
</phpunit>

src/Endpoint.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77
use Illuminate\Database\Eloquent\Builder;
88
use Illuminate\Http\Request;
99
use Illuminate\Support\Arr;
10+
use Illuminate\Support\Collection;
1011
use Illuminate\Support\Str;
1112
use Makeable\ApiEndpoints\Concerns\NormalizesRelationNames;
13+
use Spatie\QueryBuilder\AllowedInclude;
1214

1315
class Endpoint
1416
{
@@ -342,6 +344,9 @@ protected function buildNamespacedConstraintArrays($relations)
342344
};
343345
}
344346

347+
// NOTE: In order to support AllowedInclude::relationship() we'd need to do
348+
// additional normalization here since it returns a Collection of AllowedInclude.
349+
345350
// Furthermore we'll allow for multiple constraints on the same relation.
346351
// Later on we'll apply all of the constraints into the same query.
347352
return [$relation => Arr::wrap($constraint)];

src/QueryBuilder.php

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,16 @@
55
use Closure;
66
use Illuminate\Contracts\Pagination\CursorPaginator;
77
use Illuminate\Contracts\Pagination\Paginator;
8+
use Illuminate\Database\Eloquent\Builder as EloquentBuilder;
89
use Illuminate\Database\Eloquent\Model;
10+
use Illuminate\Database\Eloquent\Relations\Relation;
911
use Illuminate\Http\Request;
1012
use Illuminate\Support\Arr;
1113
use Illuminate\Support\Collection;
1214
use Illuminate\Support\Str;
1315
use Makeable\ApiEndpoints\Concerns\AddsAppendsToQuery;
1416
use Makeable\ApiEndpoints\Concerns\NormalizesRelationNames;
17+
use Spatie\QueryBuilder\AllowedInclude;
1518
use Spatie\QueryBuilder\QueryBuilder as SpatieBuilder;
1619

1720
class QueryBuilder extends SpatieBuilder
@@ -21,6 +24,15 @@ class QueryBuilder extends SpatieBuilder
2124
allowedAppends as originalAllowedAppends;
2225
}
2326

27+
public function __construct(
28+
protected Relation|EloquentBuilder $subject,
29+
?Request $request = null
30+
) {
31+
$this->request = $request
32+
? QueryBuilderRequest::fromRequest($request)
33+
: app(QueryBuilderRequest::class);
34+
}
35+
2436
/**
2537
* @var array
2638
*/
@@ -47,27 +59,14 @@ public function __call($name, $arguments)
4759
return $result;
4860
}
4961

50-
/**
51-
* @param Request|null $request
52-
* @return QueryBuilder
53-
*/
54-
protected function initializeRequest(?Request $request = null): static
55-
{
56-
$this->request = $request
57-
? QueryBuilderRequest::fromRequest($request)
58-
: app(QueryBuilderRequest::class);
59-
60-
return $this;
61-
}
62-
6362
/**
6463
* @param $appends
6564
* @return QueryBuilder
6665
*/
6766
public function allowedAppends($appends): static
6867
{
6968
collect($appends)
70-
->mapWithKeys(Closure::fromCallable([$this, 'normalizeRelationQueries']))
69+
->flatMap(fn ($constraints, $relation) => $this->normalizeRelationQueries($constraints, $relation))
7170
->tap(function (Collection $appends) {
7271
$this->originalAllowedAppends($appends->keys()->all());
7372
})
@@ -129,7 +128,7 @@ protected function addAppendsToResults(Collection $results, Collection $appends
129128
public function allowedIncludes($includes): static
130129
{
131130
collect($includes)
132-
->mapWithKeys(Closure::fromCallable([$this, 'normalizeRelationQueries']))
131+
->flatMap(fn ($constraints, $relation) => $this->normalizeRelationQueries($constraints, $relation))
133132
->mapWithKeys(fn ($constraints, $relation) => [$this->normalizeRelationName($relation) => $constraints])
134133
->tap(function (Collection $includes) {
135134
$this->queueConstraints($includes);
@@ -244,12 +243,20 @@ protected function mergeConstraints(...$constraints): Closure
244243
* @param $relation
245244
* @return array
246245
*/
247-
protected function normalizeRelationQueries($constraints, $relation): array
246+
protected function normalizeRelationQueries($constraints, $relation): Collection
248247
{
249-
if (is_numeric($relation)) {
248+
// Currently not working as intended
249+
// // Support AllowedInclude::relationship() which returns a Collection of AllowedInclude
250+
// if (is_numeric($relation) && is_array($constraints) && count($constraints) === 1 && $constraints[0] instanceof Collection) {
251+
// return $constraints[0]->mapWithKeys(function (AllowedInclude $include) {
252+
// return [$include->getName() => [fn ($query) => $include->include($query)]];
253+
// });
254+
// }
255+
256+
if (is_numeric($relation) && is_string($constraints)) {
250257
[$constraints, $relation] = [[], $constraints];
251258
}
252259

253-
return [$relation => $constraints];
260+
return collect([$relation => $constraints]);
254261
}
255262
}

tests/Feature/EndpointHttpTest.php

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ class EndpointHttpTest extends TestCase
1212
{
1313
use RefreshDatabase;
1414

15-
/** @test */
16-
public function it_can_load_model_with_nested_endpoint_relations()
15+
public function test_it_can_load_model_with_nested_endpoint_relations()
1716
{
1817
$user = factory(User::class)
1918
->with(1, 'servers.databases')
@@ -30,8 +29,7 @@ public function it_can_load_model_with_nested_endpoint_relations()
3029
]]);
3130
}
3231

33-
/** @test **/
34-
public function any_allowed_relation_is_also_countable()
32+
public function test_any_allowed_relation_is_also_countable()
3533
{
3634
$user = factory(User::class)->with(2, 'servers')->create();
3735

@@ -45,8 +43,7 @@ public function any_allowed_relation_is_also_countable()
4543
]]);
4644
}
4745

48-
/** @test **/
49-
public function it_appends_attributes()
46+
public function test_it_appends_attributes()
5047
{
5148
$server = factory(Server::class)->create();
5249

@@ -60,8 +57,7 @@ public function it_appends_attributes()
6057
]]);
6158
}
6259

63-
/** @test **/
64-
public function it_accepts_custom_queries_for_appends()
60+
public function test_it_accepts_custom_queries_for_appends()
6561
{
6662
$user = factory(User::class)->with(1, 'servers')->create();
6763

@@ -77,8 +73,7 @@ public function it_accepts_custom_queries_for_appends()
7773
]]);
7874
}
7975

80-
/** @test */
81-
public function filters_may_be_applied()
76+
public function test_filters_may_be_applied()
8277
{
8378
$notFavorite = factory(Server::class)->create(['is_favorite' => false]);
8479
$favorite = factory(Server::class)->create(['is_favorite' => true]);
@@ -93,8 +88,7 @@ public function filters_may_be_applied()
9388
]]);
9489
}
9590

96-
/** @test **/
97-
public function it_normalizes_snake_case_to_camel_case()
91+
public function test_it_normalizes_snake_case_to_camel_case()
9892
{
9993
factory(Team::class)
10094
->with(1, 'users')
@@ -111,8 +105,7 @@ public function it_normalizes_snake_case_to_camel_case()
111105
->assertJsonCount(1, '0.users.0.favorite_servers.0.databases');
112106
}
113107

114-
/** @test **/
115-
public function it_supports_circular_includes()
108+
public function test_it_supports_circular_includes()
116109
{
117110
$server = factory(Server::class)
118111
->with(1, 'databases')
@@ -132,4 +125,24 @@ public function it_supports_circular_includes()
132125
]],
133126
]]);
134127
}
128+
129+
// Currently not working as intended
130+
// public function test_it_supports_allowed_includes_syntax()
131+
// {
132+
// $server = factory(Server::class)
133+
// ->with(1, 'users.teams')
134+
// ->create();
135+
//
136+
// $this
137+
// ->withoutExceptionHandling()
138+
// ->getJson('/servers?include=users.teams,users.teams_count')
139+
// ->assertSuccessful()
140+
// ->assertJson([[
141+
// 'id' => $server->id,
142+
// 'users' => [[
143+
// 'teams' => [
144+
// ],
145+
// ]],
146+
// ]]);
147+
// }
135148
}

0 commit comments

Comments
 (0)