Hammad Butt
Hammad Butt

Reputation: 93

How to Apply Laravel Eloquent Polymorphic Condition while querying based on type

Hi there I am working on a Laravel Project in which I have used polymorphic relation. Here is the polymorphic Model:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class approval extends Model
{
    use HasFactory;

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

} 

I put here the query:

return  approval::with('approvable')->get();

When I run query the query I get result something like this:

[
{
"id": 27,
"status": "sent",
"description": "<p>Ok its perfect</p>",
"type": null,
"extra_description": null,
"sender_id": 17,
"receiver_id": 18,
"added_by": null,
"approvable_id": 27,
"approvable_type": "App\\Models\\deviation",
"created_at": "2023-01-04T10:25:21.000000Z",
"updated_at": "2023-01-04T10:25:21.000000Z",
"approvable": {
"id": 27,
"externalId": "deviation_261672825172",
"name": "Deviation 1021",
"type": "external",
"internal_type": null,
"seriousness": "level_2",
"schedule_date": "2023-01-06 09:39:32",
"sent_to_manager": null,
"status": "completed",
"completed_at": "2023-01-04 11:15:30",
"root_cause_status": null,
"root_cause_completed_at": null,
"actions_taken_status": null,
"actions_taken_completed_at": null,
"verification_status": null,
"verification_completed_at": null,
"description": "<p>In publishing and graphic design, Lorem ipsum is a placeholder text commonly used to demonstrate the visual form of a document or a typeface without relying on meaningful content. Lorem ipsum may be used as a placeholder before final copy is available.</p>",
"customer_id": 5,
"manager_id": 17,
"added_by": 18,
"company_id": 2,
"created_at": "2023-01-04T09:39:32.000000Z",
"updated_at": "2023-01-04T11:15:30.000000Z",
"ccp_pc": null,
"schedule_type": "auto",
"close_up_notes": "dsfdsfdsf",
"parent_id": 26,
"repeat_incident": "yes",
"affected_products": null,
"complainer": null,
"sample_received": "yes",
"sending_status": "sent"
}
},
{
"id": 28,
"status": "approved",
"description": "<p>fggfdg</p>",
"type": null,
"extra_description": null,
"sender_id": 17,
"receiver_id": 17,
"added_by": null,
"approvable_id": 19,
"approvable_type": "App\\Models\\checklist_category",
"created_at": "2023-01-07T07:14:10.000000Z",
"updated_at": "2023-01-07T07:14:10.000000Z",
"approvable": {
"id": 19,
"name": "Checklist 1009",
"description": "Checklist 1009",
"type": "audit",
"company_id": 2,
"created_by": 17,
"created_at": "2023-01-07T06:37:59.000000Z",
"updated_at": "2023-01-07T07:14:10.000000Z",
"delete_status": "false",
"status": "approved",
"approved_by": 17,
"status_changed_at": "2023-01-07 07:14:10",
"equipment_id": null
}
}
]

It is basically linked with two models right now

checklist_category
deviation

Now, I do not want here all data from related models. I want here that when the type is checklist_category, then I only want to select('id','name','description') from checklist_category model and when the type is deviation, I want to select('id','name','seriousness') from deviation model.

So how would it be possible in eloquent eager loading?

Upvotes: 0

Views: 309

Answers (1)

Lk77
Lk77

Reputation: 2462

Here is how i would do it :

->with([
   'approvable' => function (MorphTo $morphTo)
   {
       // Use contrain to select some fields
       $morphTo->constrain([
            ChecklistCategory::class  => function (Builder $query) {
                $query->select('id');
            },
            Deviation::class  => function (Builder $query) {
                $query->select('other_field');
            },
        ]);
   },
])

You can use constrain to customize the query for each type of models, and your case add a select.

you have access to the query builder and you can do everything you need, so you can also add where/whereIn and all sorts of calls

If you also need to get relations for each type of models you can use morphWith :

->with([
   'approvable' => function (MorphTo $morphTo)
   {
       // use morphWith to get a subrelation 
       // (it's the same as calling ->with() inside the ->constrain callback)
       $morphTo->morphWith([
           ChecklistCategory::class        => [
               'subrelation_of_checklist_category:id,name',
               'another_one:id,created_at'
           ],
           Deviation::class  => [
                'subrelation_of_deviation:id,deviation_id',
                'another_one:id,created_at'
           ]
       ]);
   },
])

Upvotes: 1

Related Questions