Laravelでの基本的なリレーションシップもしくはJOIN


Laravelっぽくリレーションシップを使うのであればEloquentのRelationshipを使うことになるでしょう。
いくつかのパターンがありますが、ここでは利用頻度が高いOne To Many(hasManyとbelongsTo)を見てみます。

また、わざわざ定義をModelに書かなくても、普通にJOINも使えますのでそれも見てみます。

その他のパターンについては、[本家サイト](http://laravel.com/docs/5.1/eloquent-relationships#one-to-many)を見て下さい。

##準備：テスト用のテーブル情報

まず、テスト用のテーブルを用意します。
ここでは、[別の記事で利用したテーブル](http://qiita.com/zaburo/items/548b3c40fee68cd1e3b7)を利用して、テストをしてみたいと思います。create情報などもあるので、必要な人はどうぞ。

テストに利用するテーブルの情報は以下の通りです。

###概要

* 部署テーブル(depts)と社員テーブル(employees)が存在。
* 社員テーブルでは所属部署をdept_idで管理（紐付け）している。

###テーブルの構造と内容

####部署テーブル(depts)

desc depts;

```bash
+-----------+-------------+------+-----+---------+-------+
| Field     | Type        | Null | Key | Default | Extra |
+-----------+-------------+------+-----+---------+-------+
| dept_id   | int(11)     | NO   | PRI | NULL    |       |
| dept_name | varchar(32) | YES  |     | NULL    |       |
+-----------+-------------+------+-----+---------+-------+
```

>このテーブルにはLaravelを利用する上で注意しなければならない点が2つります。
1つは、primary keyが"depts_id"となっていることです。Eloquentのリレーションシップは、各テーブルのキーが"id"であることを前提に動作しますので、その点についての対応が必要になります。
2つめとしては、timestampカラムがありませんので、その点についても対応が必要になります。

select * from detps;

```bash
+---------+-----------+
| dept_id | dept_name |
+---------+-----------+
|       1 | 営業部     |
|       2 | 経理部     |
|       3 | 技術部     |
|       4 | 法務部     |
+---------+-----------+
```

####社員テーブル(employees)

desc employees;

```bash
+---------+-------------+------+-----+---------+----------------+
| Field   | Type        | Null | Key | Default | Extra          |
+---------+-------------+------+-----+---------+----------------+
| id      | int(11)     | NO   | PRI | NULL    | auto_increment |
| dept_id | int(11)     | YES  |     | NULL    |                |
| name    | varchar(32) | YES  |     | NULL    |                |
+---------+-------------+------+-----+---------+----------------+
```
select * from employees;

```bash
+----+---------+--------+
| id | dept_id | name   |
+----+---------+--------+
|  1 |       1 | 田中    |
|  2 |       2 | 玉木    |
|  3 |       3 | 鈴木    |
|  4 |       3 | 山本    |
|  5 |       2 | 斉藤    |
|  6 |       1 | 佐藤    |
|  7 |       1 | 小澤    |
|  8 |       2 | 関野    |
|  9 |       0 | 中村    |
+----+---------+--------+
```

Eloquentのテストようにはやや不適切ですが、どこにも所属していない中村さんがいます。

##hasManyとbelongsTo

ではHasManyとbelongsToを見てみます。

###利用目的

そもそもリレーションシップの利用目的はなんでしょうか？多くの場合、下記のようなものです。

* ある部署に所属している社員一覧を得たい。
* 社員一覧を照会した際、部署をidではなく日本語名で得たい。

要は結合です。
素のSQLでは正規化されたテーブルを結合するにはJOIN句を利用しますが、これをEloquentでより簡単にしたいということになります。

では、具体的にEloquentのリレーションシップの使い方を見てみます。

###親テーブルと子テーブル？

技術上、2つのテーブルに親子関係はありませんが、利用上は部署テーブルが社員テーブルの親ということになるでしょう。つまり、部署の下に社員が存在しているという関係です。つまり、

* 部署にはたくさんの社員がいる(部署 hasMany 社員の関係)
* 社員はどこか１つの部署に所属している(社員 belongsTo 部署）

この関係をModelにて表現することで、リレーション機能を利用します。

###モデルの定義

Eloquentでは、複数のテーブル名を単数にし、先頭文字を大文字にしたModelが、テーブルと紐付きます。ですので、ここではDeptモデルとEmployeeというモデルを用意します。

>既存テーブルで複数になっていないものは、Model内のprotected $table = "tablename";で定義します。

モデルの雛形は、

```bash
php artisan make:model Dept
```

という感じでartisanで生成できます。

###Dept

Dept hasMany Employeeの関係です。
通常、複数の社員情報が返る可能性があります。

```php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Dept extends Model
{
    //timestamps利用しない
    public $timestamps = false;
	
	//primaryKeyの変更
    protected $primaryKey = "dept_id";
	
	//hasMany設定
    public function employees()
    {
    	return $this->hasMany('App\Employee');
    }
}
```

>紐付けに使うkeyはhasManyの第2、第3引数で制御することもできますが、$primaryKeyで設定するのが手間がないです。

###Employee

Employee belongsTo Deptの関係ですね。
基本的に所属する部署１つの情報が返ります。

```php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Employee extends Model
{
    //timestamps利用しない
    public $timestamps = false;

	//belongsTo設定
    public function dept()
    {
    	return $this->belongsTo('App\Dept');
    }
}
```

これでModelの定義が終わりました。

###使ってみる

では定義したModelを利用してみます。

####部署に誰が所属しているか？を表示

```php
Route::get('hasmany',function(){

	//id=1の部署を取得
	$dept = App\Dept::find(1);

	//所属メンバーを取得
	$employees = $dept->employees;

	//部署名表示
	echo "部署名: ".$dept->dept_name."メンバー<br>";

	//メンバー表示
	foreach($employees as $employee)
	{
		echo $employee->name."<br>";
	}

	//人数表示
	echo $employees->count()."名<br>";

	return;

});
```

要は`$dept`しか取得していないのに、その下にぶら下がる社員を`$dept->employees`で取得できるってことです。便利。

####社員一覧に部署名を表示

```php
Route::get('/belongsto',function(){

	//社員一覧取得
	$employees = App\Employee::all();

	//ループして表示
	foreach($employees as $employee)
	{
		//データにnullの値があるためif文入れる（本来はいらない）
		if(!empty($employee->dept->dept_name)) 
			//部署名取得
			echo $employee->dept->dept_name." ".$employee->name."<br>";
	}
	
	return;

});
```

社員を取得して、`$employee->dept->dept_name`で所属部署を得ることができます。

##EloquentとQueryBuilderでのJOIN句

1箇所とかだけでリレーションシップを利用したいような場合は、いちいちModelをいじるのもめんどいものです。
そんな場合は、EloquentやQueryBuilderのクエリ？文の中で、JOINも使えます。

```php
Route::get('join',function(){

	//eloquent
	$employees = App\Employee::select()
					->join('depts','depts.dept_id','=','employees.dept_id')
					->get();

	//表示
	foreach($employees as $employee)
	{
		echo $employee->dept_name." ".$employee->name."<br>";
		//eloquentは、echo $employee['dept_name']でも動く。
	}

	echo "---------------------------------<br>";

	//query builder
	$employees = \DB::table('employees')
					->join('depts','employees.dept_id','=','depts.dept_id')
					->get();


	foreach($employees as $employee)
	{
		//表示
		echo $employee->dept_name." ".$employee->name."<br>";
	}

	return;		
});
```

2つのテーブルをJOINさせるとき、id名がかぶる場合があります。そういう時は、`->get();`内で、`->get(["a.id as aid","b.id as bid"]);`などと指定すればよいようです。

普通にjoinするとinner joinのようですが、`->leftJoin()`とすることもできるようです。

##その他

EloquentはLaravel以外でも使えます。[こちら](http://qiita.com/zaburo/items/9b8aa05c975677669142)の情報も合わせてどうぞ。