Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel Eloquent: multiple foreign keys for relationship

I am in the process of porting a project to Laravel.

I have two database tables which are in a One-To-Many relationship with each other. They are joined by three conditions. How do I model this relationship in Eloquent?

I am not supposed to modify the database schema, since it has to remain backwards compatible with other things.

I have tried the following, but it doesn't work.

The owning side:

use Illuminate\Database\Eloquent\Model;

class Route extends Model
{
    public function trips()
    {
        return $this->hasMany('Trip', 'route_name,source_file', 'route_name,source_file')
    }
}

The inverse side:

use Illuminate\Database\Eloquent\Model;

class Trip extends Model
{
    public function routes()
    {
        return $this->belongsTo('Route', 'route_name,source_file', 'route_name,source_file');
    }
}

Example Route database values:

id    | route_name     | source_file
---------------------------------------
1     | Berlin - Paris | file1.xls   
2     | Madrid - London| file2.xls
3     | Berlin - Paris | file3.xls

Example Trip database values:

id        | route_name           | source_file | duration
---------------------------------------------------------
1         | Berlin - Paris       | file1.xls   | 78
2         | Madrid - London      | file2.xls   | 241
3         | Berlin - Paris       | file3.xls   | 65
1         | Berlin - Paris       | file1.xls   | 95
1         | Berlin - Paris       | file1.xls   | 65

Route and Trip have other attributes, which I did not include here for brevity.

Is this possible in Eloquent?

like image 345
Genti Saliu Avatar asked Jan 03 '18 12:01

Genti Saliu


People also ask

Can a table have multiple foreign keys in laravel?

A table can have multiple foreign keys based on the requirement.

How do you define many relationships in laravel?

As we have defined the hasMany relationship on Brand model which return the related records of Product model, we can define the inverse relationship on the Product model. Open your app/Product. php model file and add a new method called brand() in it which will return the related brand of a product.

What is the use of eloquent in laravel?

Eloquent is an object relational mapper (ORM) that is included by default within the Laravel framework. An ORM is software that facilitates handling database records by representing data as objects, working as a layer of abstraction on top of the database engine used to store an application's data.


2 Answers

I had to deal with a similar problem. The solution provided by @fab won't work with eager loading because $this->source_file would be null at the time the relationship is processed. I came up with this solution

After installing Compoships and configuring it in your models, you can define your relationships matching multiple columns.

The owning side:

use Illuminate\Database\Eloquent\Model;
use Awobaz\Compoships\Compoships;

class Route extends Model
{
    use Compoships;

    public function trips()
    {
        return $this->hasMany('Trip', ['id', 'route_name', 'source_file'], ['route_id', 'route_name', 'source_file']);
    }
}

The inverse side:

use Illuminate\Database\Eloquent\Model;
use Awobaz\Compoships\Compoships;

class Trip extends Model
{
    use Compoships;

    public function route()
    {
        return $this->belongsTo('Route', ['route_id', 'route_name', 'source_file'], ['id', 'route_name', 'source_file']);
    }
}

Compoships supports eager loading.

like image 74
topclaudy Avatar answered Oct 24 '22 14:10

topclaudy


As Jonathon already mentioned, you could try to add an where-clause to your relationship:

use Illuminate\Database\Eloquent\Model;

class Route extends Model
{
    public function trips()
    {
        return $this->hasMany('Trip', 'route_name')->where('source_file', $this->source_file);
    }
}

The inverse side:

use Illuminate\Database\Eloquent\Model;

class Trip extends Model
{
    public function routes()
    {
        return $this->belongsTo('Route', 'route_name')->where('source_file', $this->source_file);
    }
}
like image 14
fab Avatar answered Oct 24 '22 16:10

fab