38

In Laravel 5.1 I can see that table column relationships can be set-up in 2 ways:

1) Defining Foreign Keys in the Migration table.

2) Defining the Eloquent relationships in the Models.

I have read the documentations and I am still confused on the following:

  1. Do I need to use both or only 1 is needed?

  2. Is it wrong to use both at the same time? Or does it make it redundant or cause conflicts?

  3. What is the benefit of using Eloquent relationships without mentioning the Foreign keys in migration column?

  4. What is the difference?

These are the codes I have now. Its still unclear to me if I need to remove the foreign keys I have set-up in my migration file.

Migration:

  public function up()
    {   

       Schema::create('apps', function (Blueprint $table) {
          $table->increments('id');
          $table->string('app_name');
          $table->string('app_alias');
          $table->timestamps();
          $table->engine = 'InnoDB';
       });

      // This is the second Migration table
      Schema::create('app_roles', function (Blueprint $table) {
          $table->increments('id');
          $table->integer('app_id')->unsigned()->index();
          $table->integer('user_id')->unsigned()->index();
          $table->integer('role_id')->unsigned()->index();
          $table->engine = 'InnoDB';

          $table->unique(array('app_id', 'user_id'));

          $table->foreign('app_id')
                ->references('id')
                ->on('apps')
                ->onDelete('cascade');

          $table->foreign('user_id')
                ->references('id')
                ->on('users')
                ->onDelete('cascade');

          $table->foreign('role_id')
                ->references('id')
                ->on('roles')
                ->onDelete('cascade');
        });     
    }

Model with Eloquent Relationships:

// App Model
class App extends Model
{

     public function appRoles() {
         return $this->hasMany('App\Models\AppRole');
     }
}

// AppRole Model
class AppRole extends Model
{
   public function app() {
       return $this->belongsTo('App\Models\App');
   }

   public function user() {
       return $this->belongsTo('App\User');
   }

   public function role() {
       return $this->belongsTo('App\Models\Role');
   }
}

// User Model
class User extends Model implements AuthenticatableContract, CanResetPasswordContract
{
    .....
    public function appRole() {
         return $this->belongsToMany('App\Models\AppRole');
     }
}

// Role Model
class Role extends EntrustRole
{
     public function appRole() {
         return $this->hasMany('App\Models\AppRole');
     }
}

Can someone help me understand this please?

Neel
  • 9,352
  • 23
  • 87
  • 128

2 Answers2

37

Both go hand in hand. One is in-complete without the other one. If you want your relations to work properly, you need to define both of these things.

If you have just defined the foreign key in a migration file, the relation would work just in case you write a raw query. It won't work on your models since, you haven't written anything about relations in your models.

So, as soon as you write hasMany in one of your models, and corresponding function in the other model, only then your models know about each other, and then you can successfully query things through your model as well as in your database.

Also note that if you have properly defined relations through hasMany and belongsTo in your models, but haven't provided foreign key in the table of the model who belongsTo other table, your relations won't work.

In short, both are equally compulsory.

Arslan Ali
  • 17,418
  • 8
  • 58
  • 76
  • perfect. That's what I was confused about and thank you for confirming that for me. Taking a quick look at my Migration and Model codes above, have I done the interlinking of relationships and foreign key constraints correctly? This is my first attempt and just wondering if I am on the right path with it. Thanks again @ArslanAli – Neel Jul 10 '15 at 11:34
  • @Neel For the review of your code, you can post your code at http://codereview.stackexchange.com/, and can get a decent(I hope) review about it. Thanks. – Arslan Ali Jul 10 '15 at 11:46
  • sorry, I am not sure if I understand this sentence right: `but haven't provided foreign key in the table the model who belongsTo other table, your relations won't work.` – Neel Jul 10 '15 at 11:52
  • 1
    I edited my answer. Sorry. Well, all I meant is that if you don't provide `integer('user_id')` in your migration file, and simply write `belongsTo` in your model, it won't work. – Arslan Ali Jul 10 '15 at 12:22
  • aha.,, I understand. Thank you. :) – Neel Jul 10 '15 at 12:31
  • 4
    I know it is an old answer but not sure if anything changed since. I have declared relationship in my models but haven't done the foreign key constrains in mogrations, but my stuff still works well. Eloquent assumes the names of the columns (eg. app_id etc.). In this case - is specifying foreign key in mogrations required? What would it add to my app if I declare it anyway? – Varin Feb 27 '18 at 12:20
  • @Varin Thanks for getting in touch. It's been a long time since I last touched Laravel. I have been using Rails since then, so I'm not sure about this. If you happen to know for sure, you can edit this answer. :) – Arslan Ali Feb 27 '18 at 15:54
  • 1
    @Varin I know this is a old post and to answer your question, yes I declared relationships in models without using foreign keys in migration files and it works perfectly fine. Therefore, I think it's optional. – Lord Jesus Oct 12 '21 at 14:41
6

Eloquent assumes the foreign key of the relationship based on the model name. In this case, the App model is automatically assumed to have an app_id foreign key, so in your migrations you do not need to specify:

$table->foreign('app_id')
->references('id')
->on('apps')
->onDelete('cascade');

Documentation

apex39
  • 603
  • 1
  • 6
  • 20