初めてのLaravel 5.1 : (31) Relationships

今回は、モデルで1対nのリレーションを扱いたいと思います。ユーザーが複数の記事を持つ様に、UserモデルとArticleモデルを関連付けます。


Model

UserモデルとArticleモデルを1対nで関連付けます。

User

// app/User.php

class User extends Model implements AuthenticatableContract, CanResetPasswordContract
{
	...
	public function articles() 
	{
		return $this->hasMany('App\Article');
	}
}

articles() メソッドを作成し、hasMany() メソッドで ‘AppArticle’ と関連付けます。
これで以下のように Userに関連付く Articleをn件取得できるようになります。

$articles = User::find(1)->articles();

Article

// app/Article.php

class Article extends Model
{
	...
	public function user() 
	{
		return $this->belongsTo('App\User');
	}
}

user() メソッドを作成し、belongsTo() メソッドで ‘AppUser’ と関連付けます。
これで以下の様に Articleに関連付く Userを1件取得できるようになります。

$user = Article::find(1)->user();

MIgration

ArticlesテーブルにUsersテーブルへの外部キーを追加します。以前に作成したマイグレーションファイルを直接修正し、DBは全てロールバックして、初めから再構築したいと思います。

<?php
// database/migrations/YYYY_MM_DD_TTTTTT_create_articles_table.php

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

class CreateArticlesTable extends Migration
{
	public function up()
	{
		Schema::create('articles', function(Blueprint $table)
		{
			$table->increments('id');
			$table->integer('user_id')->unsigned();	// 追加
			$table->string('title');
			$table->text('body');
			$table->timestamps();

			// 外部キーを追加
			$table->foreign('user_id')
						->references('id')
						->on('users')
						->onDelete('cascade');
		});
	}

	public function down()
	{
		Schema::drop('articles');
	}
}

user_id を外部キーとして追加しました。外部キー制約に onDelete(‘cascade’) を指定し、親レコードである Usersのデータが削除されたら、子レコードである Articlesのデータも削除するように指定しました。

では、以下のように artisan コマンドでDBを全てロールバックし、再度全マイグレーションを実行します。データは全て消えてしまうのでご注意ください。

php artisan migrate:refresh

Seed

Articlesテーブルの変更に伴い、Seedも修正します。

<?php

use App\User;
use App\Article;
use Carbon\Carbon;
use Faker\Factory as Faker;
use Illuminate\Database\Seeder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;

class DatabaseSeeder extends Seeder
{

	public function run()
	{
		Model::unguard();

		$this->call('UsersTableSeeder');  // 追加
		$this->call('ArticlesTableSeeder');

        	Model::reguard();
	}

}

// 追加
class UsersTableSeeder extends Seeder
{

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

		User::create([
			'name' => 'root',
			'email' => 'root@sample.com',
			'password' => bcrypt('password')
		]);
	}
}

class ArticlesTableSeeder extends Seeder
{

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

		$user = User::all()->first();
		$faker = Faker::create('en_US');

		for ($i = 0; $i &amp;lt; 10; $i++) {
			// Article::create([
			// 	'title' => $faker->sentence(),
			// 	'body' => $faker->paragraph(),
			// 	'published_at' => CarbonCarbon::today(),
			// ]);

			// 変更
			$article = new Article([
				'title' => $faker->sentence(),
				'body' => $faker->paragraph(),
				'published_at' => Carbon::now(),
			]);
			$user->articles()->save($article);  // $userと関連付けて $articleを保存
		}
	}
}
  • ユーザーデータを1件追加するようにしました。
  • 記事データをユーザーと関連付けて保存するよう変更しました。

artisan コマンドで seedを実行します。

php artisan db:seed

Controller

記事の新規登録時に、ユーザーと関連付ける様、修正します。

// app/Http/Controllers/ArticlesController.php

class ArticlesController extends Controller {
	...
	public function store(ArticleRequest $request) {
		// Article::create($request->all());
		\Auth::user()->articles()->create($request->all());

		\Session::flash('flash_message', '記事を追加しました。');

		return redirect()->route('articles.index');
	}
	...
}

store() メソッドで新規の記事を、ログイン中のユーザーの記事として保存します。


動作確認

ログインして、記事を新規作成した後に、tinkerでデータを確認してみます。
新規のユーザーを http://localhost:8000/auth/register から登録して、色々試してみてください。

$ php artisan tinker
>>>
>>> $user = App\User::where("name", "who")->first();
>>>
>>> $user->articles->count();
=> 2
>>>
>>> $user->articles->toArray();
=> [
       [
           "id"           => "11",
           "user_id"      => "5",
           "title"        => "WHOの記事",
           "body"         => "かくかくrnしかじか",
           "created_at"   => "2015-03-24 11:56:17",
           "updated_at"   => "2015-03-24 11:56:17",
           "published_at" => "2015-03-24 00:00:00"
       ],
       [
           "id"           => "12",
           "user_id"      => "5",
           "title"        => "WHOの2件目の記事",
           "body"         => "foornbar",
           "created_at"   => "2015-03-24 12:05:31",
           "updated_at"   => "2015-03-24 12:05:31",
           "published_at" => "2015-03-24 00:00:00"
       ]
   ]
>>>
>>>
>>> $article = App\Article::find(11);
>>>
>>> $article->user->toArray();
=> [
       "id"         => "5",
       "name"       => "who",
       "email"      => "who@sample.com",
       "created_at" => "2015-03-24 11:55:55",
       "updated_at" => "2015-03-24 11:55:55"
   ]
>>> 
  • $user->articlesでユーザーモデルから記事にアクセス出来ました。
  • $article->userで記事モデルからユーザーモデルにアクセス出来ました。

まとめ

hasMany(), belongsTo() を使って、モデルの1対nのリレーションを作ることが出来るようになりました。

Eloquentのリレーションには、1対nの他にも、1対1やn対n等もありますので、公式サイトには目を通しておいてください。
http://laravel.com/docs/5.1/eloquent-relationships

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中