LoginSignup
4
4

More than 3 years have passed since last update.

Laravelのリレーション、Eloquentについて

Last updated at Posted at 2020-01-25

Eloquentについて

データベースとモデルを紐つける機能

1対1

例題

今回はUsersとProfilesテーブルの連携について考えます。
ユーザーを管理するテーブルにはidとnameカラムがあります。
プロフィールを管理するテーブルにはidとuser_idとurlがあります。
1対1のリレーションでは1人のユーザーは1つのプロフィールを持っていることが前提となります。

Userモデルの作成

$ php artisan make:model User -m
Model created successfully.
Created Migration: 2020_01_14_084605_create_users_table
database/migrations/2020_01_14_084605_create_users_table
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->bigIncrements('id');
+           $table->string('name');
            $table->timestamps();
        });
    }

Profileモデルの作成

$ php artisan make:model Profile -m
Model created successfully.
Created Migration: 2020_01_14_090207_create_profiles_table
database/migrations/
    public function up()
    {
        Schema::create('profiles', function (Blueprint $table) {
            $table->bigIncrements('id');
+           $table->integer('user_id');
+           $table->string('url');
            $table->timestamps();
        });
    }

ポイント

UserモデルにhasOneを定義

テーブル間の関係はuserテーブルのidをprofileテーブルのuser_idで紐つける。

Userモデルに定義する

app/User.php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
  public function profile() {
    return $this->hasOne(Profile::class);
  }
}

Profileモデルに定義する

app/Profile.php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Profile extends Model
{
    public function user() {
      return $this->belongsTo(User::class);
    }
}

データベースにデータを挿入する。

DatabaseSeeder.phpを編集

database/seeds/DatabseSeeder.php
    public function run()
    {
       $this->call(UsersTableSeeder::class);
       $this->call(ProfilesTableSeeder::class);
    }

UsersTableSeeder.php

database/seeds/UsersTableSeeder.php

ProfilesTableSeeder.php

database/seeds/ProfilesTableSeeder.php

tinkerで確認

$ php artisan tinker
Psy Shell v0.9.12 (PHP 7.3.13 — cli) by Justin Hileman
>>> $user = User::find(1);
[!] Aliasing 'User' to 'App\User' for this Tinker session.
=> App\User {#2980
     id: 1,
     name: "Enomoto Riko",
     created_at: "2020-01-14 09:13:35",
     updated_at: "2020-01-14 09:13:35",
   }
>>> $user->profile;
=> App\Profile {#2983
     id: 4,
     user_id: 1,
     url: "https://1",
     created_at: "2020-01-14 09:22:02",
     updated_at: "2020-01-14 09:22:02",
   }
>>> 

1対多

例)ユーザーを管理しているuserテーブルとユーザーが注文したNoを管理しているordersテーブルで考えてみる。ユーザーはたくさんの注文をしており、注文は整数のNoで管理されている。

Orderモデルの作成

php artisan make:model Order -m
Model created successfully.
Created Migration: 2020_01_23_124628_create_orders_table

odersテーブルを作成

database/migrations/2020_01_23_124628_create_orders_table.php
    public function up()
    {
        Schema::create('orders', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->integer('user_id');
            $table->integer('order_no');
            $table->timestamps();
        });
    }
$ php artisan migrate
Migrating: 2020_01_23_124628_create_orders_table
Migrated:  2020_01_23_124628_create_orders_table (0.03 seconds)

seederファイルの作成

php artisan make:seeder OrdersTableSeeder  
Seeder created successfully.

OrdersTableSeederの編集

database/seeds/OrdersTableSeeder
    public function run()
    {
      DB::table('orders')->insert([
      ['user_id' => 3,'order_no' => '00001','created_at' => new Datetime(),'updated_at' => new Datetime()],
      ['user_id' => 3,'order_no' => '00002','created_at' => new Datetime(),'updated_at' => new Datetime()],
      ['user_id' => 4,'order_no' => '00003','created_at' => new Datetime(),'updated_at' => new Datetime()],
      ['user_id' => 2,'order_no' => '00004','created_at' => new Datetime(),'updated_at' => new Datetime()],
      ['user_id' => 1,'order_no' => '00005','created_at' => new Datetime(),'updated_at' => new Datetime()],
      ['user_id' => 3,'order_no' => '00006','created_at' => new Datetime(),'updated_at' => new Datetime()],
      ['user_id' => 5,'order_no' => '00007','created_at' => new Datetime(),'updated_at' => new Datetime()],
      ['user_id' => 1,'order_no' => '00008','created_at' => new Datetime(),'updated_at' => new Datetime()],
      ['user_id' => 4,'order_no' => '00009','created_at' => new Datetime(),'updated_at' => new Datetime()],
      ['user_id' => 5,'order_no' => '00010','created_at' => new Datetime(),'updated_at' => new Datetime()],
    ]);

    }

DatabaseSeeder.phpの編集

seederの実行

tinkerで確認

$user = User::find(1);
=> App\User {#2973
     id: 1,
     name: "Enomoto",
     created_at: "2020-01-23 13:15:07",
     updated_at: "2020-01-23 13:15:07",
   }
>>> $user->order;
=> Illuminate\Database\Eloquent\Collection {#3001
     all: [
       App\Order {#2998
         id: 5,
         user_id: 1,
         order_no: "00005",
         created_at: "2020-01-23 13:15:07",
         updated_at: "2020-01-23 13:15:07",
       },
       App\Order {#2997
         id: 8,
         user_id: 1,
         order_no: "00008",
         created_at: "2020-01-23 13:15:07",
         updated_at: "2020-01-23 13:15:07",
       },
     ],
   }

多対多

例)ユーザーテーブルとスキルテーブルで確認します。
スキルテーブルにはプログラミングの言語が入っています。
あるユーザは複数のプログラミングを扱えるとします。

Skillモデルを作成します。

$ php artisan make:model Skill -m
Model created successfully.
Created Migration: 2020_01_24_134708_create_skills_table

skillsテーブルの作成

    public function up()
    {
        Schema::create('skills', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('language');
            $table->timestamps();
        });
    }

migration実行

$ php artisan migrate
Migrating: 2020_01_24_134708_create_skills_table
Migrated:  2020_01_24_134708_create_skills_table (0.03 seconds)

seederファイルの作成

$ php artisan make:seeder SkillsTableSeeder
Seeder created successfully.

seederを実行する

database/seeds/DatabaseSeeder.php
    public function run()
    {
       // $this->call(UsersTableSeeder::class);
       // $this->call(ProfilesTableSeeder::class);
       // $this->call(OrdersTableSeeder::class);
       $this->call(SkillsTableSeeder::class);
    }

実行

$ php artisan db:seed
Seeding: SkillsTableSeeder
Database seeding completed successfully.

中間テーブルuser_skillの作成

migrationファイルの作成

$ php artisan make:migration create_user_skill_table
Created Migration: 2020_01_25_012117_create_user_skill_table

user_skillテーブルの作成

database/migrations/2020_01_25_012117_create_user_skill_table
    public function up()
    {
        Schema::create('user_skill', function (Blueprint $table) {
            $table->bigInteger('user_id')->unsigned();
            $table->bigInteger('skill_id')->unsigned();
            $table->primary(['user_id','skill_id']);

            //外部キー制約
            $table->foreign('user_id')
                ->references('id')
                ->on('users')
                ->onDelete('cascade');
            //
            $table->foreign('skill_id')
                ->references('id')
                ->on('skills')
                ->onDelete('cascade');

        });
    }

migrateの実行

seeder関連

database/seeds/UserSkillTableSeeder
    public function run()
    {
      DB::table('skill_user')->insert([
     ['user_id' => 1, "skill_id" => 1],
     ['user_id' => 1, "skill_id" => 3],
     ['user_id' => 2, "skill_id" => 2],
     ['user_id' => 2, "skill_id" => 3],
     ['user_id' => 3, "skill_id" => 4],
     ['user_id' => 4, "skill_id" => 5],
     ['user_id' => 5, "skill_id" => 1],
   ]);

    }

モデル関連の修正

Userモデル編集

app/User.php
  public function skills() {
    return $this->belongsToMany(Skill::class);
  }

Skillモデルの編集

app/Skill.php
  public function users() {
    return $this->belongsToMany(User::class);
  }

tinkerで確認

$ php artisan tinker
Psy Shell v0.9.12 (PHP 7.3.13 — cli) by Justin Hileman
>>> $skill = Skill::find(1);
[!] Aliasing 'Skill' to 'App\Skill' for this Tinker session.
=> App\Skill {#2980
     id: 1,
     language: "HTML",
     created_at: "2020-01-25 03:15:24",
     updated_at: "2020-01-25 03:15:24",
   }
>>> $skill->users;
=> Illuminate\Database\Eloquent\Collection {#2981
     all: [
       App\User {#2984
         id: 1,
         name: "Enomoto",
         created_at: "2020-01-25 03:15:24",
         updated_at: "2020-01-25 03:15:24",
         pivot: Illuminate\Database\Eloquent\Relations\Pivot {#2983
           skill_id: 1,
           user_id: 1,
         },
       },
       App\User {#2988
         id: 5,
         name: "Sugihara",
         created_at: "2020-01-25 03:15:24",
         updated_at: "2020-01-25 03:15:24",
         pivot: Illuminate\Database\Eloquent\Relations\Pivot {#2986
           skill_id: 1,
           user_id: 5,
         },
       },
     ],
   }
>>> 

番外編:id以外をprimary_keyにするuserのnameで紐つける

usersテーブルのmigrationファイルを修正

database/migrations/2020_01_14_084605_create_users_table.php
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            // $table->bigIncrements('id');
            $table->string('name')->primary();
            $table->timestamps();
        });
    }

profilesテーブルのmigrationファイルを修正

database/migrations/2020_01_14_090207_create_profiles_table.php
    public function up()
    {
        Schema::create('profiles', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('user_name');
            $table->string('url');
            $table->timestamps();
        });
    }

ポイント:テーブル名_プライマリーキー→user_name

Userモデルを編集

app/User.php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
  protected $primaryKey = "name";
  protected $keyType = "string";
  public $incrementing = false;

  public function profile() {
    return $this->hasOne(Profile::class);
  }
}

protected $primaryKey = "name";

nameカラムをプライマリーキーに設定

public $incrementing = false;

1づつ増えていく整数にしない場合

データベースにデータを挿入

usersテーブルに挿入するデータ

database/seeds/UsersTableSeeder.php
    public function run()
    {
      DB::table('users')->insert([
     ['name' => 'Enomoto','created_at' => new Datetime(),'updated_at' => new Datetime()],
     ['name' => 'Amano','created_at' => new Datetime(),'updated_at' => new Datetime()],
     ['name' => 'Shimamura','created_at' => new Datetime(),'updated_at' => new Datetime()],
     ['name' => 'Hirai','created_at' => new Datetime(),'updated_at' => new Datetime()],
     ['name' => 'Sugihara','created_at' => new Datetime(),'updated_at' => new Datetime()],
   ]);
  }
}

profilesテーブルにデータを挿入

database/seeds/ProfilesTableSeeder.php
    public function run()
    {
      DB::table('profiles')->insert([
      ['user_name' => 'Amano','url' => "https://AmanoYasushi",'created_at' => new Datetime(),'updated_at' => new Datetime()],
      ['user_name' => 'Sugihara','url' => "https://SugiharaGensei",'created_at' => new Datetime(),'updated_at' => new Datetime()],
      ['user_name' => 'Enomoto','url' => "https://EnomotoRiko",'created_at' => new Datetime(),'updated_at' => new Datetime()],
      ['user_name' => 'Shimamura','url' => "https://ShimamuraMayu",'created_at' => new Datetime(),'updated_at' => new Datetime()],
      ['user_name' => 'Hirai','url' => "https://HiraiHana",'created_at' => new Datetime(),'updated_at' => new Datetime()],
    ]);
   }
}

tinkerで確認

$ php artisan tinker
Psy Shell v0.9.12 (PHP 7.3.13 — cli) by Justin Hileman
>>> $user = User::find('Amano');
[!] Aliasing 'User' to 'App\User' for this Tinker session.
=> App\User {#2980
     name: "Amano",
     created_at: "2020-01-22 11:54:31",
     updated_at: "2020-01-22 11:54:31",
   }
>>> $user->profile;
=> App\Profile {#2983
     id: 1,
     user_name: "Amano",
     url: "https://AmanoYasushi",
     created_at: "2020-01-22 11:54:31",
     updated_at: "2020-01-22 11:54:31",
   }

中間テーブルへの書き込みと削除について

attach関数を使う

$userにidが1のユーザーを代入する。

>>> $user = User::find(1);
=> App\User {#2998
     id: 1,
     name: "Enomoto",
     created_at: "2020-01-25 03:15:24",
     updated_at: "2020-01-25 03:15:24",
   }

userとskillの中間テーブルに書き込む

  • user_idが1、skill_idが1
  • user_idが1、skill_idが2
  • user_idが1、skill_idが3 にするために、$skillsに配列で1,2,3を渡す
>>> $skills = array(1,2,3);
=> [
     1,
     2,
     3,
   ]

attach関数を使って、中間テーブルに書き込む

>>> $user->skills()->attach($skills);
=> null

中間テーブルでuser_idの1と紐ついている物を出力する。

>>> $user->skills;
=> Illuminate\Database\Eloquent\Collection {#3016
     all: [
       App\Skill {#2990
         id: 1,
         language: "HTML",
         created_at: "2020-01-25 03:15:24",
         updated_at: "2020-01-25 03:15:24",
         pivot: Illuminate\Database\Eloquent\Relations\Pivot {#2994
           user_id: 1,
           skill_id: 1,
         },
       },
       App\Skill {#3013
         id: 2,
         language: "CSS",
         created_at: "2020-01-25 03:15:24",
         updated_at: "2020-01-25 03:15:24",
         pivot: Illuminate\Database\Eloquent\Relations\Pivot {#2991
           user_id: 1,
           skill_id: 2,
         },
       },
       App\Skill {#3031
         id: 3,
         language: "javascript",
         created_at: "2020-01-25 03:15:24",
         updated_at: "2020-01-25 03:15:24",
         pivot: Illuminate\Database\Eloquent\Relations\Pivot {#3028
           user_id: 1,
           skill_id: 3,
         },
       },
     ],
   }
>>> 

detachメソッドを使って、user_idが1と紐ついているカラムを削除する

>>> $user->skills()->detach();
=> 5
>>> $user = user::find(1);
=> App\User {#3015
     id: 1,
     name: "Enomoto",
     created_at: "2020-01-25 03:15:24",
     updated_at: "2020-01-25 03:15:24",
   }

user_idが1のものが削除されていることを確認する。

>>> $user->skills;
=> Illuminate\Database\Eloquent\Collection {#2987
     all: [],
   }

$user = User::find('Amano');

プライマリーキーのnameをAmanoで検索

$user->profile;

profilesテーブルからnameの"Amano"に該当する外部キーuser_nameからデータを取得

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4