Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[5.4] whereHas on polymorphic relations not work #18523

Closed
lkmadushan opened this issue Mar 27, 2017 · 18 comments
Closed

[5.4] whereHas on polymorphic relations not work #18523

lkmadushan opened this issue Mar 27, 2017 · 18 comments
Labels
bug

Comments

@lkmadushan
Copy link
Contributor

@lkmadushan lkmadushan commented Mar 27, 2017

  • Laravel Version: 5.4
  • PHP Version: 7.1
  • Database Driver & Version: PostgreSQL 9

Description:

when try whereHas method on a polymorphic relation does not works as expected.

Statistics::whereHas('applicable', function ($query) {
        $query->where('employee.id', 1);
    })->toSql();
select * from "statistics" where exists (select * from "statistics" as "laravel_reserved_0" where "laravel_reserved_0"."id" = "laravel_reserved_0"."applicable_id" and "employee"."id" = ?)
@Dylan-DPC

This comment has been minimized.

Copy link
Contributor

@Dylan-DPC Dylan-DPC commented Mar 27, 2017

@lkmadushan what's the output? any error? or does it give an empty response?

@themsaid

This comment has been minimized.

Copy link
Member

@themsaid themsaid commented Mar 27, 2017

Please provide more details, doesn't work is not a bug report.

@lkmadushan

This comment has been minimized.

Copy link
Contributor Author

@lkmadushan lkmadushan commented Mar 28, 2017

Sorry. I have updated the description. Currently whereHas on polymorphic relations doesn't add constraints to the relationship query. It always check existence in same table.

@themsaid

This comment has been minimized.

Copy link
Member

@themsaid themsaid commented Mar 30, 2017

This won't be an easy fix afaik, we'll need to run several queries on several related tables in order for this work.

@paulofreitas

This comment has been minimized.

Copy link
Contributor

@paulofreitas paulofreitas commented Mar 30, 2017

This is related to #5429. There are some workarounds discussed there, like this one: #5429 (comment)

It's a known limitation that won't probably be easy to fix. Workarounds indeed work but they involve some tricky engineering.

@aios

This comment has been minimized.

Copy link

@aios aios commented Apr 1, 2017

Marked as No-fix when polimorph relations has not intersect collumns

@ghost

This comment has been minimized.

Copy link

@ghost ghost commented Apr 13, 2017

i'm currently using this code in my own project

my Model (\App\Production\Models\Production Model)

public function detail()
{
    return $this->morphTo('detail');
}

public function scopeDetailable($query, $callable = null)
{
    list($type, $key) = $this->getPolymorphicFields();

    $this->newQuery()->distinct()->get([$type])->keyBy($type)->map(function ($model)  use ($type) {
        return (new $model->{$type})->getTable();
    })->each(function ($table, $modelClass) use (&$query, $key, $callable) {
        $model = new $modelClass;

        $query = $query->orWhereExists(function ($query) use ($table, $model, $key, $callable) {
            $query->select('*')->from($table)->whereRaw("{$this->getTable()}.{$key} = {$table}.{$model->getKeyName()}")
                ->when($callable instanceof \Closure, $callable);
        });
    });

    return $query;
}

protected function getPolymorphicFields()
{
    $relation = $this->detail();

    return [$relation->getMorphType(), $relation->getForeignKey()];
}

my Controller

\App\Production\Models\Production::detailable(function ($query) {
    $query->whereDate('panen_future_date', '2017-02-08');
})->with('detail')->get()

and it works for my use case.

please note that all model related to \App\Production\Models\Production model have 'panen_future_date' filed in its table.

@Dylan-DPC

This comment has been minimized.

Copy link
Contributor

@Dylan-DPC Dylan-DPC commented Apr 13, 2017

@bunnypro can you try it on a new project with just the STR (steps to reproduce), it will be better :)

@ghost

This comment has been minimized.

Copy link

@ghost ghost commented Apr 13, 2017

i forgot to compare the _type filed.

ok i'll try to repoduce it with fresh laravel project and also comparing the _type filed.

@ghost

This comment has been minimized.

Copy link

@ghost ghost commented Apr 13, 2017

i have reproduced in a fresh laravel project. here is the https://github.com/bunnypro/querying-polymorphic

just migrate and use DummySeeder class for seeding.
i didn't write any unit testing, but i wrote a route in web route (web.php) for testing, just serve and access
/?search=your search

@Dylan-DPC

This comment has been minimized.

Copy link
Contributor

@Dylan-DPC Dylan-DPC commented Apr 13, 2017

Do you get the same issue or not?

@ghost

This comment has been minimized.

Copy link

@ghost ghost commented Apr 13, 2017

yes i do
that's just my temporary solution for this issue.

@vesteves

This comment has been minimized.

Copy link

@vesteves vesteves commented May 1, 2017

Ppl,
I solve it with strange way but it's working... I'll try explain:

code:

$agendamentos = Agendamento::where(
            'administrador_id',
            Auth::user()->userable_id)->orderBy('id', 'desc')
        ->get();

and It's the code to return object to view:

return view('agendamentos.lista', [
            'agendamentos' => $agendamentos,
            'clientes' => $clientes
        ]);

The hint and the strange thing on the same is:

$clientes = Cliente::whereHas('credito',
    function ($query) {
        $query->where('administrador_id', Auth::user()->userable_id);
    })
->get();
foreach ($agendamentos as $agendamento) {
    foreach ($agendamento->cliente as $cliente) {
        $agendamento->cliente->users = $agendamento->cliente->users;
    }
}
return view('agendamentos.lista', [
    'agendamentos' => $agendamentos
]);

If I do this loop, for NOTHING, it work well and i can use on blade it:

@foreach ($agendamentos as $agendamento)
    {{ $agendamento->cliente->users->name }}
@endforeach

and it on vue:

<ul>
<li v-for="agendamentos in agendamento">{{ agendamento.cliente.users.name }}

I hope it help

@themsaid themsaid removed the database label Jun 7, 2017
@phroggyy

This comment has been minimized.

Copy link
Contributor

@phroggyy phroggyy commented Aug 6, 2017

@themsaid I've thought of a semi-solution after discussing this with another developer. It does have a fairly big caveat, but I still think it's better than nothing... Basically:

Prerequisite:
The user must use morphMap at least for the target model (the relation we want to query our whereHas on).

Solution:
If the Relation::morphMap() is indexed, that is, has the following structure:

[
    User::class,
    Post::class,
    Comment::class,
]

We know that the {morphable}_type is the name of the related table. As such, the subquery performed by laravel should be able to use that value straight away for the select.

If the Relation::morphMap() is not indexed, that is, has a structure like:

[
    'user' => User::class,
    'post' => Post::class,
    'comment' => Comment::class,
]

We cannot be sure what the table name is. As such, the solution is... Ugly. We can loop over the morph map, running (new $model)->getTable() on each of them. After that, construct a SQL SWITCH statement that runs on the {morphable}_type column. That's pretty ugly, but it was the only solution I could think of that'd solve it for both scenarios (as long as morph map is present).

@morningmemo

This comment has been minimized.

Copy link

@morningmemo morningmemo commented Feb 12, 2018

@bunnypro your solution is good.
but it is do not support for whereHas in polymorphic whereHas.
so i send to 'pull request' that solution for this problem to that repository.

@laurencei

This comment has been minimized.

Copy link
Contributor

@laurencei laurencei commented Sep 20, 2018

@staudenmeir - does your merged PR fix this issue? Can I close it?

@staudenmeir

This comment has been minimized.

Copy link
Contributor

@staudenmeir staudenmeir commented Sep 20, 2018

@laurencei The issue itself is basically unfixable, my PR just added a proper exception. I think this can be closed.

@staudenmeir

This comment has been minimized.

Copy link
Contributor

@staudenmeir staudenmeir commented Jun 27, 2019

Laravel 5.8.27 adds whereHasMorph(): #28928

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
10 participants
You can’t perform that action at this time.