54

In Laravel 4, when working with many-to-many relationships as described in the 4.2 docs, how can I actually get Laravel to create the pivot table for me?

Do I need to add something in my migrations for the two models that are involved? Do I need to manually create a migration for the pivot table? Or how does Laravel know to create the pivot table?

All I've done so far is add the belongsToMany information to the two respective models, i.e.

class User extends Eloquent 
{
    public function roles()
    {
         return $this->belongsToMany('Role');
     }
 }

However, that does not trigger creation of the pivot table. What step am I missing?

Community
  • 1
  • 1
Ben
  • 15,938
  • 19
  • 92
  • 138

10 Answers10

74

It appears as though the pivot table does need to be created manually (i.e. Laravel does not do this automatically). Here's how to do it:

1.) Create a new migration, using singular table names in alphabetical order (default):

php artisan make:migration create_alpha_beta_table --create --table=alpha_beta

2.) Inside the newly created migration, change the up function to:

public function up()
{
    Schema::create('alpha_beta', function(Blueprint $table)
    {
        $table->increments('id');
        $table->integer('alpha_id');
        $table->integer('beta_id');
    });
}

3.) Add the foreign key constraints, if desired. (I haven't gotten to that bit, yet).


Now to seed, say, the alpha table, using keys from beta, you can do the following in your AlphaTableSeeder:

public function run()
{
    DB::table('alpha')->delete();

    Alpha::create( array( 
        'all'           =>  'all',
        'your'          =>  'your',
        'stuff'         =>  'stuff',
    ) )->beta()->attach( $idOfYourBeta );
}
M Shafique
  • 786
  • 7
  • 18
Ben
  • 15,938
  • 19
  • 92
  • 138
  • If you are getting 'call to undefined method..." when your seed tries to run that {model}()->attach(/... method, remember to created a model for both tablese, with a belongstomany in one of them. Eg, for this example: In models/Alpha.php you would include: public function beta() { return $this->belongsToMany('Beta'); } – sersun Oct 30 '14 at 02:07
  • 1
    I think step 1 should be: ```php artisan migrate:make create_alpha_beta_table --create=alpha_beta``` – Adamski Feb 03 '15 at 11:59
  • 1
    is that first id field necessary? – Miguel Stevens Nov 25 '16 at 13:00
  • 1
    for intermediate pivot tables, there should't be a primary key. – Tharaka Dilshan Apr 23 '19 at 15:08
  • 3
    Drop the id, add foreign keys, and in most cases you also want a *unique* index covering both FKs. – okdewit Jun 19 '19 at 13:33
  • @TharakaDilshan I agree, no AI primary key is needed. However, the touple [alpha_id,beta_id] should be the primary key, or at least indexed! Otherwise you query spped will slow downa lot – Adam May 05 '21 at 09:01
44

I use Jeffrey Way's Laravel-4-Generators or Laravel-5-Generators-Extended.

then you can just use this artisan command:

php artisan generate:pivot table_one table_two
Geoffrey
  • 5,407
  • 10
  • 43
  • 78
user3260759
  • 515
  • 5
  • 10
  • 1
    This creates the foreign key constraints as well. – dan-klasson Dec 24 '14 at 09:27
  • 5
    For Laravel-5-Generators-Extended, the command is `make:migration:pivot` and no longer `generate:pivot` (as it was in Laravel-4-Generators). – Jon Feb 15 '16 at 20:00
29

To expand on Ben's answer (I tried to edit it but reviewers said it added too much):

To add the foreign key constraints, make sure if alpha id is unsigned, alpha_id is also unsigned in the pivot table. This migration would run after (2) in Ben's answer since it alters the table created then.

public function up()
{
    Schema::table('alpha_beta', function(Blueprint $table)
    {
        $table->foreign('alpha_id')->references('id')->on('alpha');
        $table->foreign('beta_id')->references('id')->on('beta');
    });
}
Afzal N
  • 2,546
  • 1
  • 26
  • 24
12

For Many to Many relationships you can create the Migration file of the Database manually like this:

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;

class CreateAccountTagTable extends Migration
{

    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('account_tag', function (Blueprint $table) {
            // $table->timestamps(); // not required
            // $table->softDeletes(); // not required

            $table->integer('account_id')->unsigned();
            $table->foreign('account_id')->references('id')->on('accounts');

            $table->integer('tag_id')->unsigned()->nullable();
            $table->foreign('tag_id')->references('id')->on('tags');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('account_tag');
    }
}

Note: in case you have timestamps on the pivot table you must set withTimestamps on the relationship of both ends like this:

return $this->belongsToMany(\Mega\Modules\Account\Models\Tag::class)->withTimestamps();

.

return $this->belongsToMany(\Mega\Modules\Account\Models\Account::class)->withTimestamps();
Mahmoud Zalt
  • 30,478
  • 7
  • 87
  • 83
11
  1. Create new migration:
php artisan make:migration create_alpha_beta_table --create=alpha_beta
  1. Inside the newly created migration:
public function up() {
    Schema::create('alpha_beta', function(Blueprint $table) {
            $table->increments('id');
            $table->unsignedBigInteger('alpha_id');
            $table->unsignedBigInteger('beta_id');
            // foreign keys
            $table->foreign('alpha_id')->references('id')->on('alphas');
            $table->foreign('beta_id')->references('id')->on('betas');
     });
}
Adam Pery
  • 1,924
  • 22
  • 21
6

for the latest Laravel's versions:

composer require --dev laracasts/generators

php artisan make:migration:pivot table1 table2
4

In addition to all the above answers

  • There is no need to have an AI index for a pivot table. Its uniquely defined by its touple (key1,key2).
  • The primary key should be the composition (key1,key2). The benefits are that the touples are unique and all queries are best optimized.

So here comes a real life example:

Schema::create('bill_user', function (Blueprint $table) {
    // unsigned is needed for foreign key
    $table->integer('user_id')->unsigned();
    $table->integer('bill_id')->unsigned();

    $table->primary(['user_id', 'bill_id']);

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

    $table->foreign(bill_id')
        ->references('id')->on('bills')
        ->onDelete('cascade');
});
Adam
  • 25,960
  • 22
  • 158
  • 247
0

following the latest laravel conventions, the up method should be

public function up() {
        Schema::create('country_timezone', function (Blueprint $table) {
            $table->foreignId('country_id')->references('id')->on('countries');
            $table->foreignId('timezone_id')->references('id')->on('timezones');
        });
    }

the simplest but modern way of writing pivot table migration, where the Country and Timezone are models with many-to-many relationship. And id and timestamps are not necessary to include but straightforward manner

Danish Mehmood
  • 111
  • 1
  • 7
0

in the older version, you can use some generator or artisan to make pivots, but in the newer version, this work is too easy. you must only make migration to do that like the below code.

php artisan make:migration category_post --create=category_post

after run code make migration with this params

 $table->foreignId('post_id')->constrained('post');
 $table->foreignId('category_id')->constrained('category');
Pirooz Jenabi
  • 440
  • 5
  • 7
0

1-Create a migration for the pivot table by running the following command in your terminal:

php artisan make:migration create_table_name_table

2- In the migration file, create the pivot table with the columns that you need for your relationship.

<?php Schema::create('table_name', function (Blueprint $table) { $table->unsignedBigInteger('model1_id'); $table->unsignedBigInteger('model2_id'); // add any other columns that you need for your relationship $table->timestamps(); // set up composite key $table->primary(['model1_id', 'model2_id']); // set up foreign keys $table->foreign('model1_id')->references('id')->on('model1_table')->onDelete('cascade'); $table->foreign('model2_id')->references('id')->on('model2_table')->onDelete('cascade'); });

3- In your models, set up the relationship between the two models and the pivot table.

<?php class Model1 extends Model { public function model2s() { return $this->belongsToMany(Model2::class, 'table_name', 'model1_id', 'model2_id'); } } class Model2 extends Model { public function model1s() { return $this->belongsToMany(Model1::class, 'table_name', 'model2_id', 'model1_id'); } }

4- To display the data in a pivot table format in your application, you can use the withPivot() method to retrieve the additional columns from the pivot table.

<?php $model1 = Model1::find(1); foreach ($model1->model2s as $model2) { echo $model2->pivot->column_name; // include any other columns that you need from the pivot table }

Pirooz Jenabi
  • 440
  • 5
  • 7