@@ -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}
0 commit comments