未経験からエンジニア転職をするための最強ロードマップロードマップ

【応用Laravel教材③】Laravelでタスク管理アプリ実装!〜プロジェクト一覧機能実装からログイン後のリダイレクト先変更編〜

ファド

こんにちは!
PHPのLaravelやJavaScriptでWeb開発をしているフリラーンスエンジニアのファドと申します!

こちらの記事は応用Laravel教材の第3回目の記事になります。

その他の応用Laravel教材を学習したい方は下記リンクから直接教材へ飛ぶことができます。

目次

プロジェクト一覧

次はプロジェクト一覧画面を作成していきましょう。

ルーティング

まずはルーティングから行っていきます。
task-app/routes/web.phpを下記の通り編集してください。

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ProjectController;

Route::get('/', function () {
    return view('welcome');
});

Route::get('/dashboard', function () {
    return view('dashboard');
})->middleware(['auth'])->name('dashboard');

// ログイン必須ルート
Route::middleware('auth')->group(function () {
    // プロジェクト一覧画面
    Route::get('projects', [ProjectController::class, 'index'])->name('projects.index');
});

require __DIR__.'/auth.php';

まず、タスク管理アプリには、未ログインユーザーがアクセスできないページがいくつか存在しています。
その内の一つが今回実装するプロジェクト一覧画面です。
web.phpでは、アプリケーションの利用に認証を求める機能を実装することができます。

ページに認証を求める処理はミドルウェアを用いて実装します。
ミドルウェアとは、ルート毎の処理に移る前に実行される処理のことです。
つまり、画面を表示する前にログインかどうかをミドルウェアを使用して確かめるということです。

認証を求めるミドルウェアは最初から用意されているので、ルートにミドルウェアを適用するだけで実装することができます。

具体的な記述方法は下記の通りです。

Route::middleware('auth')->group(function () {
    // ここにログイン後しか表示できないルートを記述する
});

とても簡単ですね。

以降ログインが必要な画面・処理のルーティングをする場合は、この中に記述していきます。
今はこれから実装するプロジェクト一覧画面のルーティングを記述しています。

コントローラー作成&編集

次に、ルーティングで指定したProjectコントローラーを作成していきます。
ターミナルで下記コマンドをtask-appディレクトリ上で実行してください。

$ ./vendor/bin/sail php artisan make:controller ProjectController

作成が完了したら、task-app/app/Http/Controllers/ProjectController.phpを下記の通り編集してください。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ProjectController extends Controller
{
    /**
     * プロジェクト一覧画面表示
     */
    public function index()
    {
        return view('projects.index');
    }
}

これでProjectコントローラーindexメソッドを作成することができました。
http://localhost/projectsにアクセスがあった場合、projects/index.blade.phpを表示させるように処理を記述したので、index.blade.phpを作成していきましょう。

まずはtask-app/resources/viewsディレクトリ配下にprojectsフォルダを作成してください。
作成が完了したらprojectsフォルダ内にindex.blade.phpを作成してください。

コマンドで作成する場合は、ターミナルで下記コマンドをtask-appディレクトリ上で実行してください。

$ mkdir resources/views/projects && touch resources/views/projects/index.blade.php

作成したtask-app/resources/views/projects/index.blade.phpを下記の通り編集してください。

@extends('layouts.layout')

@section('title')
    プロジェクト一覧
@endsection

@section('content')
    <div class="container mt-4">
        <div class="row">
            <div class="col col-md-6 offset-md-3">
                <div class="card">
                    <div class="card-header bg-dark text-light d-flex justify-content-between align-items-center">
                        <p class="mb-0 h5">プロジェクト</p>
                        <a href="#" class="btn btn-primary">追加</a>
                    </div>
                    <table class="table table-hover mb-0">
                        <tbody class="text-center">
                            <tr>
                                <td class="table-active"><a href="#">プロジェクト1</a></td>
                            </tr>
                            <tr>
                                <td><a href="#">プロジェクト2</a></td>
                            </tr>
                            <tr>
                                <td><a href="#">プロジェクト3</a></td>
                            </tr>
                            <tr>
                                <td><a href="#">プロジェクト4</a></td>
                            </tr>
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>
@endsection

今回は特に難しい記述はありません。
まだプロジェクトのデータが存在していないので、HTMLでデータ部分を記述しています。

テーブル作成

プロジェクトのデータを保存するためのprojectsテーブルを作成していきます。
projectsテーブルの内容は下記の通りです。

カラム名日本語
idID
user_idユーザーID
project_nameプロジェクト名
created_at作成日
updated_at更新日

user_idというカラムが存在していますが、このカラムの値とusersテーブルidを紐付けることで、どのユーザーが作成したプロジェクトなのかをデータとして紐付けることができます。

それでは、さっそくマイグレーションでprojectsテーブルを作成していきましょう。
ターミナルで下記コマンドをtask-appディレクトリ上で実行してください。

$ ./vendor/bin/sail php artisan make:migration create_projects_table

作成したtask-app/database/migrations/2022_06_23_223330_create_projects_table.phpを下記の通り編集してください。
※2022_06_23_223330は作成した日時なので、皆さんのファイルとは異なっています。

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('projects', function (Blueprint $table) {
            $table->id();
            $table->bigInteger('user_id')->unsigned(); // ここを追加
            $table->string('project_name', 30); // ここを追加
            $table->timestamps();

            // 外部キーの設定
            $table->foreign('user_id')->references('id')->on('users'); // ここを追加
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('projects');
    }
};

追加した内容を確認すると、外部キーの設定という処理が追加されています。
これは2つのテーブル間でデータの整合性を保つために設定される制約です。
必須の設定ではありませんが、usersテーブルprojectsテーブルのデータの整合性を保つために記述しておきます。

※データの整合性を保つ例としては、ユーザー情報が削除されると、削除されたユーザーに紐付いたプロジェクト情報も削除されます。

では、ターミナルで下記コマンドをtask-appディレクトリ上で実行してください。

$ ./vendor/bin/sail php artisan migrate

これでprojectsテーブルが作成されました。

モデル作成

次に、projectsテーブルのデータを操作するためのモデルを作成しましょう。
ターミナルで下記コマンドをtask-appディレクトリ上で実行してください。

$ ./vendor/bin/sail php artisan make:model Project

作成したtask-app/app/Models/Project.phpを下記の通り編集してください。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Project extends Model
{
    use HasFactory;

    protected $fillable = [
        'user_id',
        'project_name',
    ];
}

データ内容を変えたいカラムを$fillableで指定しておきましょう。
今回はユーザーIDプロジェクト名の2つのカラムのみでOKです。

テストデータ作成

モデルの作成も終わったので、シーダーを使用してテストデータを作成していきましょう。
ターミナルで下記コマンドをtask-appディレクトリ上で実行してください。

$ ./vendor/bin/sail php artisan make:seeder ProjectsTableSeeder

作成したtask-app/database/seeders/ProjectsTableSeeder.phpを下記の通り編集してください。

<?php

namespace Database\Seeders;

use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB; // ここを追加

class ProjectsTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        // usersテーブルから1つのデータを取得
        $user = DB::table('users')->first();

        DB::table('projects')->insert([
            'project_name' => 'プロジェクト1',
            'user_id' => $user->id,
            'created_at' => date('Y-m-d H:i:s'),
            'updated_at' => date('Y-m-d H:i:s'),
        ]);

        DB::table('projects')->insert([
            'project_name' => 'プロジェクト2',
            'user_id' => $user->id,
            'created_at' => date('Y-m-d H:i:s'),
            'updated_at' => date('Y-m-d H:i:s'),
        ]);

        DB::table('projects')->insert([
            'project_name' => 'プロジェクト3',
            'user_id' => $user->id,
            'created_at' => date('Y-m-d H:i:s'),
            'updated_at' => date('Y-m-d H:i:s'),
        ]);
    }
}

特に難しい処理はしていません。
今回はテストデータとして3つのデータを作成しました。
また、user_idには、存在するuser_idが保存されていてほしいので、$user = DB::table('users')->first();と記述して、シーダーファイル内でユーザー情報を取得するようにしています。

次にtask-app/database/seeders/DatabaseSeeder.phpを下記の通り編集してください。

<?php

namespace Database\Seeders;

use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        $this->call([
            UsersTableSeeder::class,
            ProjectsTableSeeder::class,
        ]);
    }
}

これでprojectsテーブルのテストデータを作成する準備が整いました。
それでは、ターミナルで下記コマンドをtask-appディレクトリ上で実行してください。

$ ./vendor/bin/sail php artisan migrate:refresh --seed

今回は新しくシーダーファイルを追加したので、migrate:refreshコマンドを実行します。
このmigrate:refreshコマンドを実行すると、全てのテーブルが一回削除され、もう一度マイグレーションが実行されます。
つまり、中のデータもリセットされるということです。

また、--seedオプションを付けると、シーダーの実行も一緒にしてくれるので、テーブルの作成とデータの作成を同時に行ってくれます。

migrate:refreshコマンド後にテーブルのデータを確認しておくといいですね!

リレーション

次はリレーションを定義していきます。

そもそもリレーションとは、データベース上のテーブルを関連付けるための機能です。
例えば今回の実装の場合、usersテーブルprojectsテーブルの2つが存在しています。
外部キーの設定でも少し説明しましたが、この2つのテーブルはiduser_idで関連付けられています。

これをLaravelでは、どのテーブルとどのテーブルが関連しているのかをモデルの中に定義することができます。

リレーションにはいくつかの種類があり、代表的なものを2つ紹介します。

リレーションメソッド
1 対 1hasOne()1人のユーザーに対してプロフィール画像は1枚
1 対 1(逆)belongsTo()1枚のプロフィール画像に対してユーザーは1人
1 対 多hasMany()1人のユーザーに対して投稿は複数
1 対 多(逆)belongsTo()1つの投稿に対してユーザーは1人

リレーションでは、このようにどのテーブルとどのテーブルがどのような関係で関連しているのかを定義することができます。

リレーションを設定していると、下記のような利点があります。

  • リレーション先のテーブルにあるデータを取得できる
  • テーブル情報に変更があれば、自動的に変更があったテーブルとリレーションのあるテーブルにも情報が反映される

なんとなくイメージはできたと思うので、さっそく実装していきます。

task-app/app/Models/User.phpを下記の通り編集してください。

<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;

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

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array<int, string>
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

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

    // --- ここから追加 ---

    /**
     * Projectsテーブルとのリレーション
     */
    public function projects()
    {
        return $this->hasMany(Project::class);
    }

    // --- ここまで追加 ---
}

今回は$this->hasMany(Project::class);と定義しています。
それは、1人のユーザーに対して複数のプロジェクトを保持することができるからです。

また、メソッド名はprojectsと複数形にしています。
これも複数のプロジェクトを保持できることから複数形にしています。

projectsテーブルから見た時のリレーションも設定していきましょう。
task-app/app/Models/Project.phpを下記の通り編集してください。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Project extends Model
{
    use HasFactory;

    protected $fillable = [
        'project_name',
        'user_id',
    ];

    // --- ここから追加 ---

    /**
     * Usersテーブルとのリレーション
     */
    public function user()
    {
        return $this->belongsTo(User::class);
    }

    // --- ここまで追加 ---
}

今回は$this->belongsTo(User::class);と定義しています。
それは、1つのプロジェクトに対して、1人のユーザーがそのプロジェクトの所有者だからです。

また、メソッド名はuserと単数形にしています。
これは1つのプロジェクトにつき、プロジェクトの保有者は1人だからです。

これで定義自体は終わりです。
定義したメソッドの使用方法は実装時に確認しましょう。

コントローラー編集

プロジェクトのテストデータを用意したので、projectsテーブルからデータを取得して表示できるようにしてみましょう。

task-app/app/Http/Controllers/ProjectController.phpを下記の通り編集してください。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth; // ここを追加

class ProjectController extends Controller
{
    /**
     * プロジェクト一覧画面
     */
    public function index()
    {
        // ログインユーザーが作成した全てのプロジェクトを取得
        $projects = Auth::user()->projects->all();

        return view('projects.index', compact('projects'));
    }
}

Laravelでは現在のログインユーザー情報をAuth::user()と記述することで取得することができます。
これはLaravelのAuthファサードという機能を使用することで実装することができるので、use文を使用して、Authファサードを読み込んでいます。

また、ユーザー情報に->projects->all()と記述するとリレーション先のprojectsテーブルの情報を取得することができます。
ここで先ほどUserモデルに定義したprojectsメソッドを使用することができるということです。

後は取得したプロジェクト情報をcompact関数を使用してビューに渡しています。

ビュー編集

次はビューを編集していきましょう。
task-app/resources/views/projects/index.blade.phpを下記の通り編集してください。

@extends('layouts.layout')

@section('title')
    プロジェクト一覧
@endsection

@section('content')
    <div class="container mt-4">
        <div class="row">
            <div class="col col-md-6 offset-md-3">
                <div class="card">
                    <div class="card-header bg-dark text-light d-flex justify-content-between align-items-center">
                        <p class="mb-0 h5">プロジェクト</p>
                        <a href="#" class="btn btn-primary">追加</a>
                    </div>
                    <table class="table table-hover mb-0">
                        <tbody class="text-center">
                            @foreach ($projects as $project)
                                <tr>
                                    <td><a href="#">{{ $project->project_name }}</a></td>
                                </tr>
                            @endforeach
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>
@endsection

http://localhost/projectsにアクセスし、下記画像のような画面が表示されればOKです。

これでプロジェクト一覧が表示されるようになりました。

新規登録・ログイン後のリダイレクト先を変更

現在、新規登録・ログイン後にリダイレクトされる先は下記の通りです。

これを先ほど作成したプロジェクト一覧に遷移するように設定しましょう。

Laravel Breezeでログイン機能を実装した場合、新規登録・ログイン後のリダイレクト先を変更するには、RouteServiceProvider.phppublic const HOME = '/dashboard'を変更する必要があります。

task-app/app/Providers/RouteServiceProvider.phpを下記の通り編集してください。

<?php

namespace App\Providers;

use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Support\Facades\Route;

class RouteServiceProvider extends ServiceProvider
{
    /**
     * The path to the "home" route for your application.
     *
     * Typically, users are redirected here after authentication.
     *
     * @var string
     */
    public const HOME = '/projects';

    // --- 以下省略 ---
}

編集が終了したら、http://localhost/loginからログインしてください。
ログイン後のリダイレクト先が下記画像のようにプロジェクト一覧画面になっていればOKです。

定数HOMEにプロジェクト一覧のパスを指定することで、指定したリダイレクト先にリダイレクトされるようになります。

これは新規登録処理のコントローラーRegisteredUserController.phpとログイン処理のコントローラーAuthenticatedSessionController.phpstoreメソッドの中身で、RouteServiceProviderの定数HOMEがリダイレクト先として指定してあるからです。

RegisteredUserController.phpstoreメソッドは下記の通りです。

public function store(Request $request)
{
    $request->validate([
        'name' => ['required', 'string', 'max:255'],
        'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
        'password' => ['required', 'confirmed', Rules\Password::defaults()],
    ]);

    $user = User::create([
        'name' => $request->name,
        'email' => $request->email,
        'password' => Hash::make($request->password),
    ]);

    event(new Registered($user));

    Auth::login($user);

    return redirect(RouteServiceProvider::HOME);
}

return redirect(RouteServiceProvider::HOME);と記述されているのがわかると思います。

また、AuthenticatedSessionController.php storeメソッドは下記の通りです。

public function store(LoginRequest $request)
{
    $request->authenticate();

    $request->session()->regenerate();

    return redirect()->intended(RouteServiceProvider::HOME);
}

return redirect()->intended(RouteServiceProvider::HOME);と記述されています。

中身の処理をわざわざ覚える必要は全くありません。
リダイレクト先の変更はRouteServiceProvider.phpの定数HOMEを変更することで実装できることが理解できればOKです!

念の為、新規登録後のリダイレクト先もプロジェクト一覧になっているかも各自確かめておきましょう。

次の教材

次の教材は下記から簡単に飛ぶことができます!
引き続きプログラミングを楽しんでいきましょう!

あわせて読みたい
【応用Laravel教材④】Laravelでタスク管理アプリ実装!〜タスク一覧機能実装編〜 こちらの記事は応用Laravel教材の第4回目の記事になります。 その他の応用Laravel教材を学習したい方は下記リンクから直接教材へ飛ぶことができます。 タスク一覧 プロ...

プログラミング学習サポートについて

「独学で挫折した。。。」

「一人でのプログラミング学習がしんどい。。。」

「未経験からエンジニア転職をしたいけど何をしたら良いかわからない。。。」

このような悩みをお持ちの方向けに、本教材作成者のファドがMENTAという学習サイトにてあなたのプログラミング学習とエンジニア転職を徹底サポートいたします!

サポート価格はなんと1日あたりたったの約300円!

教材で分からない箇所のサポートはもちろんのこと、本サイトで公開しているすべての課題の解答も公開しております。
また、MENTAで学習を終わらせていただいた方限定で懇意にしていただいている企業さんを紹介することもあります!

なお、サポート内容の詳細は下記の通りです。

  • 目標設定
  • マインドセット
  • オリジナル教材見放題
  • オリジナル課題見放題
  • オリジナル課題の解答見放題
  • 課題コードレビュー
  • 教材への無制限質問
  • 課題への無制限質問
  • ポートフォリオ作成アドバイス
  • 褒めのコーチング

いくつかのプランを用意させていただいておりますので、下記より一度ご覧ください!

あわせて読みたい
【プログラミング学習】1日あたりたったの「300円」のみでプログラミングを学び、最短で転職or稼ぐ!|【ME... プログラミングを学びたいすべての方へこれからの時代は格安でプログラミングを学び、最短で稼げ自己紹介はじめまして!この度はプランをご覧いただき、誠にありがとうござ...

コメント

    この記事が気に入ったら
    フォローしてね!

    よかったらシェアしてね!
    • URLをコピーしました!

    コメント

    コメントする

    目次