Laravel 10 入門トップページ


目次

  1. 概要
  2. プロジェクトの作成と初期設定
  3. 一対多のリレーションシップ
  4. 多対多のリレーションシップ
  5. ビューを使った表示
  6. 学部の情報を表示・変更する
  7. キャンパスの情報を表示・変更・削除する
  8. 学生の情報を表示・変更・削除する

Laravel でリレーションシップを使いこなす

キャンパスの情報を表示・変更・削除する

ここでの概要

ここでは,個別のキャンパス情報を表示するページを作成します.また,キャンパス情報を更新(変更)するためのフォームも作成します.特に,あるキャンパスの情報を削除した時に,そのキャンパスに所属する情報を連鎖的に削除する方法についても説明します.

目次に戻る

キャンパス情報の表示

ここでは,個別のキャンパス情報を表示するページを作成します.このためにはまずルート情報を定義します.例えば,/campuses/1 という URI でアクセスされた場合には ID = 1 のキャンパスである KAC の情報を表示します.

routes/web.php(抜粋)Route::get('/campuses', [CampusesController::class, 'index']) -> name('campuses.index');
Route::get('/campuses/{id}', [CampusesController::class, 'show']) -> name('campuses.show');
Route::get('/faculties', [FacultiesController::class, 'index']) -> name('faculties.index');
Route::get('/faculties/{id}', [FacultiesController::class, 'show']) -> name('faculties.show');
Route::get('/faculties/{id}/edit', [FacultiesController::class, 'edit']) -> name('faculties.edit');
Route::patch('/faculties', [FacultiesController::class, 'update']) -> name('faculties.update');
Route::get('/students', [StudentsController::class, 'index']) -> name('students.index');
Route::get('/lectures', [LecturesController::class, 'index']) -> name('lectures.index');

次にコントローラに show 関数を追加します.まずは引数だけを表示するようにします.

app/HTTP/Controllers/CampusesController.php<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Campus;     // 追加

class CampusesController extends Controller
{
    public function index()
    {
        $campuses = Campus::get();
        return view('campuses.index')
                ->with('campuses', $campuses);
    }

    public function show($id)
    {
        dd($id);
    }
}

学部の一覧ページ /faculties と キャンパスの一覧ページ /campuses にキャンパス個別ページへのリンクを設置します.それぞれの index.blade.php ファイルを次のように変更してください.

resources/views/faculties/index.blade.php<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>学部一覧</title>
</head>
<body>
    <h1>学部一覧</h1>
    <ul>
        @foreach ($faculties as $faculty)
            <li>
                <a href="{{ route('faculties.show', $faculty->id) }}">{{ $faculty->faculty }}</a>は{{ $faculty->established }}年に設置され,キャンパスは <a href="{{ route('campuses.show', $faculty->campus->id) }}">{{ $faculty->campus->campus }}</a> です
            </li>
        @endforeach
    </ul>
</body>
</html>

resources/views/campuses/index.blade.php<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>キャンパス一覧</title>
</head>
<body>
    <h1>キャンパス一覧</h1>
    <ul>
        @foreach ($campuses as $campus)
            <li>
                <a href="{{ route('campuses.show', $campus->id) }}">
                    {{ $campus->campus }}
                </a>
                <ul>
                    @foreach ($campus->faculties as $faculty)
                        <li><a href="{{ route('faculties.show', $faculty->id) }}">{{ $faculty->faculty }}</a></li>
                    @endforeach
                </ul>
            </li>
        @endforeach
    </ul>
</body>
</html>

キャンパス一覧ページや学部一覧ページから「KAC」のリンクを押下すると,ID だけが確認できました.

laravel10-2023-relationship-33.png

次は,CampusesController の show 関数を編集して,学部情報を実際に取得し,ビューに渡すという処理を書きます.

app/HTTP/Controllers/CampusesController.php(抜粋)    public function show($id)
    {
        $campus = Campus::where('id', $id)
                            ->first();
        if (!$campus) {
            return redirect('/campuses');
        }
        return view('campuses.show')
                ->with('campus', $campus);
    }

さらにビューを作成します.具体的には resources/views/campuses/show.blade.php を作成して,次のような内容を記載します.index.blade.php とほどんど同じなのでコピーして一部を書き換えても構いません.

resources/views/campuses/show.blade.php<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>{{ $campus->campus }}</title>
</head>
<body>
    <h1>{{ $campus->campus }}</h1>
    <ul>
        @foreach ($campus->faculties as $faculty)
            <li><a href="{{ route('faculties.show', $faculty->id) }}">{{ $faculty->faculty }}</a></li>
        @endforeach
    </ul>
</body>
</html>

これでキャンパス詳細情報を表示するページができました.

laravel10-2023-relationship-34.png

目次に戻る

キャンパス情報の編集

次はキャンパス詳細情報のページから編集ページへのリンクを作成して編集作業ができるような機能を実装します.まずはルートの定義を行います.ここでは,編集画面を表示するためのルートの定義と,編集画面で「更新」ボタンを押した後の処理を行うためのルートの定義を追加します.

routes/web.php(抜粋)Route::get('/campuses', [CampusesController::class, 'index']) -> name('campuses.index');
Route::get('/campuses/{id}', [CampusesController::class, 'show']) -> name('campuses.show');
Route::get('/campuses/{id}/edit', [CampusesController::class, 'edit']) -> name('campuses.edit');
Route::patch('/campuses', [CampusesController::class, 'update']) -> name('campuses.update');
Route::get('/faculties', [FacultiesController::class, 'index']) -> name('faculties.index');
Route::get('/faculties/{id}', [FacultiesController::class, 'show']) -> name('faculties.show');
Route::get('/faculties/{id}/edit', [FacultiesController::class, 'edit']) -> name('faculties.edit');
Route::patch('/faculties', [FacultiesController::class, 'update']) -> name('faculties.update');
Route::get('/students', [StudentsController::class, 'index']) -> name('students.index');
Route::get('/lectures', [LecturesController::class, 'index']) -> name('lectures.index');

コントローラには編集画面表示のための edit 関数と更新処理を行う update 関数を定義します.更新処理については,まだ実際には更新せずフォームから送信された情報を表示する機能だけを入れておきます.

app/HTTP/Controllers/CampusesController.php(抜粋)    public function edit($id)
    {
        $campus = Campus::where('id', $id)
                            ->first();
        if (!$campus) {
            return redirect('/campuses');
        }
        return view('campuses.edit')
                ->with('campus', $campus);
    }

    public function update(Request $request)
    {
        dd($request);
    }

個別キャンパス情報の表示ページに編集画面へのリンクを設置します.

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>{{ $campus->campus }}</title>
</head>
<body>
    <h1>{{ $campus->campus }}</h1>
    <ul>
        @foreach ($campus->faculties as $faculty)
            <li><a href="{{ route('faculties.show', $faculty->id) }}">{{ $faculty->faculty }}</a></li>
        @endforeach
    </ul>
    <hr>
    <p><a href="{{ route('campuses.edit', $campus->id) }}">[キャンパス情報の編集]</a></p>
</body>
</html>

さらに編集画面を設計します.適切なフォルダに新しいファイル edit.blade.php を作成して,次の内容にしてください.

resources/views/campuses/edit.blade.php<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>{{ $campus->campus }}の編集</title>
</head>
<body>
    <h1>{{ $campus->campus }}の編集</h1>
    <div>
        <form method="post" action="{{ route('campuses.update') }}" enctype="multipart/form-data">
            @csrf
            {{ method_field('patch') }}
            <input type="hidden" name="id" value="{{ $campus->id }}">
            <p>
                <label for="campus">キャンパス名:</label>
                <input type="text" name="campus"
                    id="campus"
                    value="{{ $campus->campus }}{{ old('campus') }}">
            </p>
            <p>
                <input type="submit" value="更新">
            </p>
        </form>
    </div>
</body>
</html>

ここまでの状態での動作を確認します.個別学部の表示ページには「キャンパス情報の編集」リンクがあるので,それをクリックします.

laravel10-2023-relationship-35.png

「KAC」の編集画面が表示されました.

laravel10-2023-relationship-36.png

キャンパス名を「有瀬キャンパス」に書き換えて「更新ボタン」をクリックします.

laravel10-2023-relationship-37.png

フォームに入力された情報などが $request に格納されていることがわかります.この時に不正な書き込みを防止するためのトークンが仕込まれていることにも注意してください.

laravel10-2023-relationship-38.png

では,実際にデータベースを更新するコードを入力します.

app/HTTP/Controllers/CampusesController.php(抜粋)    public function update(Request $request)
    {
        // 掲示板の例を参考にここで Validation を記載しよう(ここでは省略します.)

        $campus = Campus::where('id', $request->id)
                            ->first();
        $campus->campus = $request->campus;
        $campus->save();

        return redirect()->route('campuses.show', $request->id);
    }

実際に「KAC」を「有瀬キャンパス」に更新した結果です.

laravel10-2023-relationship-39.png

もちろんキャンパス一覧ページでも更新内容が確認できるはずです.

laravel10-2023-relationship-40.png

目次に戻る

キャンパス情報の削除

次は,キャンパス情報を削除する機能を実装します.なお,あるキャンパスの情報を削除するとそのキャンパスに所属している学部の情報も連鎖的に削除することにします(連鎖的に削除しない方法ももちろん実現可能です).まずは削除のためのルートを定義します.

routes/web.php(抜粋)Route::get('/campuses', [CampusesController::class, 'index']) -> name('campuses.index');
Route::get('/campuses/{id}', [CampusesController::class, 'show']) -> name('campuses.show');
Route::get('/campuses/{id}/edit', [CampusesController::class, 'edit']) -> name('campuses.edit');
Route::patch('/campuses', [CampusesController::class, 'update']) -> name('campuses.update');
Route::delete('/campuses/{id}', [CampusesController::class, 'destroy']) -> name('campuses.destroy');
Route::get('/faculties', [FacultiesController::class, 'index']) -> name('faculties.index');
Route::get('/faculties/{id}', [FacultiesController::class, 'show']) -> name('faculties.show');
Route::get('/faculties/{id}/edit', [FacultiesController::class, 'edit']) -> name('faculties.edit');
Route::patch('/faculties', [FacultiesController::class, 'update']) -> name('faculties.update');
Route::get('/students', [StudentsController::class, 'index']) -> name('students.index');
Route::get('/lectures', [LecturesController::class, 'index']) -> name('lectures.index');

個別キャンパス情報の表示ページに削除のためのボタンを設置します.

resources/views/campuses/show.blade.php<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>{{ $campus->campus }}</title>
</head>
<body>
    <h1>{{ $campus->campus }}</h1>
    <ul>
        @foreach ($campus->faculties as $faculty)
            <li><a href="{{ route('faculties.show', $faculty->id) }}">{{ $faculty->faculty }}</a></li>
        @endforeach
    </ul>
    <hr>
    <p><a href="{{ route('campuses.edit', $campus->id) }}">[キャンパス情報の編集]</a></p>
    <div>
        <form action="{{ route('campuses.destroy', $campus->id )}}" method="post">
            @csrf
            {{ method_field('DELETE') }}
            <button>キャンパスの削除</button>
        </form>
    </div>
</body>
</html>

コントローラに destroy メソッドを作成し,指定したレコードをテーブルから削除するコードを入力します.

    public function destroy($id)
    {
        $campus = Campus::where('id', $id)
                        ->first();
        if (!$campus) {
            return redirect('/campuses');
        }
        $campus->delete();
        return redirect('/campuses');
    }

これから「KPC」のレコード削除に関する実験を行うので,その前にデータベースをロールバック,マイグレーション,シードの投入を実行してデータベースをリセットしておきます.

vagrant@ubuntu2204 laravelRelationship $ php artisan migrate:rollback; php artisan migrate; php artisan db:seed ⏎

まず,学部一覧ページを表示して10の学部が存在することを確認します.

laravel10-2023-relationship-41.png

次に,キャンパス一覧のページでも2つのキャンパスに合計10の学部があることを確認します.

laravel10-2023-relationship-42.png

「KPC」のページを表示します.KPCには5つの学部が所属しています.ここで,「キャンパス情報の削除」ボタンを押して,KPCのレコードを削除します.

laravel10-2023-relationship-43.png

「KPC」のレコードを削除した結果,キャンパス「KAC」だけになりました.

laravel10-2023-relationship-44.png

それと同時に,学部テーブルからからKPCに所属していた学部がすべて連鎖的に削除されていることも確認できました.

laravel10-2023-relationship-45.png

今の「KPC」を削除した作業の途中で適宜 SQLite でデータベースの内容を確認したところ,次のような結果になりました.

vagrant@ubuntu2204 laravelRelationship $ sqlite3 database/database.sqlite ⏎
SQLite version 3.38.2 2022-03-26 13:51:10
Enter ".help" for usage hints.
sqlite> .tables ⏎
campuses                lectures                students
faculties               migrations              users
failed_jobs             password_reset_tokens
lecture_student         personal_access_tokens
sqlite> .headers on ⏎
sqlite> SELECT * FROM campuses; ⏎ # KPCの削除前
id|campus|created_at|updated_at
1|KAC||
2|KPC||
sqlite> SELECT * FROM faculties; ⏎ # KPCの削除前
id|faculty|established|campus_id|created_at|updated_at
1|栄養学部|1966|1||
2|法学部|1967|2||
3|経済学部|1967|1||
4|薬学部|1972|2||
5|人文学部|2004|1||
6|経営学部|2004|2||
7|総合リハビリテーション学部|2005|1||
8|現代社会学部|2014|2||
9|グローバル・コミュニケーション学部|2015|2||
10|心理学部|2018|1||
sqlite> SELECT * FROM campuses; ⏎ # KPCの削除後
id|campus|created_at|updated_at
1|KAC||
sqlite> SELECT * FROM faculties; ⏎ # KPCの削除後
id|faculty|established|campus_id|created_at|updated_at
1|栄養学部|1966|1||
3|経済学部|1967|1||
5|人文学部|2004|1||
7|総合リハビリテーション学部|2005|1||
10|心理学部|2018|1||
sqlite> .exit ⏎
vagrant@ubuntu2204 laravelRelationship $

なお,ここでの例では faculties テーブルのマイグレーションonDelete('cascade') を指定しました.キャンパスと学部は「一対多」の関係ですが,一側の campuses テーブルでの削除によって,多側テーブルである faculties テーブルで連鎖的な削除が行われました.CASCADE 以外にも,RESTRICT, SET NULL, NO ACTION などが利用できます.詳細は例えばこのWebページなどで確認してください.

目次に戻る