副業におすすめなサイトを見る→

Docker×Laravel8もくもく会のアプリ作成7(一覧画面の作成④)

アプリリリースのお知らせ

予定を探すアプリyoteipickerをリリースしました。

アプリの利用用途:暇だから何か予定入れたいけど今週の土日は何しようかな〜?ってときに使えるアプリです。

Docker×Laravel8でもくもく会アプリの一覧画面パート4です。
この記事では、データベースの値を表示させます。

>>ココナラと似てるおすすめの副業サイトを確認する

>>リモートワークもあるおすすめの転職サイトを確認する

休日で空いた時間の暇つぶしを探せるアプリを公開しています。

Contents

データベースの値を表示させて一覧画面を完成させる

前回の記事では、もくもく会イベント一覧画面のレイアウトをデータを仮置きで表示させました。

今回は、実際にデータベースの値を一覧画面に組み込んでいきますが、PHPの関数の知識を使うのでPHP公式や解説ページを確認しながら理解していきましょう。

まずは完成形のソース

@extends('layouts.app')

@section('content')
<style>
    #mokumoku-lists {
        filter:drop-shadow(2px 4px 6px #000);
    }
    .content-filed {
        width: 60%;
    }
</style>

{{-- ナビゲーション --}}
<nav class="navbar navbar-expand-lg navbar-light bg-light container">
    <div class="container-fluid">
        <a class="navbar-brand" href="{{ route('event.index') }}">もくもく会</a>
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#mokumoku" aria-controls="mokumoku" aria-expanded="false" aria-label="Toggle navigation">
            <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="mokumoku">
        <ul class="navbar-nav me-auto mb-2 mb-lg-0">
            <li class="nav-item">
                <a class="nav-link active" aria-current="page" href="{{ route('event.index') }}">一覧</a>
            </li>
            <li class="nav-item">
                <a class="nav-link" href="">開催する</a>
            </li>
        </ul>
        </div>
    </div>
</nav>

{{-- もくもく会開催一覧リスト --}}
@foreach ($events as $event)
<div class="card container text-center mb-5" id="mokumoku-lists">
    <div class="card-header font-weight-bold bg-white">
      <a href="">{{ $event->title }}</a>
    </div>
    <div class="card-body">
        <div class="category text-left">
            <label for="category-label"><span class="badge badge-primary p-2">{{ 'Laravel' }}</span></label>
        </div>
        <div class="entry-fee-wrapper d-flex">
            <label for="entry-fee"><span class="badge badge-success p-2">{{ '参加費' }}</span></label>
            <p class="text-danger font-weight-bold p-1 h5">{{ $event->entry_fee.'円' }}</p>
        </div>
        <div class="content-wrapper d-flex">
            <div class="content-filed">
                <p class="card-text text-left">
                    {{ mb_substr($event->content, 0, 100, 'UTF-8').'...' }}
                </p>
            </div>
            <div class="btn-filed ml-auto d-flex">
                <button class="btn btn-primary mr-3">{{ '詳細' }}</button>
                <button class="btn btn-info mr-3">{{ '編集' }}</button>
                <button class="btn btn-danger mr-3">{{ '削除' }}</button>
            </div>
        </div>
    </div>
    @php
        // 指定の日付を△△/××に変換する
        $date = date("m/d" ,strtotime($event->date));
        //指定日の曜日を取得する
        $getWeek = date('w', strtotime($event->date));
        //配列を使用し、要素順に(日:0〜土:6)を設定する
        $week = [
            '日', //0
            '月', //1
            '火', //2
            '水', //3
            '木', //4
            '金', //5
            '土', //6
        ];

        // 開始時間 ex.15:00:00→15:00に変換。秒部分を切り捨て
        $start_time = substr($event->start_time, 0, -3);
        // 終了時間 ex.19:00:00→19:00に変換。秒部分を切り捨て
        $end_time = substr($event->end_time, 0, -3);
    @endphp
    <div class="card-footer text-left font-weight-bold bg-white">
      {{ '開催日時:'.$date.'('.$week[$getWeek].')'. $start_time. '-' .$end_time }}
    </div>
</div>
@endforeach
@endsection

大事なポイントを以下にまとめました。

  • 文字は”で囲み、文字と変数を組み合わせる場合は、’文字’.$eventと.を使う
  • mb_substr関数で文字数を制御。超過したら…にする
  • @php …@endphpでbladeの中で、PHPの変数定義をできる状態にする
  • date関数とstrtotimeを使って、日付を△△/××に変換
  • 曜日の配列を用意する
  • substr関数で指定の箇所の文字列を削除

こんな感じです。

文字は”で囲み、文字と変数を組み合わせる場合

bladeのなかで、文字列と変数を組み合わせる場合は、.で繋ぎます。

例えば、

// 以下のように.でつなげる
{{ $変数.'文字列' }}
{{ '文字列'.$変数 }}
{{ '文字列'.$変数.'文字列' }}

// OK
{{ $event->entry_fee.'円' }} // 500円

// 構文エラーが出る
{{ $event->entry_fee'円' }}

開催日時のところがちょっと複雑に見えますが、上記を知っていれば問題ないです。

{{ '開催日時:'.$date.'('.$week[$getWeek].')'. $start_time. '-' .$end_time }}

// 分解すると、、、
{{ '文字列'.$変数.'文字列'.$変数.'文字列'.$変数.'文字列'.$変数 }}

mb_substr関数で文字数を制御。超過したら…にする

次に、イベントの詳細にて文字の超過分は…で制御しましょう。

コードの該当箇所は、以下の部分です。

{{ mb_substr($event->content, 0, 100, 'UTF-8').'...' }}

// UTF-8は現在のwebサイトにおける標準文字

// PHPのmb_substr関数を使って制御する
mb_substr(指定文字列, 開始位置, 終了位置, 文字のエンコード)

日本語を指定する場合は、mb_substrを使いましょう。(英語ならsubstr関数でもできるが、日本語に適用すると、2文字カウントになったりするから。)

この辺の詳細は、PHPの公式(mb_substr)をご参照ください。

今回のアプリでは、100文字超えたら…で表示できるようにしました。

@php …@endphpでbladeの中で、PHPの関数を使える状態にする

blade内でPHPの変数を定義したい場合は、@php…@endphpでくくりましょう。

この辺りは以下の記事で解説しています。

date関数とstrtotimeを使って、日付を△△/××に変換

データベースで、dateのカラム値は2021-11-07となっています。

一覧画面に表示する場合は、11/7と表示できるようにPHPのdate関数を使って制御します。

コードの該当箇所は以下です。

// 指定の日付を△△/××に変換する
$date = date("m/d" ,strtotime($event->date));

// date関数の使い方
date(表示形式, strtotime(指定日付))

date関数では、strtotime関数も合わせて使われます。(タイムスタンプに変換)

この辺りもPHPの公式(date関数)PHPで日付を変換する解説記事に目を通して理解を深めましょう。

曜日の配列を用意する

date関数を使えば、曜日も取得できます。

ただ、曜日の場合はちょっと工夫が必要です。

なぜなら以下のコードで返ってくる値は、日とかではなく0,1,2,…6だからです。

//指定日の曜日を取得する
$getWeek = date('w', strtotime($event->date)); // 11/7なら0,11/8なら1,11/9なら2が返ってくる

なので、曜日の配列を用意する必要があります。

//配列を使用し、要素順に(日:0〜土:6)を設定する
$week = [
    '日', //0
    '月', //1
    '火', //2
    '水', //3
    '木', //4
    '金', //5
    '土', //6
];

// 例
$week[0] →日
$week[1] →月

// $getWeekは0,1,2...6のいずれかの値が入るから、以下で曜日を取得できる
$week[$getWeek]

substr関数で指定の箇所の文字列を削除

最後に、開始時間と終了時間を整形です。

データベースで、start_timeとend_timeの値は15:00:00,19:00:00と入ってくるので、表示する際には15:00.19:00と制御します。

substr関数を使って、指定の文字列の特定文字列を削除する方針でいきましょう。

該当ソースコード

// 開始時間 ex.15:00:00→15:00に変換。秒部分を切り捨て
$start_time = substr($event->start_time, 0, -3);

// 終了時間 ex.19:00:00→19:00に変換。秒部分を切り捨て
$end_time = substr($event->end_time, 0, -3);

// substr関数の基本的な使い方
// substr関数は指定文字列を切り取って返す関数
substr(指定文字列, 開始位置, 終了位置);

// 結果:he
substr('hello', 0, 2);

// 結果:hel 終了位置を−に指定すると、末尾も文字列を削除してくれる
substr('hello', 0, -2);

こちらもPHPの関数の説明になるので、詳しくはPHP公式(substr)末尾の文字列の削除のやり方をご参照ください。

イベントとカテゴリーをリレーションさせてカテゴリーを表示させる

次に、eventモデルとcategoryモデルをリレーションさせて、カテゴリーを表示させていきます。

該当のソースコード

// {{ 'Laravel' }}となっている箇所
<div class="category text-left">
  <label for="category-label"><span class="badge badge-primary p-2">{{ 'Laravel' }}</span></label>
</div>

// 最終的なコード
<div class="category text-left">
  <label for="category-label"><span class="badge badge-primary p-2">{{ $event->category->category_name }}</span></label>
</div>

コードを見てもらうとわかるとおり、$event->カラムではなくて、$event->category->categoriesテーブルのカラム名となっていますね。

これは、eventモデルとcategoryモデルをリレーション(データ紐付け)させることで、eventsテーブルにあるcategory_idとcategoriesテーブルにあるcategory_idで一致するデータを一緒に取得できます。

Laravel8公式リファレンス(リレーション)

ちょっとわかりにくいので図で表すと、こんな感じです。

また、categoryはたくさんのeventをもち、逆にeventは一つのカテゴリーに属する関係です。

なので、それぞれのモデルにリレーションを書いていきます。

Eventモデル

<?php

namespace App\Models;

use App\Models\Category;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Event extends Model
{
    use HasFactory;

    // モデルに関連づけるテーブル
    protected $table = 'events';

    // テーブルに関連づける主キー
    protected $primaryKey = 'event_id';

    // 登録・編集ができるカラム
    protected $fillable = [
        'category_id',
        'title',
        'date',
        'start_time',
        'end_time',
        'content',
        'entry_fee',
    ];

    /**
     * カテゴリーリレーション
     */
    public function category()
    {
        return $this->belongsTo(Category::class, 'category_id', 'category_id');
    }

    /**
     * eventsテーブルのレコードを全件取得
     * 
     * @param void
     * @return Event eventsテーブル
     */
    public function allEventsData()
    {
        return $this->get();
    }
}

categoryモデル

<?php

namespace App\Models;

use App\Models\Event;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Category extends Model
{
    use HasFactory;

    // モデルに関連づけるテーブル
    protected $table = 'categories';

    // テーブルに関連づける主キー
    protected $primaryKey = 'category_id';

    // 登録・編集ができるカラム
    protected $fillable = [
        'category_name'
    ];

    /**
     * イベントリレーション
     */
    public function events()
    {
        return $this->hasMany(Event::class, 'category_id', 'category_id');
    }

    /**
     * categoriesテーブルのレコードを全件取得
     * 
     * @param void
     * @return Category categoriesテーブル
     */
    public function allCategoriesData()
    {
        return $this->get();
    }
}

リレーションが組めたので、categoryを繋げることでcategory_nameにアクセスできます。

細かい部分は解説しないので、ぜひLaravel8公式などに目を通して理解を深めましょう。(実務では公式リファレンス読めないと話にならないので。)

{{ $event->category->category_name }}

ナビゲーションを共通化する

最後に、ナビゲーションを共通化させます。

現在は、カテゴリー一覧、イベント一覧ページに同じようなナビゲーションの記述を書いてますし、この後作る登録画面でもまた書くので冗長です。

まずは、親ファイルであるapp.blade.phpにナビゲーションを@includeさせます。

<!doctype html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- CSRF Token -->
    <meta name="csrf-token" content="{{ csrf_token() }}">

    <title>{{ config('app.name', 'Laravel') }}</title>

    <!-- Scripts -->
    <script src="{{ asset('js/app.js') }}" defer></script>

    <!-- Fonts -->
    <link rel="dns-prefetch" href="//fonts.gstatic.com">
    <link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet">

    <!-- Font Awesome -->
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css">

    <!-- Styles -->
    <link href="{{ asset('css/app.css') }}" rel="stylesheet">
</head>
<body>
    <div id="app">
        <main class="py-4">
            @include('common.nav')
            @yield('content')
        </main>
    </div>
</body>
</html>

@includeを使うと、別のbladeファイルを読み込めます。

Laravel8 Bladeテンプレート

そして、commonファイルを作成し、nav.blade.phpにナビゲーションを書きます。

{{-- ナビゲーション --}}
<nav class="navbar navbar-expand-lg navbar-light bg-light container">
  <div class="container-fluid">
      <a class="navbar-brand" href="{{ route('event.index') }}">{{ 'もくもく会' }}</a>
      <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#mokumoku" aria-controls="mokumoku" aria-expanded="false" aria-label="Toggle navigation">
          <span class="navbar-toggler-icon"></span>
      </button>
      <div class="collapse navbar-collapse" id="mokumoku">
      <ul class="navbar-nav me-auto mb-2 mb-lg-0">
          <li class="nav-item">
              <a class="nav-link active" aria-current="page" href="{{ route('event.index') }}">{{ 'もくもく会一覧' }}</a>
          </li>
          <li class="nav-item">
            <a class="nav-link active" aria-current="page" href="{{ route('category.index') }}">{{ 'カテゴリ一覧' }}</a>
          </li>
          <li class="nav-item">
              <a class="nav-link active" href="{{ route('event.register') }}">{{ '開催する' }}</a>
          </li>
      </ul>
      </div>
  </div>
</nav>

各bladeファイルでは、@extends(‘layout.app’)を読み込んでいるので、各bladeファイルにナビゲーションの記述はもう不要です。

@extends('layouts.app')

@section('content')
<style>
    #mokumoku-lists {
        filter:drop-shadow(2px 4px 6px #000);
    }
    .content-filed {
        width: 60%;
    }
</style>
{{-- もくもく会開催一覧リスト --}}
@foreach ($events as $event)
<div class="card container text-center mb-5" id="mokumoku-lists">
    <div class="card-header font-weight-bold bg-white">
      <a href="">{{ $event->title }}</a>
    </div>
    <div class="card-body">
        <div class="category text-left">
            <label for="category-label"><span class="badge badge-primary p-2">{{ $event->category->category_name }}</span></label>
        </div>
        <div class="entry-fee-wrapper d-flex">
            <label for="entry-fee"><span class="badge badge-success p-2">{{ '参加費' }}</span></label>
            <p class="text-danger font-weight-bold p-1 h5">{{ $event->entry_fee.'円' }}</p>
        </div>
        <div class="content-wrapper d-flex">
            <div class="content-filed">
                <p class="card-text text-left">
                    {{ mb_substr($event->content, 0, 100, 'UTF-8').'...' }}
                </p>
            </div>
            <div class="btn-filed ml-auto">
                <button class="btn btn-primary mr-3">{{ '詳細' }}</button>
                <button class="btn btn-info mr-3">{{ '編集' }}</button>
                <button class="btn btn-danger mr-3">{{ '削除' }}</button>
            </div>
        </div>
    </div>
    @php
        // 指定の日付を△△/××に変換する
        $date = date("m/d" ,strtotime($event->date));
        //指定日の曜日を取得する
        $getWeek = date('w', strtotime($event->date));
        //配列を使用し、要素順に(日:0〜土:6)を設定する
        $week = [
            '日', //0
            '月', //1
            '火', //2
            '水', //3
            '木', //4
            '金', //5
            '土', //6
        ];

        // 開始時間 ex.15:00:00→15:00に変換。秒部分を切り捨て
        $start_time = substr($event->start_time, 0, -3);
        // 終了時間 ex.19:00:00→19:00に変換。秒部分を切り捨て
        $end_time = substr($event->end_time, 0, -3);
    @endphp
    <div class="card-footer text-left font-weight-bold bg-white">
      {{ '開催日時:'.$date.'('.$week[$getWeek].')'. $start_time. '-' .$end_time }}
    </div>
</div>
@endforeach
@endsection
@extends('layouts.app')

@section('content')
<div class="container">
  <table class="table table-striped">
    <thead>
      <tr>
        <th scope="col">カテゴリーID</th>
        <th scope="col">カテゴリー名</th>
      </tr>
    </thead>
    <tbody>
      @foreach ($categories as $category)
      <tr>
          <td>{{ $category->category_id }}</td>
          <td>{{ $category->category_name }}</td>
      </tr>
      @endforeach
    </tbody>
  </table>
</div>
@endsection

ナビゲーションも共通化できました。

一覧画面の表示がちょっと長くなりましたが、これで一覧表示は終了です。

次回は、登録画面の実装をしていきます。

>>ココナラと似てるおすすめの副業サイトを確認する

>>リモートワークもあるおすすめの転職サイトを確認する

休日で空いた時間の暇つぶしを探せるアプリを公開しています。

スキルを売り買いするならココナラ

コメント

コメントする

CAPTCHA


Contents
閉じる