Laravel5のEloquentORMで1対多のリレーション(その3)

今日は、Gathersに詳細データを添付したいと思います。新たに、detailsテーブルと、itemsテーブルを作成します。detailsテーブルに詳細情報を登録するのですが、detailsの詳細情報の項目名は、itemsテーブルから参照することにします。

  1. detailsテーブル
    • カラム(id,gather_id,item_id,.content+タイムスタンプ)
  2. itemsテーブル
    • カラム(id,name,sort)

テーブルの作成

SetupControllerのgetCreateメソッドを下記のように修正します。

app/Http/Controllers/SetupController.php

 public function getCreate($db_table)
 {
 //テーブルの存在確認
 if(Schema::hasTable($db_table)){
 return redirect()
 ->back()
 ->withMessage("{$db_table}テーブルが存在しますので、処理を中止します")
 ->withAlert("alert alert-danger");
 }
 if($db_table == 'gathers'):
 Schema::create($db_table, function(Blueprint $table)
 {
 $table->increments('id');
 $table->string('name',100);
 $table->integer('category_id')->index();
 $table->string('code',100)->index();
 $table->text('description')->nullable();
 $table->timestamps();
 $table->timestamp('deleted_at',null)->nullable();
 });
 return redirect()
 ->back()
 ->withMessage("{$db_table}テーブルを作成しました")
 ->withAlert('alert alert-success');
 elseif($db_table == 'categories'):
 Schema::create($db_table, function(Blueprint $table)
 {
 $table->increments('id');
 $table->string('name',100);
 $table->text('description')->nullable();
 });
 return redirect()
 ->back()
 ->withMessage("{$db_table}テーブルを作成しました")
 ->withAlert("alert alert-success");
 elseif($db_table == 'details'):
 Schema::create($db_table, function(Blueprint $table)
 {
 $table->increments('id');
 $table->integer('gather_id');
 $table->integer('item_id');
 $table->text('content');
 $table->timestamps();
 $table->timestamp('deleted_at',null)->nullable();
 });
 return redirect()
 ->back()
 ->withMessage("{$db_table}テーブルを作成しました")
 ->withAlert("alert alert-success");
 elseif($db_table == 'items'):
 Schema::create($db_table, function(Blueprint $table)
 {
 $table->increments('id');
 $table->string('name',100);
 $table->integer('sort')->default(1);
 });
 return redirect()
 ->back()
 ->withMessage("{$db_table}テーブルを作成しました")
 ->withAlert("alert alert-success");
 else:
 Schema::create($db_table, function(Blueprint $table)
 {
 $table->increments('id');
 $table->string('name');
 $table->text('description')->nullable();
 $table->timestamps();
 $table->timestamp('deleted_at',null)->nullable();
 });
 return redirect()
 ->back()
 ->withMessage("{$db_table}テーブルを作成しました")
 ->withAlert('alert alert-success');
 endif;
}

setupビューを下記のように修正します。

app/resources/views/setup/index.blade.php

@extends('app')
@section('content')
<div class="container">
<h2>テーブルの作成</h2>
@if(Session::has('message'))
<p class="{{Session::get('alert')}}">
{{ Session::get('message') }}
</p>
@endif
<a href="{{ url('setup/create/gathers') }}" type="button" class="btn btn-primary btn-lg btn-block">gathersテーブルの作成</a>
<a href="{{ url('setup/create/categories') }}" type="button" class="btn btn-primary btn-lg btn-block">categoriesテーブルの作成</a>
<a href="{{ url('setup/create/details') }}" type="button" class="btn btn-primary btn-lg btn-block">detailsテーブルの作成</a>
<a href="{{ url('setup/create/items') }}" type="button" class="btn btn-primary btn-lg btn-block">itemsテーブルの作成</a>
</div>
@endsection

下記のようなテーブルが生成されます。

2015-05-26 14-53-13

2015-05-26 14-54-46

モデルの生成

detailsテーブルと、itemsテーブルを作成したら、モデルを生成します。

コマンドプロンプトから下記のように入力します。

php artisan make:model Detail
php aritsan make:model Item

生成したモデルを下記のように修正します。

app/Detail.php

<?php namespace App;

use Illuminate\Database\Eloquent\Model;

class Detail extends Model {
 
 //複数代入のブラックリスト
 protected $guarded=['id','created_at','updated_at','deleted_at']; 
 
 /* 
 * 1対多のリレーション
 * DetailはItemに従属している
 */
 public function item(){
 return $this->belongsTo('App\Item');
 }
 
}

14-16行目:1対多のリレーションを設定します。belongsToメソッドの第1引数は、リレーションを行うモデルを指定します。Laravel4では、ここは単にItem(モデル名)でしたので、名前空間付きのApp\Itemに変更になっていることを忘れないでください。私は、ここでかなりはまってしまいました。第2引数は、外部ID、第3引数は、内部IDですが、いずれも規約通り(外部IDが、item_id、内部IDがid)に作成していれば、省略できます。

app/Item.php

<?php namespace App;
use Illuminate\Database\Eloquent\Model;
class Item extends Model {
 
 //複数代入のブラックリスト
 protected $guarded=['id'];
 
 //自動タイムスタンプの無効化
 public $timestamps=false;
}

ここでは、リレーションを設定していませんが、Itemモデルから、Detailモデルを呼び出す場合は、hasManyメソッドでApp\Detailを指定する必要があります。

又、Itemモデルには、created_atとupdated_atは作成していませんので、自動タイムスタンプを無効にしておく必要があります。

Gatherモデルの修正

ついでにGatherモデルにもリレーションを設定します。下記を追加します。

app/Gather.php

public function detail(){
 return $this->hasMany('App\Detail');
 }
}

GatherモデルとDetailモデルをリレーションでつなぎます。これで、下記のようにアクセスすることができます。

  • $gather=Gather::find($id);
    foreach($gather->detail as $detail):
    $detail->item->name; //Itemモデルのnameプロパティにアクセス
    $detail->content; //Detailモデルのcontentプロパティにアクセス
    endforeach;

本日は、ここまでにします。

このエントリーを含むはてなブックマーク Buzzurlにブックマーク livedoorクリップ Yahoo!ブックマークに登録

トラックバック&コメント

この投稿のトラックバックURL:

コメントをどうぞ

このページの先頭へ