简体   繁体   中英

Retrieve data from multiple joins using eloquent

I'm developing a project to track deliveries of goods. My idea would be that one delivery can go to different places, and all those places are connected by single trips.

Here is my Eloquent schema:

class Delivery extends Model
{
    public function places()
    {
        return $this->hasMany(Place::CLASS, 'delivery_id');
    }

    public function trips()
    {
        // what should I do here?
    }
}
class Place extends Model
{
    public function delivery()
    {
        return $this->belongsTo(Delivery::CLASS, 'delivery_id');
    }
}
class Trip extends Model
{
    public function departurePlace()
    {
        return $this->belongsTo(Place::CLASS, 'departure_place_id');
    }

    public function arrivalPlace()
    {
        return $this->belongsTo(Place::CLASS, 'arrival_place_id');
    }
}

Basically what I am trying to do is to get all the trips that are related to one delivery. Or, as another way of saying it, all the trips that connect all the places that one delivery must go through. This is the SQL query that achieves the result I want:

select distinct trip.*
from delivery
    join place on (place.delivery_id = delivery.id)
    join trip on (place.id = trip.arrival_place_id or place.id = trip.departure_place_id)

I would like to have a trips() method on my Delivery model, that returns that result. However I am quite confused as to how achieve that using Eloquent.

Unfortunately we could have simply used the union method to achieve this, but it seems that is doesn't work for hasManyThrough relations.

Anyway, I think Eloquent relations are not meant to be used to achieve such a specific query.

Instead, you may use Eloquent scopes to achieve this.

So based on the answer of @Saengdaet, we can write two relations and then combine them with a scope :

(BTW: I don't know why you said that his code gave an error...)

class Delivery extends Model
{
    public function places()
    {
        return $this->hasMany(Place::class);
    }

    public function outboundTrips()
    {
        return $this->hasManyThrough(
            Trip::class, 
            Place::class,
            "delivery_id", // Foreign key on places table
            "departure_place_id", // Foreign key on trips table
        );
    }

    public function inboundTrips()
    {
        return $this->hasManyThrough(
            Trip::class, 
            Place::class,
            "delivery_id", // Foreign key on places table
            "arrival_place_id", // Foreign key on trips table
        );
    }

    public function scopeTrips($query)
    {
        $deliveriesWithTrips = $query->with(['outboundTrips', 'inboundTrips'])->get();

        $trips = [];
        $deliveriesWithTrips->each(function ($elt) use (&$trips) {
            $trips[] = $elt->inboundTrips->merge($elt->outboundTrips);
        });

        return $trips;
    }
}

And now to retrieve all trips for a given delivery you simply write:

 Delivery::where('id', $id)->trips();

If you want to get all trips from using Delivery model, you can use `hasManyThrough" relationship that provides a convenient shortcut for accessing distant relations via an intermediate relation.

But you have to choose which FK on your Trip model will you use to relate it

You can refer to "has-many-through" relationship

class Delivery extends Model
{
    public function places()
    {
        return $this->hasMany(Place::CLASS, 'delivery_id');
    }

    public function trips()
    {
        return $this->hasManyThrough(
                       Trip::Class, 
                       Place::Class,
                       "delivery_id", // Foreign key on places table
                       "departure_place_id", // Foreign key on trips table
                       "id", // Local key on deliveries table
                       "id" // Local key on places table
        );
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM