У меня есть следующие таблицы:
articles
hasMany(tags)
movies
hasMany(tags)
series
hasMany(tags)
subs (morph)
media_id
media_type
user_id
Все первые три таблицы содержат множество тегов, а подтаблица имеет отношение Morph между ними всеми.
Идея проста: пользователь может подписаться на фильмы и/или сериалы, а НЕ на статьи, скажем, выбрать -в записи из фильмов.
Будет вставлена следующая запись:
media_id => 1, media_type => movie, user_id => 1
Предположим, у нас есть 10 тысяч таких записей в таблице sub. Теперь я создаю записи в статьях с определенными тегами. Я хочу уведомить всех пользователей в подписках, у которых есть подписка на фильмы и/или сериалы, имеющие точно такие же теги, что и запись, на которую я ориентируюсь из статей .
TL;DR: уведомление пользователей, интересующихся определенными тегами из фильмов или сериалов.
Для достижения для этого я добавил morphTo в модель subs:
public function media(){
return $this->morphTo();
}
Логика проста:
- Получите статью.
- Получите связь tags() и сохраните ее в переменной.
- Проверьте, не пусты ли теги, если нет, продолжайте
- Получить все подписки.
- Получить morphTo и получите его теги.
- Сравните и продолжите.
$article = MediaArticle::find($notificationable_id);
$article_tags = $article->tags;
$subbed_users = array();
if (empty($article_tags) === false) {
$subs = NotificationMediaSub::all();
foreach ($subs as $sub) {
$sub_tags = $sub->media->tags;
foreach ($sub_tags as $sub_tag) {
foreach ($article_tags as $article_tag_title) {
if (strcasecmp($sub_tag->title, $article_tag_title->title) === 0) {
array_push($subbed_users, $sub->user_id);
}
}
}
}
// continue here
}
=======================
- Подход
public function media() {
if ($this->taggable_type === AdminHelper::MORPH_MEDIA_TRANSLATION_MOVIE['original']) {
return $this->belongsTo(MediaMovie::class, 'taggable_id', 'id');
} elseif ($this->taggable_type === AdminHelper::MORPH_MEDIA_TRANSLATION_SERIES['original']) {
return $this->belongsTo(MediaSeries::class, 'taggable_id', 'id');
}
return $this->belongsTo(MediaMovie::class, 'taggable_id', 'id')->where('id', 0);
}
Теперь я получаю субтитры следующим образом:
$article = MediaArticle::find($notificationable_id);
$article_tags = $article->tags;
$subbed_users_tokens = array();
if (empty($article_tags) === false) {
$article_tags = $article_tags->map(function ($tag) {
return $tag->title;
});
$related_tags = MediaTag::whereIn("title", $article_tags)->get();
$related_tags = $related_tags->map(function ($tag) {
return $tag->id;
});
$tags_relationship = MediaTagsRelationship::whereIn("tag_id", $related_tags)->where("taggable_type", "movie")->orWhere("taggable_type", "series")->get();
foreach ($tags_relationship as $tag_relationship) {
$media = $tag_relationship->media()->with('subs')->get();
if (empty($media) === false) {
$media = $media[0];
$subs = $media->subs->map(function ($sub) {
return $sub->firebase_token;
});
array_push($subbed_users_tokens, $subs);
}
}
}
Подробнее здесь: https://stackoverflow.com/questions/572 ... hip-advice