Skip to content

Commit 05644f3

Browse files
committed
Merge branch 'release/4.3.0'
2 parents 35ccb63 + 8875021 commit 05644f3

File tree

11 files changed

+399
-5
lines changed

11 files changed

+399
-5
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file. This projec
55

66
## Unreleased
77

8+
## [4.3.0] - 2024-10-13
9+
10+
### Added
11+
12+
- [#38](https://github.com/laravel-json-api/eloquent/pull/38) Added `WhereAll` and `WhereAny` filters.
13+
14+
### Fixed
15+
16+
- [#39](https://github.com/laravel-json-api/eloquent/issues/39) Fixed a bug in the eager loader iterator where include
17+
paths starting with the same word were incorrectly removed. E.g. `car` and `carOwner` would result in just `carOwner`.
18+
819
## [4.2.0] - 2024-08-26
920

1021
### Added

src/Filters/Concerns/HasColumns.php

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
<?php
2+
/*
3+
* Copyright 2024 Cloud Creativity Limited
4+
*
5+
* Use of this source code is governed by an MIT-style
6+
* license that can be found in the LICENSE file or at
7+
* https://opensource.org/licenses/MIT.
8+
*/
9+
10+
declare(strict_types=1);
11+
12+
namespace LaravelJsonApi\Eloquent\Filters\Concerns;
13+
14+
use Illuminate\Database\Eloquent\Model;
15+
16+
trait HasColumns
17+
{
18+
/**
19+
* @var string|null
20+
*/
21+
private ?string $table = null;
22+
23+
/**
24+
* @var array<string>
25+
*/
26+
private array $columns = [];
27+
28+
/**
29+
* @return array<string>
30+
*/
31+
public function columns(): array
32+
{
33+
return $this->columns;
34+
}
35+
36+
/**
37+
* Add a column to the filter.
38+
*
39+
* @param string $column
40+
* @return $this
41+
*/
42+
public function withColumn(string $column): static
43+
{
44+
$this->columns[] = $column;
45+
46+
return $this;
47+
}
48+
49+
/**
50+
* Add columns to the filter.
51+
*
52+
* @param string ...$columns
53+
* @return $this
54+
*/
55+
public function withColumns(string ...$columns): static
56+
{
57+
$this->columns = [
58+
...$this->columns,
59+
...$columns,
60+
];
61+
62+
return $this;
63+
}
64+
65+
/**
66+
* Force the table name when qualifying the columns.
67+
*
68+
* This allows the developer to force the table that the columns are qualified with.
69+
*
70+
* @param string $table
71+
* @return $this
72+
*/
73+
public function qualifyAs(string $table): static
74+
{
75+
$this->table = $table;
76+
77+
return $this;
78+
}
79+
80+
/**
81+
* Get qualified columns.
82+
*
83+
* @return array<string>
84+
*/
85+
protected function qualifiedColumns(?Model $model = null): array
86+
{
87+
if ($this->table) {
88+
return array_map(
89+
fn($column) => $this->table . '.' . $column,
90+
$this->columns,
91+
);
92+
}
93+
94+
if ($model) {
95+
return array_map(
96+
static fn($column) => $model->qualifyColumn($column),
97+
$this->columns,
98+
);
99+
}
100+
101+
return $this->columns;
102+
}
103+
}

src/Filters/WhereAll.php

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<?php
2+
/*
3+
* Copyright 2024 Cloud Creativity Limited
4+
*
5+
* Use of this source code is governed by an MIT-style
6+
* license that can be found in the LICENSE file or at
7+
* https://opensource.org/licenses/MIT.
8+
*/
9+
10+
declare(strict_types=1);
11+
12+
namespace LaravelJsonApi\Eloquent\Filters;
13+
14+
use Illuminate\Support\Traits\Conditionable;
15+
use LaravelJsonApi\Eloquent\Contracts\Filter;
16+
17+
class WhereAll implements Filter
18+
{
19+
use Concerns\DeserializesValue;
20+
use Concerns\HasColumns;
21+
use Concerns\HasOperator;
22+
use Concerns\IsSingular;
23+
use Conditionable;
24+
25+
/**
26+
* @var string
27+
*/
28+
private string $name;
29+
30+
/**
31+
* Create a new filter.
32+
*
33+
* @param string $name
34+
* @param array<string>|null $columns
35+
* @return static
36+
*/
37+
public static function make(string $name, array $columns = null): static
38+
{
39+
return new static($name, $columns);
40+
}
41+
42+
/**
43+
* WhereAll constructor.
44+
*
45+
* @param string $name
46+
* @param array<string>|null $columns
47+
*/
48+
public function __construct(string $name, array $columns = null)
49+
{
50+
$this->name = $name;
51+
$this->columns = $columns ?? [];
52+
$this->operator = '=';
53+
}
54+
55+
/**
56+
* @inheritDoc
57+
*/
58+
public function key(): string
59+
{
60+
return $this->name;
61+
}
62+
63+
/**
64+
* @inheritDoc
65+
*/
66+
public function apply($query, $value)
67+
{
68+
return $query->whereAll(
69+
$this->qualifiedColumns($query->getModel()),
70+
$this->operator(),
71+
$this->deserialize($value)
72+
);
73+
}
74+
}

src/Filters/WhereAny.php

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<?php
2+
/*
3+
* Copyright 2024 Cloud Creativity Limited
4+
*
5+
* Use of this source code is governed by an MIT-style
6+
* license that can be found in the LICENSE file or at
7+
* https://opensource.org/licenses/MIT.
8+
*/
9+
10+
declare(strict_types=1);
11+
12+
namespace LaravelJsonApi\Eloquent\Filters;
13+
14+
use Illuminate\Support\Traits\Conditionable;
15+
use LaravelJsonApi\Eloquent\Contracts\Filter;
16+
17+
class WhereAny implements Filter
18+
{
19+
use Concerns\DeserializesValue;
20+
use Concerns\HasColumns;
21+
use Concerns\HasOperator;
22+
use Concerns\IsSingular;
23+
use Conditionable;
24+
25+
/**
26+
* @var string
27+
*/
28+
private string $name;
29+
30+
/**
31+
* Create a new filter.
32+
*
33+
* @param string $name
34+
* @param array<string>|null $columns
35+
* @return static
36+
*/
37+
public static function make(string $name, array $columns = null): static
38+
{
39+
return new static($name, $columns);
40+
}
41+
42+
/**
43+
* WhereAny constructor.
44+
*
45+
* @param string $name
46+
* @param array<string>|null $columns
47+
*/
48+
public function __construct(string $name, array $columns = null)
49+
{
50+
$this->name = $name;
51+
$this->columns = $columns ?? [];
52+
$this->operator = '=';
53+
}
54+
55+
/**
56+
* @inheritDoc
57+
*/
58+
public function key(): string
59+
{
60+
return $this->name;
61+
}
62+
63+
/**
64+
* @inheritDoc
65+
*/
66+
public function apply($query, $value)
67+
{
68+
return $query->whereAny(
69+
$this->qualifiedColumns($query->getModel()),
70+
$this->operator(),
71+
$this->deserialize($value)
72+
);
73+
}
74+
}

src/QueryBuilder/EagerLoading/EagerLoadIterator.php

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
*/
2626
class EagerLoadIterator implements IteratorAggregate
2727
{
28-
2928
/**
3029
* @var Schema
3130
*/
@@ -70,11 +69,13 @@ public function __construct(Schema $schema, IncludePaths $paths)
7069
*/
7170
public function collect(): Collection
7271
{
73-
$values = collect($this);
72+
$values = Collection::make($this);
7473

75-
return $values->reject(
76-
fn($path) => $values->contains(fn($check) => $path !== $check && Str::startsWith($check, $path))
77-
)->sort()->values();
74+
return $values
75+
->reject(static fn(string $path) => $values
76+
->contains(fn(string $check) => $path !== $check && Str::startsWith($check, $path . '.')))
77+
->sort()
78+
->values();
7879
}
7980

8081
/**

tests/app/Models/Mechanic.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Illuminate\Database\Eloquent\Factories\HasFactory;
1515
use Illuminate\Database\Eloquent\Model;
16+
use Illuminate\Database\Eloquent\Relations\HasOne;
1617
use Illuminate\Database\Eloquent\Relations\HasOneThrough;
1718

1819
class Mechanic extends Model
@@ -25,6 +26,14 @@ class Mechanic extends Model
2526
*/
2627
protected $fillable = ['name'];
2728

29+
/**
30+
* @return HasOne
31+
*/
32+
public function car(): HasOne
33+
{
34+
return $this->hasOne(Car::class);
35+
}
36+
2837
/**
2938
* @return HasOneThrough
3039
*/

tests/app/Schemas/MechanicSchema.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use LaravelJsonApi\Eloquent\Contracts\Paginator;
1616
use LaravelJsonApi\Eloquent\Fields\DateTime;
1717
use LaravelJsonApi\Eloquent\Fields\ID;
18+
use LaravelJsonApi\Eloquent\Fields\Relations\HasOne;
1819
use LaravelJsonApi\Eloquent\Fields\Relations\HasOneThrough;
1920
use LaravelJsonApi\Eloquent\Fields\Str;
2021
use LaravelJsonApi\Eloquent\Filters\WhereIdIn;
@@ -39,6 +40,7 @@ public function fields(): array
3940
ID::make(),
4041
DateTime::make('createdAt')->readOnly(),
4142
Str::make('name'),
43+
HasOne::make('car'),
4244
HasOneThrough::make('carOwner'),
4345
DateTime::make('updatedAt')->readOnly(),
4446
];

tests/app/Schemas/PostSchema.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
use LaravelJsonApi\Eloquent\Fields\Str;
2525
use LaravelJsonApi\Eloquent\Filters\OnlyTrashed;
2626
use LaravelJsonApi\Eloquent\Filters\Where;
27+
use LaravelJsonApi\Eloquent\Filters\WhereAll;
28+
use LaravelJsonApi\Eloquent\Filters\WhereAny;
2729
use LaravelJsonApi\Eloquent\Filters\WhereDoesntHave;
2830
use LaravelJsonApi\Eloquent\Filters\WhereHas;
2931
use LaravelJsonApi\Eloquent\Filters\WhereIdIn;
@@ -94,6 +96,8 @@ public function filters(): iterable
9496
Where::make('slug')->singular(),
9597
WhereIn::make('slugs')->delimiter(','),
9698
WithTrashed::make('withTrashed'),
99+
WhereAll::make('all', ['title','content'])->withColumn('slug')->using('like'),
100+
WhereAny::make('any', ['title','content'])->withColumn('slug')->using('like'),
97101
];
98102
}
99103

tests/lib/Acceptance/EagerLoading/EagerLoaderTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ public static function includePathsProvider(): array
6262
'profile', // auto included for users
6363
],
6464
],
65+
'mechanic' => [
66+
'mechanics',
67+
'car,carOwner,carOwner.car,carOwner.car.mechanic,car.mechanic',
68+
['car.mechanic', 'carOwner.car.mechanic'],
69+
],
6570
];
6671
}
6772

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy