Skip to content

Commit

Permalink
Merge pull request #25 from reado/feature/create_not_current_status_s…
Browse files Browse the repository at this point in the history
…cope

Created a notCurrentStatus scope - all models without provided names
  • Loading branch information
freekmurze authored Mar 2, 2018
2 parents e8e3a5d + e5a5fc3 commit 4a78a5e
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 1 deletion.
18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,12 +131,28 @@ $allStatuses = $model->statuses;

### Retrieving models with a given latest state

The `currentStatus` scope will return models that have a status with the give name.
The `currentStatus` scope will return models that have a status with the given name.

```php
$allPendingModels = Model::currentStatus('pending');
```

### Retrieving models without a given state

The `otherCurrentStatus` scope will return all models that do not have a status with the given name, including any model that does not have any statuses associated with them.

```php
$allNonPendingModels = Model::otherCurrentStatus('pending');
```

You can also provide an array of status names to exclude from the query.
```php
$allNonInitiatedOrPendingModels = Model::otherCurrentStatus(['initiated', 'pending']);

// or alternatively...
$allNonInitiatedOrPendingModels = Model::otherCurrentStatus('initiated', 'pending');
```

#### Validating a status before setting it

You can add custom validation when setting a status by overwriting the `isValidStatus` method:
Expand Down
23 changes: 23 additions & 0 deletions src/HasStatuses.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,29 @@ public function scopeCurrentStatus(Builder $builder, string $name)
});
}

/**
* @param string|array $names
*
* @return void
**/
public function scopeOtherCurrentStatus(Builder $builder, ...$names)
{
$names = is_array($names) ? array_flatten($names) : func_get_args();
$builder
->whereHas('statuses', function (Builder $query) use ($names) {
$query
->whereNotIn('name', $names)
->whereIn('id', function (QueryBuilder $query) use ($names) {
$query
->select(DB::raw('max(id)'))
->from($this->getStatusTableName())
->where('model_type', static::class)
->groupBy('model_id');
});
})
->orWhereDoesntHave('statuses');
}

public function getStatusAttribute(): string
{
return (string) $this->latestStatus();
Expand Down
21 changes: 21 additions & 0 deletions tests/HasStatusesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -180,4 +180,25 @@ public function it_can_return_a_string_when_calling_the_attribute()

$this->assertEquals('waiting for a change', $this->testModel->status()->reason);
}

/** @test */
public function it_can_find_all_models_that_do_not_have_a_status_with_the_given_name()
{
$model1 = TestModel::create(['name' => 'model1']);
$model2 = TestModel::create(['name' => 'model2']);
$model3 = TestModel::create(['name' => 'model3']);
$model4 = TestModel::create(['name' => 'model4']);
$model5 = TestModel::create(['name' => 'model5']);

$this->testModel->setStatus('initiated');
$model1->setStatus('initiated');

$model2->setStatus('pending');
$model3->setStatus('ready');
$model4->setStatus('complete');

$this->assertCount(4, TestModel::otherCurrentStatus('initiated')->get());
$this->assertCount(3, TestModel::otherCurrentStatus('initiated', 'pending')->get());
$this->assertCount(3, TestModel::otherCurrentStatus(['initiated', 'pending'])->get());
}
}

0 comments on commit 4a78a5e

Please sign in to comment.