Laravel - Как искать на основе тегов во многих ко многим полиморфным отношениям?
-
21-12-2019 - |
Вопрос
У меня есть форма, настроенная с помощью текстового ввода и вход с несколькими выборами. Вход Multi-Select имеет список тегов. Теги устанавливаются как многозначное полиморфное отношение. Чтобы помочь сделать все возможное, ниже является контуром моих таблиц и моделей:
Таблицы:
org
id - integer
name - text
...
tags
id - integer
name - text
taggables
tag_id - integer
taggable_id - integer
taggable_type - text
.
Модели:
class Org extends Eloquent
{
...
public function tags()
{
return $this->morphToMany('Tag', 'taggable');
}
}
class Tag extends Eloquent
{
...
public function org()
{
return $this->morphedByMany('Org', 'taggable');
}
}
.
в моих маршрутах .php-файл, я пытаюсь выполнить поиск, например ...
$search = Input::get('keyword');
$searchTerms = explode(' ', $search);
$query = Org::query();
$fields = array('name', 'description', 'additional_info', 'website');
foreach ($searchTerms as $term)
{
foreach ($fields as $field)
{
$query->orWhere($field, 'LIKE', '%'. $term .'%');
}
}
if(Input::get('tags'))
{
$tags = Input::get('tags');
$query
->join('taggables', 'taggables.taggable_id', '=', 'org.id')
->where('taggables.taggable_type', '=', 'Org')
->join('tags', 'taggables.tag_id', '=', 'tags.id')
->groupBy('org.id');
foreach ($tags as $tag)
{
$query->orWhere('tags.id', '=', $tag);
}
}
$org = $query->get();
.
Однако это, конечно, не работает. Поиск ключевых слов работает нормально, но я не уверен, как добавить запрос, который будет получать только строки, которые имеют указанные связанные теги. Переменная $ Tags - это массив, содержащий идентификаторы тегов.
Я хочу вернуть только строки из таблицы ORG, имеющих по меньшей мере одну из тегов, указанных в массиве.
<Сильное> Обновление: Я обновил свой код, и оно своего рода работает, но, похоже, возвращает теги, а не связанные организации - хотя я чувствую себя близко. Вот соответствующий код, который я добавил (или просто посмотреть на него выше):
$query
->join('taggables', 'taggables.taggable_id', '=', 'org.id')
->join('tags', 'taggables.tag_id', '=', 'tags.id')
->where('taggables.taggable_type', '=', 'Org')
->whereIn('tags.id', $tags);
.
<Сильное> Обновление 2: Это, кажется, работает, как я этого хочу, но по какой-то причине он извлекает имя тега вместо имени организации ...
$tags = Input::get('tags');
$query
->join('taggables', 'taggables.taggable_id', '=', 'org.id')
->where('taggables.taggable_type', '=', 'Org')
->join('tags', 'taggables.tag_id', '=', 'tags.id')
->groupBy('org.id');
foreach ($tags as $tag)
{
$query->orWhere('tags.id', '=', $tag);
}
. Решение
Я получил ключевое слово + Поиск метки, работающий следующим образом:
$query = Org::query();
// Search by keyword(s)
if(Input::get('keyword'))
{
$search = Input::get('keyword');
$searchTerms = explode(' ', $search);
$fields = array('org.name', 'org.description', 'org.additional_info', 'org.website');
foreach ($searchTerms as $term)
{
foreach ($fields as $field)
{
$query->orWhere($field, 'LIKE', '%'. $term .'%');
}
}
}
// Search for tag(s)
if(Input::get('tags'))
{
$tags = Input::get('tags');
$query
->join('taggables', 'taggables.taggable_id', '=', 'org.id')
->where('taggables.taggable_type', '=', 'Org')
->whereIn('taggables.tag_id', $tags)
->groupBy('org.id')
->orderBy(DB::raw('count(*)'), 'desc')
->orderBy('name', 'asc');
}
$org = $query->get();
.
Если к ключевому слову и два тега введены для поиска (например), это вернет эти организации, которые имеют одну или несколько тегов, содержат слова, которые похожи на введенные ключевые слова и сортируют результаты, так что организации сНаиболее подходящие теги появятся первыми.