Ikeda's Blog

Laravelでブログサイトを作る 13. 管理機能・子カテゴリの管理

はじめに

親カテゴリを基にして作成します。
一覧登録更新を作成した前提で進めますので、ご留意ください。

Controller

app/Http/Controllers/ChildCategoryController.phpの内容は、まずParentCategoryController.phpをコピーします。
その後、親カテゴリには無かった、カラム「parent」について追加します。
変更箇所はコード内にコメントを入れていますが、目的は以下の2点です。

  1. 画面表示する際に、セレクトメニューで使用するための「全親カテゴリ」データを取得しテンプレートへ渡す
  2. 登録更新する情報に、関連する親カテゴリのIDを追加
<?php

namespace App\Http\Controllers;

use App\Models\ChildCategory; // ※今回追加
use App\Models\ParentCategory;
use Illuminate\Http\Request;

class ChildCategoryController extends Controller
{
    /**
     * @var ChildCategory
     */
    protected $childCategory; // ※今回追加

    /**
     * @var ParentCategory
     */
    protected $parentCategory;

    /**
     * 新しいコントローラインスタンスの生成 ※ChildCategoryを追加
     *
     * @param ChildCategory $childCategory
     * @param ParentCategory $parentCategory
     * @return void
     */
    function __construct(ChildCategory $childCategory, ParentCategory $parentCategory) {
        $this->childCategory = $childCategory;
        $this->parentCategory = $parentCategory;
    }

    /**
     * 一覧画面表示
     *
     * @return mixed
     */
    public function list() {
        // 子カテゴリデータの一覧 ※今回追加
        $childCategoryData = $this->childCategory->withTrashed()->orderBy('id', 'asc')->get();

        // 親カテゴリデータの一覧 ※説明用のコメントを削除して一行にまとめ
        $parentCategoryData = $this->parentCategory->withTrashed()->orderBy('id', 'asc')->get();

        return view('admin.childCategory', [
            'childCategoryData' => $childCategoryData, // ※今回追加
            'parentCategory' => $parentCategoryData,
        ]);
    }

    /**
     * 子カテゴリ レコード総更新
     *
     * @param Request $request
     * @return mixed
     */
    public function update(Request $request) {
        $flg = true; // $flgがfalseになるまでループします
        for ($i = 1;$flg;$i++) {
            // ...省略...

            // 入力値を取得
            $id = $request['id_' . $i];
            $name = $request['name_' . $i];
            $number = $request['number_' . $i];
            $delete = $request['delete_' . $i];
            $parent = $request['parent_' . $i]; // ※今回追加

            // ...省略...

            // idがあるなら上書き、なければ新規作成
            $childCategoryData = $this->childCategory->withTrashed()->where('id', $id)->first();
            if ($childCategoryData === null) {
                $childCategoryData = new ChildCategory();
            }
            $childCategoryData->name = $name;
            $childCategoryData->number = $number;
            $childCategoryData->parent = $parent; // ※今回追加
            $childCategoryData->save();

            // ...省略...
        }

        return redirect()->route('admin_child');
    }

テンプレート

resources/views/admin/childCategory.blade.php
コチラも、ベースとしてparentCategory.blade.phpをコピーして使います。

  • テキストの「親」を「子」に変更
  • formのaction属性を、parentからchildに変更
  • 一覧表示でforeachに使用していた変数を$childCategoryData
  • 表に親カテゴリの項目を追加
@extends('admin.app')

@section('adminTitle', '子カテゴリ管理') {{-- 親→子 --}}

@section('adminMain')
    <article>
        <section class="article">
            <h2>子カテゴリ管理</h2> {{-- 親→子 --}}

            <form action="{{ route('admin_parent_update') }}" method="post"> {{-- parent→child --}}
                <table>
                    <tr>
                        <th>カテゴリ名</th>
                        <th>親カテゴリ</th> {{-- 追加 --}}
                        <th>表示順</th>
                        <th>削除</th>
                    </tr>
                    <tr id="model">
                        <td>
                            <input type="hidden" id="id" value="" />
                            <input type="text" id="name" value="" />
                        </td>
                        <td> {{-- 追加 --}}
                            <select id="parent">
                                @foreach ($parentCategory as $parentItem)
                                    <option value="{{ $parentItem->id }}">{{ $parentItem->name }}</option>
                                @endforeach
                            </select>
                        </td>
                        <td><input type="number" id="number" value="" /></td>
                        <td>
                            <label>
                                <input type="checkbox" id="delete" value="on" />削除
                            </label>
                        </td>
                    </tr>
                    <?php $cnt = 1; ?>
                    @foreach ($childCategoryData as $item) {{-- parent→child --}}
                        <tr>
                            <td>
                                <input type="hidden" name="id_{{ $cnt }}" value="{{ $item->id }}" />
                                <input type="text" name="name_{{ $cnt }}" value="{{ $item->name }}" />
                            </td>
                            <td> {{-- 追加 --}}
                                <select name="parent_{{ $cnt }}">
                                    @foreach ($parentCategory as $parentItem)
                                        <option value="{{ $parentItem->id }}"
                                            {{ ($item->parent === $parentItem->id) ? 'selected' : '' }}>
                                            {{ $parentItem->name }}
                                        </option>
                                    @endforeach
                                </select>
                            </td>
                            <td>
                                <input type="number" name="number_{{ $cnt }}"
                                    value="{{ $item->number }}" /></td>
                            <td>
                                <label>
                                    <input type="checkbox" name="delete_{{ $cnt }}" value="on"
                                        {{ ($item->deleted_at !== null) ? 'checked' : '' }} />削除
                                </label>
                            </td>
                        </tr>
                        <?php $cnt++; ?>
                    @endforeach
                    <tr>
                        <td>
                            <input type="hidden" name="id_{{ $cnt }}" value="" />
                            <input type="text" name="name_{{ $cnt }}" value="" />
                        </td>
                        <td> {{-- 追加 --}}
                            <select name="parent_{{ $cnt }}">
                                @foreach ($parentCategory as $parentItem)
                                    <option value="{{ $parentItem->id }}">{{ $parentItem->name }}</option>
                                @endforeach
                            </select>
                        </td>
                        <td><input type="number" name="number_{{ $cnt }}" value="{{ $cnt }}" /></td>
                        <td>
                            <label>
                                <input type="checkbox" name="delete_{{ $cnt }}" value="on" />削除
                            </label>
                        </td>
                    </tr>
                </table>

                <input type="hidden" id="max" value="{{ $cnt }}" />

                {{-- CSRFトークン --}}
                {{ csrf_field() }}

                <input type="button" value="+ 入力枠追加" id="addInput" />
                <input type="submit" value="更新" />
            </form>
        </section>
    </article>
@endsection

JavaScript

public/js/admin.js
入力枠追加の際に実行されるJavaScriptにも、親カテゴリについてを追記します。
lengthを使用して、「要素がある時」としているので、親子カテゴリの処理をできるだけ共通化しています。

$(document)
    // 親カテゴリの入力枠追加
    .on('click', '#addInput', function(){
        // 次の番号を算出
        const max = $('#max');
        const nextNum = parseInt(max.val()) + 1;
        max.val(nextNum);

        // id=modelになっているtr要素を、idを削除した上でcloneする
        const clone = $('#model').clone(true).removeAttr('id');

        // cloneしたtr内の各name属性を変更し、識別用のidを削除しておく
        $('#name', clone).attr('name', 'name_' + nextNum).removeAttr('id');
        $('#number', clone).attr('name', 'number_' + nextNum).val(nextNum).removeAttr('id');
        $('#id', clone).attr('name', 'id_' + nextNum).removeAttr('id');
        $('#delete', clone).attr('name', 'delete_' + nextNum).removeAttr('id');
        if ($('#parent', clone).length > 0) { // ※追加
            $('#parent', clone).attr('name', 'parent_' + nextNum).removeAttr('id');
        }

        // テーブルに追加
        clone.appendTo('table');
    })
;