Laravel - Comment effectuer une recherche en fonction des étiquettes dans une relation polymorphe beaucoup à plusieurs?
-
21-12-2019 - |
Question
J'ai un formulaire configuré avec une entrée de texte et une entrée multi-sélection. L'entrée multi-sélection a une liste des balises. Les balises sont configurées comme une relation polymorphe nombreuses à plusieurs. Pour aider à réduire les choses, ci-dessous est un contour de mes tables et mes modèles:
Tables:
org
id - integer
name - text
...
tags
id - integer
name - text
taggables
tag_id - integer
taggable_id - integer
taggable_type - text
modèles:
class Org extends Eloquent
{
...
public function tags()
{
return $this->morphToMany('Tag', 'taggable');
}
}
class Tag extends Eloquent
{
...
public function org()
{
return $this->morphedByMany('Org', 'taggable');
}
}
dans mon fichier routes.php, j'essaie d'effectuer une recherche comme ...
$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();
Cependant, cela ne fonctionne bien sûr pas. La recherche de mots-clés fonctionne bien, mais je ne sais pas comment ajouter une requête qui ne récupérera que les lignes contenant les balises associées spécifiées. La variable $ Tags est un tableau contenant les identifiants des balises.
Je veux renvoyer uniquement les lignes de la table Org qui ont au moins une des balises spécifiées dans le tableau.
$query
->join('taggables', 'taggables.taggable_id', '=', 'org.id')
->join('tags', 'taggables.tag_id', '=', 'tags.id')
->where('taggables.taggable_type', '=', 'Org')
->whereIn('tags.id', $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);
}
La solution
J'ai eu le mot-clé + la recherche de tag fonctionnant de la manière suivante:
$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();
Si un mot clé et deux balises sont entrés pour la recherche (par exemple), ceci renvoie ces organisations qui ont une ou plusieurs des balises, contiennent des mots qui sont comme le mot clé entré et trier les résultats afin que les organisations avecLes balises les plus assorties apparaîtront d'abord.