livewire-datatables icon indicating copy to clipboard operation
livewire-datatables copied to clipboard

Issue with Polymorphic relations

Open Ahmed-Elrayes opened this issue 3 years ago • 7 comments

hello, i'm having an issue now that i can't use polymorphic relations in the datatable, i've checked the main component but i didn't find

case $model instanceof MorphTo:

or

case $model instanceof MorphMany:

hope you can add it in the future, unfortunately i can't do it since i'm not that advanced level.

Ahmed-Elrayes avatar Jun 28 '21 13:06 Ahmed-Elrayes

i really hope you add Polymorphic relations support, i have column that i should add the names for users (using two guards) and as you can see in the picture i have to use the second method which is to make a call back and get the exact row i need to get its polymorphic relation so it gets the values but Filter, search doesn't work at all which caused so many issues for me with this project and i have to add custom users search, which is so bad. Image 1

Ahmed-Elrayes avatar Aug 02 '21 09:08 Ahmed-Elrayes

I second this, would be really helpful as I too am using Polymorphic relationships. Resolved for the time being using @Ahmed-Elrayes method above. Good temporary work around.

ReganLyden avatar Aug 02 '21 10:08 ReganLyden

I second this, would be really helpful as I too am using Polymorphic relationships. Resolved for the time being using @Ahmed-Elrayes method above. Good temporary work around.

Thanks, yeah it's a good work around but if you're running a big project ..etc you will have to have search, filter for it or it will be a useless datatables.... unfortunately this is my first project to work with livewire and livewire datatables, so i have lots of issues, but i tried to let it work, but unfortunately i can't let the filter or search work so i will have to make a custom search bar with parameters so i would search for the user .... but it should be implemented in this package since this package is the only working with multi functional stuff in it. unfortunately i'm not experienced enough to program it myself..

Ahmed-Elrayes avatar Aug 02 '21 11:08 Ahmed-Elrayes

hello, is there any update about polymorphic relations ? i hope the devs can do it .

Ahmed-Elrayes avatar Sep 20 '21 17:09 Ahmed-Elrayes

🤣 'the devs'

marksalmon avatar Sep 22 '21 13:09 marksalmon

well they are called devs :v it doesn't matter who does the PR ✌🏻

Ahmed-Elrayes avatar Sep 22 '21 13:09 Ahmed-Elrayes

Any news for this feature?

massimomarazzi avatar Mar 29 '22 13:03 massimomarazzi

Hello.

Can someone please help me out with this?

`
public $model = Transaction::class, $with = 'transactable, transactable.id, transactable.name';

public function columns()
{
    //
    return [
        Column::name('id'),

        Column::name('transactable.id')
            ->filterable(),          

        NumberColumn::name('amount')
            ->filterable(),

        DateColumn::name('created_at')
            ->format('Y-m-d H:i:s'),

        DateColumn::name('updated_at')
            ->format('Y-m-d H:i:s')
            
    ];

}`

The error is triggered from this dependency

https://github.com/tylernathanreed/laravel-relation-joins

itxp2008 avatar Nov 04 '22 09:11 itxp2008

Update...

After a lot, meaning a lot of variants tried I've managed to hack it

My structure is

App\Models\Client public function transactions() { return $this->morphMany(Transaction::class, 'transactable'); }

App\Models\Agent public function transactions() { return $this->morphMany(Transaction::class, 'transactable'); }

App\Models\Transaction public function transactable() { return $this->morphTo(); }

Nothing fancy, I just wanted to see all the transactions under one roof and a id/name link to the appropriate related model.

Using "with" polymorphic relation would've been best but the problem/limitation is because of this dependency

https://github.com/tylernathanreed/laravel-relation-joins

`return function (MorphTo $relation, MorphTypes $morphTypes, Builder $relatedQuery) {

        // When it comes to joining across morph types, we can really only support
        // a single type. However, when we're provided multiple types, we will
        // instead use these one at a time and pass the information along.

        if ($morphTypes->items === ['*']) {
            $types = $relatedQuery->model->distinct()->pluck($relation->getMorphType())->filter()->all();

            $types = array_unique(array_map(function ($morphType) {
                return Relation::getMorphedModel($morphType) ?? $morphType;
            }, $types));

            if (count($types) > 1) {
                throw new RuntimeException('joinMorphRelation() does not support multiple morph types.');
            }

            $morphTypes->items = $types;
        }

        // We're going to handle the morph type join as a belongs to relationship
        // that has the type itself constrained. This allows us to join into a
        // singular table, which bypasses the typical headache of morphs.

        $morphType = array_shift($morphTypes->items);

        $belongsTo = $relatedQuery->getBelongsToRelation($relation, $morphType);

        $belongsTo->where(
            $relatedQuery->qualifyColumn($relation->getMorphType()),
            '=',
            (new $morphType)->getMorphClass()
        );

        return $belongsTo;

    };`

more specific this line if (count($types) > 1) { throw new RuntimeException('joinMorphRelation() does not support multiple morph types.'); }

I really don't know why this approach...

In my case Agent and Client both have an ID and a NAME

Here is my approach and it works in one query (UNION)

`class TransactionsTable extends LivewireDatatable {

public function builder()
{
    // clients_transactions
    $clients_transactions =  Transaction::join('clients', 'clients.id', '=', 'transactions.transactable_id')
        ->select('transactions.id as id', 'transactions.transactable_id as transactable_id', 'transactions.transactable_type as transactable_type', 'transactions.amount as amount', 'name', 'transactions.created_at as created_at', 'transactions.created_at as created_at')
        ->where('transactable_type', 'App\Models\Client');

    // union agents_transactions
    return Transaction::query()->join('agents', 'agents.id', '=', 'transactions.transactable_id')
        ->where('transactable_type', 'App\Models\Agent')
        ->union($clients_transactions);
}

public function columns()
{

    return [
        Column::name('id'),

        Column::name('transactable_id')
            ->filterable(),

        Column::name('transactable_type')
            ->filterable(),
        
        NumberColumn::name('amount')
            ->filterable(),

        Column::raw('name')->filterable(),
            
        DateColumn::name('created_at')
            ->format('Y-m-d H:i:s'),

        DateColumn::name('updated_at')
            ->format('Y-m-d H:i:s')
            
    ];

}

}`

Now the filter for name doesn't work :(

Laravel approach with relation in this case would've been query1: get the transactions query2: get whereIn ids for Clients quety3: get whereIn ids for Agents

but I was afraid of using the callback column where I'm trying to query for id and show the name, depending on how many transaction will be in the DB and the per_page set to all... i didn't wanted to risk

itxp2008 avatar Nov 05 '22 07:11 itxp2008