【メモ】Laravel5.5で会員詳細ページをリレーションを使用して取得する方法


##はじめに
現在、Laravelを使って一般的なECサイトを作成しています。
勉強の記録です。
アドバイスを頂けると泣いて喜びます。

##やろうとしていること
ECサイトを作成しているの中で、登録会員一覧ページの会員詳細画面をリレーションを使って取得してスマートに表示しようとしています。

今回取得したいデータが、会員氏名、メールアドレス、お届け先住所を取得したい。

userモデルから「name」「email」
addressモデルから[postal_code」「prefectures」「municipality」「address」
なおaddressモデルには「user_id」カラムがある。

各会員はaddressモデルに住所を何個でも設定することができるが、お届け先登録住所は一つのみ。
なお、お届け先登録された住所はaddressモデルのselectカラムの1(true)で登録されている。

| userテーブル | addressテーブル | 
|:-----------|------------:|
| id       | id        |
| name     | user_id      |
| email       | postal_code        |
|         | prefectures          |
|       | municipality       |
|     | address     |
|     | select    |

</table>

##コード

###ルーティング

```php:routes/web.php
Route::group(['prefix' => 'admin', 'middleware' => 'auth:admin'], function() {
	Route::get('user_index', 'AccountController@index')->name('account.index');
	Route::get('user_detail/{id}', 'AccountController@detail')->name('account.detail');
});
```

解説
管理者のみの閲覧しか許可しないため、middlewareでadminログイン以外の人を弾くように設定
会員詳細画面はルーティングのパラメータでユーザーIDを取得しています。

なお、getで会員一覧ページに入るためのaタグはヘッダーに記述しています。

###モデル

```php:app/User.php
<?php

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password',
	];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
	];

	public function carts() {
		return $this->hasMany('\App\Cart');

	}

	public function addresses() {
		return $this->hasMany('\App\Address');

	}
}
```

###解説
ユーザーに対して一つ以上の住所が設定できるため、1対多の関係になるためhasManyを使用してリレーション設定
このコードでuserのidカラムとaddressのuser_idカラムが紐付けることができます。

[リレーションについて不明な方はこちら]
(https://qiita.com/mtakehara21/items/3cef9d12869d162e1ce9)

###コントローラー

```php:app/Http/Controllers/AccountController
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\User;
use App\Address;

class AccountController extends Controller
{
	public function index() {
		$users = User::all();
		return view('account.index', compact('users'));
	}

	public function detail($id) {
		$user = User::with(['addresses' => function($query) {
			$query->where('select', 1);
		}])->findOrFail($id);

		return view('account.detail', compact('user'));

	}
}
```

###解説
会員一覧ページはindexアクションでユーザー情報を全て取得してviewに送ります。
名前しか表示しないため、今回はこれだけ

会員詳細ページはdetailアクションで実行
ルーティングで受け取るユーザーIDを取得
そこから、withで先程記載したリレーションメソッド名を記述してaddressテーブルの情報も同時に取得
その際に、addressテーブルからはお届け先住所のみ指定したいため、selectカラムの１(true)の情報だけ指定して取得する。
ルーティングパラーメーターで受け取ったidでuserテーブルから存在するか同時にチェックして見つからなかったらerror401を飛ばすコードがfindOrFailメソッドで実行する
あとはその情報をviewのdetailページに渡すだけ


*参考記事*
[リレーション先の条件指定についての記事はこちら](https://www.webopixel.net/php/1412.html)

*よくある間違い*
whereHasとwithはリレーション先の情報を取得するかしないかで使用用途が異なってきます。

whereHasはリレーション先でクエリー文を走らせる事ができますが、リレーション先の情報を取得することができません。
withは上記の様なコードでリレーション先でクエリー文を走らせながら、リレーション先の情報を取得することができます。



###view

```php:resources/views/account/index.blade.php
@extends('layouts.app_admin')

@section('content')
<h1>会員一覧ページ</h1>
<table>
<tr>
<th>名前</th>
</tr>
@isset ($users)
@foreach ($users as $user)
<tr>
<td><a href="{{route('account.detail', ['id' => $user->id])}}">{{$user->name}}</a></td>
</tr>
@endforeach
@endisset
</table>
<a href="{{route('admin.index')}}">登録商品一覧</a>
</body>
</html>
@endsection
```


```php:resources/views/account/detail.blade.php
@extends('layouts.app_admin')

@section('content')
<h1>会員詳細ページ</h1>
<table>
<tr>
<th>名前</th>
<th>メールアドレス</th>
<th>お届け先住所</th>
</tr>
<tr>
<td>{{$user->name}}</td>
<td>{{$user->email}}</td>
@isset ($user->addresses[0])
<td>【郵便番号】:{{$user->addresses[0]->postal_code}}
</br>【都道府県】:{{$user->addresses[0]->prefectures}}
</br>【市区町村】:{{$user->addresses[0]->municipality}}
</br>【マンション・アパート名】:{{$user->addresses[0]->address}}
</td>
@else
<td>選択されていません</td>
@endisset
</tr>
</table>
<a href="{{route('admin.index')}}">登録商品一覧</a>
</body>
</html>
@endsection
```

###解説
index.blade.phpではユーザー名だけ用意してルートパラメータでdetailアクションに渡しています。route('account.detail', ['id' => $user->id])

detail.blade.phpでは会員詳細ページを表示しています。
疑問は、これで取得すると$user->addresses->postal_codeではエラーがでます。
デバックで確認してみると余計な0が紛れ込んでいたためこのようなブサイクなコードとなりました。
![デバック時のリレーションデータ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1050579/e519c3b1-2904-2a23-e7ad-99ad1c0d58bb.png)


この部分は誰かもっとスマートに書ける方法を教えて下さい、、