nicolaslopezj / searchable

A php trait to search laravel models
MIT License
2.01k stars 291 forks source link

Search polymorphic relation (tags) #222

Open Shi974 opened 4 years ago

Shi974 commented 4 years ago

Hello ! Is there any way to search polymorphic relationship ?

For instance, I am using spatie/laravel-tags package and this adds a polymorphic relationship between my models and the tags table.

So I have those tables and my models : dispositifs, infrastructures, etc. which are tagged and which can be searched.

Taggables

Tags

How could I search for tags please?

So far, I have this, but it does not seem to work. When I search for a "tag", the results returned are all the models and no point ordering is done ...

protected $searchable = [
        'columns' => [
            'dispositifs.di_sigle' => 10,
            'dispositifs.di_libelle' => 10,
            'dispositifs.di_objectif' => 6,
            'dispositifs.di_description' => 7,
            'dispositifs.di_condition' => 4,
            'dispositifs.di_procedure' => 4,
            'dispositifs.di_info' => 5,
        'acteurs.acteur_libelle' => 8,
        'tags.name' => 8,
        ],
        'joins' => [
            'operateur_dispo' => ['dispositifs.di_id', 'operateur_dispo.operateur_dispositif_id'],
            'acteurs' => ['operateur_dispo.operateur_acteur_id', 'acteurs.acteur_id'],
            'taggables' => ['taggables.tag_id','taggables.taggable_id'],
            'tags' => [ 'tags.id','taggables.tag_id'],
        ],
];

Thank you in advance and thanks to @nicolaslopezj for this awesome package ! 😁 👍

GORAZIZYAN98 commented 4 years ago

@Shi974 hey! this is my working example In model Game wich hast morph relation like

    public function translations()
    {
        return $this->morphMany(Translation::class, 'translatable');
    }

 protected $searchable = [
        'columns' => [
            'translation.text' => 10,
        ],
        'joins' => [
            'translation' => ['translation.translatable_id', 'game.id'],
        ],
    ];
Shi974 commented 4 years ago

Hey @GORAZIZYAN98 ! Thanks for your answer ! I forgot to use the relationship function. I fixed that thanks to you. ✔️ But I still have an issue. The search works but when I search for a tag, it returns only one element instead of several. Also, it's really weird, I sometimes get results that are not taggued at all. 🤔

public function tags() {
        return $this -> morphToMany('\Spatie\Tags\Tag', 'taggable');
}

SEARCH

'columns' => [
            'dispositifs.di_sigle' => 10,
            'dispositifs.di_libelle' => 10,
            'dispositifs.di_objectif' => 6,
            'dispositifs.di_description' => 7,
            'dispositifs.di_condition' => 4,
            'dispositifs.di_procedure' => 4,
            'dispositifs.di_info' => 5,
        'acteurs.acteur_libelle' => 8,
        'tags.name' => 10,
        'tags.slug' => 10,
        'tags.type' => 8,
        ],
        'joins' => [
        'operateur_dispo' => ['dispositifs.di_id', 'operateur_dispo.operateur_dispositif_id'],
        'acteurs' => ['operateur_dispo.operateur_acteur_id', 'acteurs.acteur_id'],
        'tags' => ['tags.id', 'dispositifs.di_id'],
       ]

If anyone has a little idea, I would be grateful 😄

sneakylenny commented 3 years ago

I did it like this:

protected $searchable = [
    /**
     * Columns and their priority in search results.
     * Columns with higher values are more important.
     * Columns with equal values have equal importance.
     *
     * @var array
     */
    'columns' => [
        'dispositifs.di_sigle' => 10,
        // ...
        'tags.name' => 10,
        'tags.slug' => 10,
        'tags.type' => 8,
    ],
    'joins' => [
        'taggables' => ['dispositifs.id', 'taggable.taggable_id'], // Join the pivot
        'tags' => ['taggables.tag_id', 'tags.id'], // Get tags based on joined pivot, now you can use this in "columns"!
    ]
];

To explain what I did: First, I joined the pivot (taggables) where the connection between dispositifs and tags is made. Next, from taggables I get the tag by the tag_id that is located on the joined pivot. Tags are not searchable yet, but sincetags is now in the field list, we can add the attributes in the searchable 'columns' array. Viola, tags are now searchable! :smiley:

Downsights: Since taggable is supposed to make use of both taggable_id and taggable_type in combination. I'm not sure if this will conflict if resources have the same taggable_id. 🤔

I hope this will be useful to someone! 😄

montesilva commented 3 years ago
protected $searchable = [
    /**
     * Columns and their priority in search results.
     * Columns with higher values are more important.
     * Columns with equal values have equal importance.
     *
     * @var array
     */
    'columns' => [
        'dispositifs.di_sigle' => 10,
        // ...
        'tags.name' => 10,
        'tags.slug' => 10,
        'tags.type' => 8,
    ],
    'joins' => [
        'taggables' => ['dispositifs.id', 'taggables.taggable_id'], // Join the pivot
        'tags' => ['tags.id', 'taggables.taggable_id', 'taggables.taggable_type', Taggable::class] // Join taggable_id and _type
    ]
];

I used a lot of polymorphic relations in my projects, and came accross the same problem. This solution makes use of both, taggable_id and taggable_type, so you only get resources from the type you pass, in this case Taggable.

If you dont integrate the taggable_type, you will conflict.

If you use Relation::morphMap you must insert the string equivalent for the class instead of Taggable::class.