Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add orWhereState and orWhereNotState #201

Merged
merged 4 commits into from
Apr 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion docs/querybuilder-support/01-state-scopes.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,18 @@ title: State scopes
weight: 1
---

Every model using the `HasStates` trait will have a `whereState($column, $states)` and a `whereNotState($column, $states)` scope available.
Every model using the `HasStates` trait will have these scopes available:
- `whereState($column, $states)` and `orWhereState($column, $states)`
- `whereNotState($column, $states)` and `orWhereNotState($column, $states)`

```php
$payments = Payment::whereState('state', Paid::class);
$payments = Payment::whereState('state', [Pending::class, Paid::class]);
$payments = Payment::whereState('state', Pending::class)->orWhereState('state', Paid::class);

$payments = Payment::whereNotState('state', Pending::class);
$payments = Payment::whereNotState('state', [Failed::class, Canceled::class]);
$payments = Payment::whereNotState('state', Failed::class)->orWhereNotState('state', Canceled::class);
```

When the state field has another column name in the query (for example due to a join), it is possible to use the full column name:
Expand Down
31 changes: 23 additions & 8 deletions src/HasStates.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;

trait HasStates
{
Expand Down Expand Up @@ -66,26 +67,40 @@ public static function getStatesFor(string $fieldName): Collection

public function scopeWhereState(Builder $builder, string $column, $states): Builder
{
if (! is_array($states)) {
$states = [$states];
}
$states = Arr::wrap($states);

$field = Arr::last(explode('.', $column));
$field = Str::afterLast($column, '.');

return $builder->whereIn($column, $this->getStateNamesForQuery($field, $states));
}

public function scopeWhereNotState(Builder $builder, string $column, $states): Builder
{
if (! is_array($states)) {
$states = [$states];
}
$states = Arr::wrap($states);

$field = Arr::last(explode('.', $column));
$field = Str::afterLast($column, '.');

return $builder->whereNotIn($column, $this->getStateNamesForQuery($field, $states));
}

public function scopeOrWhereState(Builder $builder, string $column, $states): Builder
{
$states = Arr::wrap($states);

$field = Str::afterLast($column, '.');

return $builder->orWhereIn($column, $this->getStateNamesForQuery($field, $states));
}

public function scopeOrWhereNotState(Builder $builder, string $column, $states): Builder
{
$states = Arr::wrap($states);

$field = Str::afterLast($column, '.');

return $builder->orWhereNotIn($column, $this->getStateNamesForQuery($field, $states));
}

/**
* @return array|\Spatie\ModelStates\StateConfig[]
*/
Expand Down
67 changes: 67 additions & 0 deletions tests/Dummy/QueryBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Spatie\ModelStates\Tests\Dummy\ModelStates\StateA;
use Spatie\ModelStates\Tests\Dummy\ModelStates\StateB;
use Spatie\ModelStates\Tests\Dummy\ModelStates\StateC;
use Spatie\ModelStates\Tests\Dummy\ModelStates\StateD;
use Spatie\ModelStates\Tests\TestCase;

class QueryBuilderTest extends TestCase
Expand Down Expand Up @@ -104,4 +105,70 @@ public function test_where_not_state()
->count()
);
}

/** @test */
public function test_or_where_state()
{
$modelOne = TestModel::create([ 'state' => StateB::class ]);
$modelTwo = TestModel::create([ 'state' => StateC::class ]);

$this->assertEquals(
0,
TestModel::query()
->whereState('state', StateA::class)
->orWhereState('state', StateC::class)
->where('id', $modelOne->id)
->count()
);

$this->assertEquals(
1,
TestModel::query()
->whereState('state', StateA::class)
->orWhereState('state', StateC::class)
->where('id', $modelTwo->id)
->count()
);

$this->assertEquals(
2,
TestModel::query()
->whereState('state', StateB::class)
->orWhereState('state', StateC::class)
->count()
);
}

/** @test */
public function test_or_where_not_state()
{
$modelOne = TestModel::create([ 'state' => StateB::class ]);
$modelTwo = TestModel::create([ 'state' => StateC::class ]);

$this->assertEquals(
1,
TestModel::query()
->whereState('state', StateA::class)
->orWhereNotState('state', StateC::class)
->where('id', $modelOne->id)
->count()
);

$this->assertEquals(
0,
TestModel::query()
->whereState('state', StateA::class)
->orWhereNotState('state', StateC::class)
->where('id', $modelTwo->id)
->count()
);

$this->assertEquals(
2,
TestModel::query()
->whereNotState('state', StateD::class)
->orWhereNotState('state', StateA::class)
->count()
);
}
}