Skip to content

Commit 9a9305e

Browse files
jodiedunlopfreekmurze
authored andcommitted
Add proper type support (#47)
* Add proper type support * Fix Style CI * Fix Style CI and insights * Rework into syncTagsWithType and add tests * Fix StyleCI
1 parent b84a00f commit 9a9305e

File tree

3 files changed

+90
-1
lines changed

3 files changed

+90
-1
lines changed

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@ $newsItem->detachTags(['tag4', 'tag5']);
3333
//syncing tags
3434
$newsItem->syncTags(['tag1', 'tag2']); // all other tags on this model will be detached
3535

36+
//syncing tags with a type
37+
$newsItem->syncTagsWithType(['tag1', 'tag2'], 'typeA');
38+
$newsItem->syncTagsWithType(['tag1', 'tag2'], 'typeB');
39+
40+
//retrieving tags with a type
41+
$newsItem->tagsWithType('typeA');
42+
$newsItem->tagsWithType('typeB');
43+
3644
//retrieving models that have any of the given tags
3745
NewsItem::withAnyTags(['tag1', 'tag2']);
3846

src/HasTags.php

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,12 +159,29 @@ public function syncTags($tags)
159159
return $this;
160160
}
161161

162+
/**
163+
* @param array|\ArrayAccess $tags
164+
* @param string|null $type
165+
*
166+
* @return $this
167+
*/
168+
public function syncTagsWithType($tags, string $type = null)
169+
{
170+
$className = static::getTagClassName();
171+
172+
$tags = collect($className::findOrCreate($tags, $type));
173+
174+
$this->syncTagIds($tags->pluck('id')->toArray(), $type);
175+
176+
return $this;
177+
}
178+
162179
protected static function convertToTags($values, $type = null, $locale = null)
163180
{
164181
return collect($values)->map(function ($value) use ($type, $locale) {
165182
if ($value instanceof Tag) {
166183
if (isset($type) && $value->type != $type) {
167-
new \InvalidArgumentException("Type was set to {$type} but tag is of type {$value->type}");
184+
throw new \InvalidArgumentException("Type was set to {$type} but tag is of type {$value->type}");
168185
}
169186

170187
return $value;
@@ -175,4 +192,55 @@ protected static function convertToTags($values, $type = null, $locale = null)
175192
return $className::findFromString($value, $type, $locale);
176193
});
177194
}
195+
196+
/**
197+
* Use in place of eloquent's sync() method so that the tag type may be optionally specified.
198+
* @param $ids
199+
* @param string|null $type
200+
* @param bool $detaching
201+
*/
202+
protected function syncTagIds($ids, string $type = null, $detaching = true)
203+
{
204+
$isUpdated = false;
205+
206+
// Get a list of tag_ids for all current tags
207+
$current = $this->tags()
208+
->newPivotStatement()
209+
->where('taggable_id', $this->getKey())
210+
->when($type !== null, function ($query) use ($type) {
211+
$tagModel = $this->tags()->getRelated();
212+
$query->join(
213+
$tagModel->getTable(),
214+
'taggables.tag_id',
215+
'=',
216+
$tagModel->getTable().'.'.$tagModel->getKeyName()
217+
)
218+
->where('tags.type', $type);
219+
})
220+
->pluck('tag_id')
221+
->all();
222+
223+
// Compare to the list of ids given to find the tags to remove
224+
$detach = array_diff($current, $ids);
225+
if ($detaching && count($detach) > 0) {
226+
$this->tags()->detach($detach);
227+
$isUpdated = true;
228+
}
229+
230+
// Attach any new ids
231+
$attach = array_diff($ids, $current);
232+
if (count($attach) > 0) {
233+
collect($attach)->each(function ($id) {
234+
$this->tags()->attach($id, []);
235+
});
236+
$isUpdated = true;
237+
}
238+
239+
// Once we have finished attaching or detaching the records, we will see if we
240+
// have done any attaching or detaching, and if we have we will touch these
241+
// relationships if they are configured to touch on any database updates.
242+
if ($isUpdated) {
243+
$this->tags()->touchIfTouching();
244+
}
245+
}
178246
}

tests/HasTagsTest.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,4 +185,17 @@ public function it_can_sync_multiple_tags()
185185

186186
$this->assertEquals(['tag3', 'tag4'], $this->testModel->tags->pluck('name')->toArray());
187187
}
188+
189+
/** @test */
190+
public function it_can_sync_tags_with_different_types()
191+
{
192+
$this->testModel->syncTagsWithType(['tagA1', 'tagA2', 'tagA3'], 'typeA');
193+
$this->testModel->syncTagsWithType(['tagB1', 'tagB2'], 'typeB');
194+
195+
$tagsOfTypeA = $this->testModel->tagsWithType('typeA');
196+
$this->assertEquals(['tagA1', 'tagA2', 'tagA3'], $tagsOfTypeA->pluck('name')->toArray());
197+
198+
$tagsOfTypeB = $this->testModel->tagsWithType('typeB');
199+
$this->assertEquals(['tagB1', 'tagB2'], $tagsOfTypeB->pluck('name')->toArray());
200+
}
188201
}

0 commit comments

Comments
 (0)