Question

it seems like the whereHas method doesn't work really well.

$res = Entreprise::whereHas('labels',function ($q)
    {
        $q->where('hidden','!=',1);
    })
    ->whereHas('labels',function ($q)
    {
        $q->whereHidden(1);
    })
    ->get();
 dd(count($res));  //shows int 2

Here is the labels relations:

public function labels()
{
    return $this->morphToMany('Label', 'labelable');
}

and here is the database:

id | nom                | deleted_at | created_at          | updated_at          | junior_id | label_type_id | abbreviation | id_siaje | hidden 
 6 | Environnord        | 0000-00-00 | 0000-00-00 00:00:00 | 0000-00-00 00:00:00 |         1 |             4 | EnvNord      |        0 |      1 
 7 | Salon créer        | 0000-00-00 | 0000-00-00 00:00:00 | 0000-00-00 00:00:00 |         1 |             4 | Créer        |        0 |      1 
 8 | Salon WebAnalytics | 0000-00-00 | 0000-00-00 00:00:00 | 0000-00-00 00:00:00 |         1 |             4 | Web          |        0 |      0 

When I do instead:

$res = Entreprise::whereHas('labels',function ($q)
    {
        $q->where('hidden','!=',1);
        $q->whereHidden(1);
    })->get()
dd(count($res)); //int 0

I get the expected value.

In my database, an entreprise object doesn't have more than 1 labels, so the label is either hidden or not, so one of the conditions should be false.

Edit

Here is the labelable table

+----+----------+--------------+----------------+-----------+
| id | label_id | labelable_id | labelable_type | junior_id |
+----+----------+--------------+----------------+-----------+
|  1 |        1 |          925 | Etude          |         1 |
|  2 |        2 |          926 | Etude          |         1 |
|  3 |        3 |          927 | Etude          |         1 |
|  4 |        2 |          927 | Etude          |         1 |
|  5 |        1 |          928 | Etude          |         1 |
|  6 |        2 |          928 | Etude          |         1 |
|  7 |        3 |          929 | Etude          |         1 |
|  8 |        2 |          931 | Etude          |         1 |
|  9 |        1 |          933 | Etude          |         1 |
| 10 |        2 |          934 | Etude          |         1 |
| 11 |        4 |            1 | User           |         1 |
| 12 |        5 |            2 | User           |         1 |
| 13 |        7 |            1 | Entreprise     |         1 |
| 14 |        6 |            2 | Entreprise     |         1 |
| 15 |        7 |            3 | Entreprise     |         1 |
| 16 |        8 |            4 | Entreprise     |         1 |
| 17 |        6 |            5 | Entreprise     |         1 |
| 18 |        7 |            6 | Entreprise     |         1 |
| 19 |        6 |            7 | Entreprise     |         1 |
+----+----------+--------------+----------------+-----------+

As you can see, the problem is probably that they are two entities with labelable_id of 1, and two entities of labelable_id of 2. But this is a morphToMany, so Eloquent should know that the labels on users should not be taken into account ?

When I have a look at the generated SQL:

 select * from `entreprises` 
     where `entreprises`.`deleted_at` is null
     and `entreprises`.`junior_id` = ? 
     and (select count(*) from `labels` 
          inner join `labelables` on `labels`.`id` = `labelables`.`label_id` 
          where `labels`.`deleted_at` is null 
          and `labels`.`junior_id` = ? 
          and `labelables`.`labelable_id` = `entreprises`.`id` 
          and `hidden` != ?
          and `hidden` = ?
          and `labels`.`deleted_at` is null
          and `labels`.`junior_id` = ?) >= ?

it seems like the labelables.labelable_type isn't taken into account, so that may be the source of the problem.

Was it helpful?

Solution

Although I don't know what the question is, I bet you actually get the correct answer and your expectation is incorrect.

Your second example with a single whereHas obviously does not return any rows, because the condition is never satisfiable.

For the first however, I guess your understanding is flawed. The generated query reflects what you specify with the two whereHas clauses. It will find all enterprises which have at least one label which is hidden, and at least one label which is not hidden. Since it's a many-many relationship, this is in fact satisfiable.

Note that this is different from the second example, where you search for all enterprises which have at least one label which is both hidden and not hidden.

I do not know the enterprises table, nor the many-many join table, but I guess the two results actually satisfy the condition as I stated above. Your database engine probably does not lie. If you think otherwise and have a feeling the generated query is actually wrong, please tell us where you think it is wrong.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top