Skip to content

Commit

Permalink
Add without tags scope (#428)
Browse files Browse the repository at this point in the history
* Add without tags scope

* Update HasTagsTest.php

* Update README.md

Co-authored-by: Stefan Damjanovic <>
Co-authored-by: Freek Van der Herten <[email protected]>
  • Loading branch information
stfndamjanovic and freekmurze authored Nov 19, 2022
1 parent f9e438f commit 0f6b46f
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 0 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ NewsItem::withAnyTags(['first tag', 'second tag'])->get();
// retrieve models that have all of the given tags
NewsItem::withAllTags(['first tag', 'second tag'])->get();

// retrieve models that don't have any of the given tags
NewsItem::withoutTags(['first tag', 'second tag'])->get();

// translating a tag
$tag = Tag::findOrCreate('my tag');
$tag->setTranslation('name', 'fr', 'mon tag');
Expand Down
15 changes: 15 additions & 0 deletions src/HasTags.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,21 @@ public function scopeWithAnyTags(
});
}

public function scopeWithoutTags(
Builder $query,
string | array | ArrayAccess | Tag $tags,
string $type = null
): Builder {
$tags = static::convertToTags($tags, $type);

return $query
->whereDoesntHave('tags', function (Builder $query) use ($tags) {
$tagIds = collect($tags)->pluck('id');

$query->whereIn('tags.id', $tagIds);
});
}

public function scopeWithAllTagsOfAnyType(Builder $query, $tags): Builder
{
$tags = static::convertToTagsOfAnyType($tags);
Expand Down
23 changes: 23 additions & 0 deletions tests/HasTagsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,29 @@
});


it('provides a scope to get all models that do not have any of the given tags', function () {
$this->testModel->attachTag('tagA');

TestModel::create([
'name' => 'model1',
'tags' => ['tagA', 'tagB'],
]);

TestModel::create([
'name' => 'model2',
'tags' => ['tagA', 'tagB', 'tagC'],
]);

$testModels = TestModel::withoutTags(['tagC']);

expect($testModels->pluck('name')->toArray())->toEqual(['default', 'model1']);

$testModels = TestModel::withoutTags(['tagC', 'tagB']);

expect($testModels->pluck('name')->toArray())->toEqual(['default']);
});


it('provides a scope to get all models that have any of the given tag instances', function () {
$tag = Tag::findOrCreate('tagA', 'typeA');

Expand Down

0 comments on commit 0f6b46f

Please sign in to comment.