LoginSignup
17
14

More than 3 years have passed since last update.

【Laravel】リレーション先のリレーションのデータの表示の仕方

Last updated at Posted at 2021-03-21

0.はじめに

本記事ではLaravel 5.8 での開発で得たものを取り上げております。

なぜ本記事を作成しようかと思ったのか、

Laravelの学習で ORM を用いてECサイトの注文履歴の表示画面を作っていた時に、
「リレーション先のさらに先」の情報を取得して表示させる必要がありましたが、

「データベースからの情報取得方法」を書いた記事は多く見つけられるものの、
「取得したデータの "表示" の仕方」についての記事はあまり見つけられなかったからです。
(探し方が良くなかったのかもしれませんが^^;)

「dd()で取得したレコードの確認までは出来ているが、表示させるのにエラーが出てうまくいかない!」
自分はこれで時間をだいぶ消費してしまいましたので、他の初学者がよりスムーズに開発の学習が行えるよう記事を作成いたしました。

おかしい所がありましたら、ぜひご指摘いただければと思います。

1.注文履歴表示画面に関わる情報

・ER図

image.png

・各モデル

Order.php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Order extends Model
{
    protected $table = 't_orders';

    public function user()
    {
        return $this->belongsTo('App\User');
    }

    public function orderDetails()
    {
        return $this->hasMany('App\OrderDetail' , 'order_id');
    }
}
OrderDetail.php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class OrderDetail extends Model
{
    protected $table = 't_order_details';

    public $timestamps = false;

    protected $fillable = [
        'product_id',
        'order_id',
        'shipment_status_id',
        'order_quantity',
    ];

    public function order()
    {
        return $this->belongsTo('App\Order','order_id');
    }

    public function shipmentStatuses()
    {
        return $this->belongsTo('App\ShipmentStatus', 'shipment_status_id');
    }

    public function products()
    {
        return $this->belongsTo('App\Product', 'id');
    }
}
ShipmentStatus.php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class ShipmentStatus extends Model
{
    protected $table = 'm_shipment_statuses';

    protected $fillable = [
        'shipment_status_name',
    ];

    public function orderDetails()
    {
        return $this->hasMany('App\OrderDetail','id');
    }
}
User.php
<?php

namespace App;

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

class User extends Authenticatable
{
    use Notifiable;
    protected $table = 'm_users';
    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'last_name',
        'first_name',
        'zipcode',
        'prefecture',
        'municipality',
        'address',
        'apartments',
        'email',
        'phone_number',
        'password',
        'company_name'
    ];

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

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];

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

    public function products()
    {
        return $this->hasMany('App\Product', 'user_id');
    }
}

※Laravelの認証機能を使用しています。
(この機能を利用してログイン中のユーザーIDを取得し注文情報の検索を行います。)

・コントローラー

OrderController
class OrderController extends Controller
{
    public function getHistory (Request $request)
    {
        //ログイン中のユーザーIDをもとに注文情報を取得する
        $orderInformations = Order::where('user_id', Auth::id())
            ->with(['user', 'orderDetails.shipmentStatuses'])
            ->orderBy('order_date', 'desc')
            ->paginate(3);

・現在データベースに収容されている情報(各seederより抜粋)

t_ordersテーブル
        DB::table('t_orders')->insert([
            [
                'user_id' => 1,
                'order_number' => 1,
                'order_date' => date('2020-10-22 13:55:19'),
            ],
            [
                'user_id' => 1,
                'order_number' => 2,
                'order_date' => date('2020-05-03 16:32:52'),
            ],
t_order_detailsテーブル
        DB::table('t_order_details')->insert([
            [
                'products_id' => 1,
                'order_id' => 1,
                'shipment_status_id' => 2,
                'order_quantity' => 1,
                'shipment_date' => date('2020-10-23 20:55:19'),
            ],
            [
                'products_id' => 2,
                'order_id' => 1,
                'shipment_status_id' => 2,
                'order_quantity' => 2,
                'shipment_date' => date('2020-10-23 20:55:19'),
            ],
            [
                'products_id' => 3,
                'order_id' => 2,
                'shipment_status_id' => 1,
                'order_quantity' => 3,
                'shipment_date' => date('Y-m-d H:i:s'),
            ],
m_shipment_statusesテーブル
        DB::table('m_shipment_statuses')->insert([
            [
                'shipment_status_name' => '準備中',
            ],
            [
                'shipment_status_name' => '発送済',
            ],
            [
                'shipment_status_name' => '入荷待ち',
            ],
            [
                'shipment_status_name' => 'キャンセル',
            ],
m_usersテーブル
        DB::table('m_users')->insert([
            [
                'password' => bcrypt('sample1'),
                'last_name' => '太郎',
                'first_name' => '田中',
                'zipcode' => '1200003',
                'prefecture' => '東京都',
                'municipality' => '足立区',
                'address' => '1-1-1',
                'apartments' => '101号室',
                'email' => 'sample1@sample.com',
                'phone_number' => '11111111111',
                'user_classification_id' => '2',
                'company_name' => '株式会社A',
                'delete_flag' => '0',
            ],

2.コントローラーからデータベース(以下DB)へ情報を要求

orderController.php
class OrdersController extends Controller
{
    public function getHistory (Request $request)
    {
        //ログイン中のユーザーIDをもとに注文情報を取得する
        $orderInformations = Order::where('user_id', Auth::id())
                ->with(['user', 'orderDetails.shipmentStatuses'])
                ->orderBy('order_date', 'desc')
                ->paginate(3);

まずは、ログイン中のユーザーの注文情報があるか、注文/t_ordersテーブル の検索を行います。
検索でログイン中のIDを取得してt_ordersテーブルの user_id カラムを検索します。
その際に with() を用いて情報を一括で取得しペジネーションの形にします。

3.取得できたデータを表示するには

データの表示について解説を行っていきます。

今回表示する注文履歴のデータは、

田中 太郎 さんが
2021-03-18 16:32:52 に商品を1個、
2020-10-23 20:55:19 に商品を2個 購入した履歴です。
最後発送日と、【 発送済 】という状態の表示まで行います。

まず、dd()を行って $orderInformations の中身を見てみましょう。
スクリーンショット 2021-03-19 124329.jpg
\#items: に値が入ってきました。
データベースからの情報の取得は成功です。

それを開いていくと..
image.png
\#attributes:の中にt_ordersテーブルの情報が入ってきています。
注文の履歴が2個あるので、配列で2つ並んでますね。

では例としてorder_dateを表示させます。

表示するためには一度$orderInformationsを foreach する必要があります。

order_history.blade.php
@foreach ($orderInformations as $order)
    注文日時:{{ $order->order_date }}<br>
@endforeach

▼ 結果
image.png
表示が出来ました。

では foreach すると何が変わるのでしょうか?

$orderの中がどうなっているのか dd() してみます。

order_history.blade.php
@foreach ($orderInformations as $order)
    注文日時:{{ $order->order_date }}<br>
@endforeach

@php dd($order) @endphp

▼ 結果
image.png
\#items:の中身だけになり、データがモデルオブジェクトになりました。

App\Order

この状態なら #attributes から取り出すことができます。
それで以下の形になります。

{{ $order->( #attributes の取り出したいカラム名) }}

では次の階層の表示に移っていきます。

m_users テーブルと、t_order_detailsテーブル の情報です。
image.png
image.png

両テーブルの情報は\#relations:の中に入っています。
ですが、m_users テーブルと、t_order_detailsテーブルでは入り方に違いがあります。
image.png

"user"App\Userであるのに対し、"orderDetails"illuminat…\Collectionとなっています。

上記から、

"user" = m_users テーブルの情報 は、$orderforeachせずとも表示することができる。

"orderDetails" = t_order_details テーブルの情報 は、$orderforeachしないと表示が出来ない。

と、表示するのにforeachの要否の違いが出ます。

では、先に手間の少ないm_users テーブルの情報の情報の表示から解説を行います。
今回は、ユーザーの氏名を表示してみます。

bladeでの表示方法は以下の様になります。

order_history.blade.php
@foreach ($orderInformations as $order)
    注文日時:{{ $order->order_date }}<br>
@endforeach

{{ $order->user->first_name }} {{ $order->user->last_name }}

▼ 結果
image.png
上記の方法で表示が行えます。
\#relations:の中に入っている情報で、このようにforeachしなくて良いのはApp\Userのパターンです。
モデルの繋がりからいくと親テーブルの情報を引き出すときです。(belongsToで引っ張ってきた情報)

では、次にt_order_details テーブルの情報の表示の解説です。
既にやり方が浮かんできている方も多いと思います。
発送日(shipment_date)の表示を行っていきます。

order_history.blade.php
@foreach ($orderInformations as $order)
    注文日時:{{$order->order_date}}<br>
@endforeach
{{ $order->user->first_name }} {{ $order->user->last_name }}<br>
@foreach ($orderInformations as $order)
@foreach ($order->orderDetails as $orderDetail)
    発送日:{{ $orderDetail->shipment_date }}<br>
@endforeach
@endforeach

▼ 結果
image.png
表示が出来ました!
\#relations:のなかに入っている情報を表示したくてforeachを行う際は、
$orderの中のorderDetailsforeach = foreach ($order->orderDetails as $orderDetail)
というように$orderの中のforeachするものを指定してあげます。

これが一番最初に行った $orderInformationsforeachとの違いです。

私はここでだいぶ時間を消費してしまいました^^;

ではでは、もうひとつ深い階層の表示を行ってみましょう。
次は m_shipment_statuses テーブルの情報です。
image.png

これまでと同じようにdd()の結果から表示のさせ方を確認していきます。

image.png

今回のm_shipment_statuses テーブルの情報の場合、

App\shipmentStatuses

モデルオブジェクトになっているのでforeachは不要です。

では表示していきましょう。

order_history.blade.php
@foreach ($orderInformations as $order)
    注文日時:{{$order->order_date}}<br>
@endforeach
{{ $order->user->first_name }} {{ $order->user->last_name }}<br>
@foreach ($orderInformations as $order)
@foreach ($order->orderDetails as $orderDetail)
    発送日:{{ $orderDetail->shipment_date }} {{ $orderDetail->shipmentStatuses->shipment_status_name }} <br>
@endforeach
@endforeach

▼ 結果
image.png

まとめ

illuminat…\Collection

でコレクションオブジェクトになっていれば、要foreach

App\〇〇

でモデルオブジェクトになっていれば、foreach不要

以上となります。

最後までご覧頂き、誠にありがとうございました。

17
14
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
17
14