アプリの名前はカロリーバスターズ

アプリを作りながらプログラミングを学びだしたスロースターターのワタシです。

早速自分が使いたいものを作ろうということで環境構築が終わりました。

今回作成するアプリはカロリーバスターズというアプリです。
私はかれこれ6ヶ月で10kgほど増量しました。

痩せようにもどの程度何をすればわかりませんでした。

そうだ！10kg痩せるためのカロリーを表示して、0まで減らせれば目標の体重になっている！といった形にすれば面白そうじゃね？？？

となりスタートしたのでした。
復習しながら書いていく



環境設定が終わったのでgit接続


    cd calorie-busters

ディレクトリに移動して

    git init

初期化

    git add .

全ファイルをステージング

    git commit -m "Initial commit: Laravel project setup"

コミットメッセージとともにコミットする。

今回はPostgreSQLを使う。

    brew update
    brew install postgresql

これでインストールします。

    brew services start postgresql

このコマンドで起動

    psql postgres

これでコマンドラインに入れるようになる。

    CREATE DATABASE calorie_busters;

これでカロリーバスターズ用のDBを作成した。

次はenvファイル

    DB_CONNECTION=pgsql
    DB_HOST=127.0.0.1
    DB_PORT=5432
    DB_DATABASE=calorie_busters
    DB_USERNAME=postgres
    DB_PASSWORD=


そして

    php artisan migrate



さあここから地獄のエラー天国が始まりました。

凄いエラーが発生していたのですが凄いところに原因はありました。

    # DB_HOST=127.0.0.1
    # DB_PORT=5432
    # DB_DATABASE=calorie_busters
    # DB_USERNAME=root
    # DB_PASSWORD=your_password

コメントアウトされていました笑

    git checkout -b feature/user-auth

でブランチを切ってログイン機能の作成をする。

### routes/web.php を編集

    use Illuminate\Support\Facades\Route;
    
    Route::get('/', function () {
        return view('welcome'); // 最初のページ
    });

Routeクラスを::で使う。
/にアクセスしたらviewのwelcomeブレードを表示。
    
    Route::get('/login', function () {
        return view('auth.login'); // ログインページ
    });

同じくだがauthフォルダのloginブレードを表示


    Route::get('/register', function () {
        return view('auth.register'); // 新規登録ページ
    });

Routeクラスを::で使う。
authフォルダのregisterブレードを表示。

### 新規ビューの作成
resources/views/welcome.blade.php を編集

    <!DOCTYPE html>
    <html lang="ja">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Calorie Busters</title>
    </head>
    <body>
        <h1>Welcome to Calorie Busters</h1>
        <div>
            <a href="/login">
                <button>ログイン</button>
            </a>
            <a href="/register">
                <button>新規アカウント登録</button>
            </a>
        </div>
    </body>
    </html>

これ後々、x-app-layoutを使って他のページを簡略化して作成していくのですが、
このページだけHTMLベタ打ち。

これも変えてやろうと思って変えたら表示エラーになりました。
理由は簡単です。
x-app-layout内は基本ログイン後の画面だったので、ログイン前のこのページではエラーが出たのでした。

ログイン時は/loginがアクセスされweb.phpのRouteが動き出します。
そしてviewで次のページが表示されます。

### ログインビューの作成
resources/views/auth/login.blade.php を作成

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>ログイン</title>
    </head>
    <body>
        <h1>ログインページ</h1>
        <form method="POST" action="/login">
            @csrf
            <label for="email">メールアドレス:</label>
            <input type="email" id="email" name="email" required>
            <br>
            <label for="password">パスワード:</label>
            <input type="password" id="password" name="password" required>
            <br>
            <button type="submit">ログイン</button>
        </form>
    </body>
    </html>

ここは特段言うことないかな。

### 新規登録ビューの作成

resources/views/auth/register.blade.php を作成

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>新規アカウント登録</title>
    </head>
    <body>
        <h1>新規アカウント登録</h1>
        <form method="POST" action="/register">
            @csrf
            <label for="name">名前:</label>
            <input type="text" id="name" name="name" required>
            <br>
            <label for="email">メールアドレス:</label>
            <input type="email" id="email" name="email" required>
            <br>
            <label for="password">パスワード:</label>
            <input type="password" id="password" name="password" required>
            <br>
            <label for="password_confirmation">パスワード確認:</label>
            <input type="password" id="password_confirmation" name="password_confirmation" required>
            <br>
            <button type="submit">登録</button>
        </form>
    </body>
    </html>


    git add .


ステージングして

    git commit -m "Add user authentication pages and navigation buttons"

コミット！



そこで先輩エンジニアからログインまわりはLaravelの機能で簡単にできるから調べてやってみてと言われた。

### 認証機能（ログイン・ユーザー登録など）を簡単に実装するBreeze

    composer require laravel/breeze --dev
    php artisan breeze:install

インストール

    php artisan migrate

これを行うと

- ホームページ（認証前）: /
- ログインページ: /login
- 新規登録ページ: /register

を自動で作ってくれた。
そしてさっき作っていたページは置き換わっていた笑

そしてコミット

    git add .
    git commit -m "Remove unnecessary custom views and integrate Breeze authentication"


### 今度はユーザープロフィールを作成する！

    git checkout -b feature/user-profile

ブランチ作成！

    php artisan make:migration add_profile_columns_to_users_table --table=users

マイグレーションファイルの作成！テーブル情報を入れる。

    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->float('height')->comment('身長 (cm)');
            $table->float('initial_weight')->comment('初期体重 (kg)');
            $table->float('target_weight')->comment('目標体重 (kg)');
            $table->integer('age')->comment('年齢');
            $table->enum('gender', ['male', 'female'])->comment('性別');
        });
    }
    
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn(['height', 'initial_weight', 'target_weight', 'age', 'gender']);
        });
    }

upメソッドは追加。
Scemaのクラスをつかってカラムを作成する。
あんまり型を指定してカラム名入れる。
nullableという制約もできるが今回は基礎代謝を計算するため全て入力必須項目となる。

downは消す時用。

    php artisan migrate

これでデータベースに書き込み。

### 登録画面にフォームを追加する

register.blade.php

    <div>
        <label for="height">身長 (cm)</label>
        <input type="number" id="height" name="height" required>
    </div>
    
    <div>
        <label for="initial_weight">初期体重 (kg)</label>
        <input type="number" id="initial_weight" name="initial_weight" required>
    </div>
    
    <div>
        <label for="target_weight">目標体重 (kg)</label>
        <input type="number" id="target_weight" name="target_weight" required>
    </div>
    
    <div>
        <label for="age">年齢</label>
        <input type="number" id="age" name="age" required>
    </div>
    
    <div>
        <label for="gender">性別</label>
        <select id="gender" name="gender" required>
            <option value="male">男性</option>
            <option value="female">女性</option>
        </select>
    </div>

labelのforとidを一致させると、label側をクリックした時にidが反応するようになる。

### バリデーションを追加

バリデーション＝制約

App\Http\Controllers\Auth\RegisteredUserController
storeメソッドの次からバリデーションを入力する

    $request->validate([
        'name' => ['required', 'string', 'max:255'],
        'email' => ['required', 'string', 'email', 'max:255', 'unique:users'],
        'password' => ['required', 'confirmed', Rules\Password::defaults()],
        'height' => ['required', 'numeric', 'min:0'],
        'initial_weight' => ['required', 'numeric', 'min:0'],
        'target_weight' => ['required', 'numeric', 'min:0'],
        'age' => ['required', 'integer', 'min:0'],
        'gender' => ['required', 'in:male,female'],
    ]);


これで最初に入力情報の確認を行い、次に

    User::create([
        'name' => $request->name,
        'email' => $request->email,
        'password' => Hash::make($request->password),
        'height' => $request->height,
        'initial_weight' => $request->initial_weight,
        'target_weight' => $request->target_weight,
        'age' => $request->age,
        'gender' => $request->gender,
    ]);

テーブルのカラムに対して先ほど入れた$requestからそれぞれ取得していく。

## プロフィールの画面設計

### ルートの設定

routes/web.php

    use App\Http\Controllers\ProfileController;
    
    Route::get('/profile', [ProfileController::class, 'show'])->name('profile');
    Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy');

プロフィールの表示ルートと削除ルートの作成。
同じ/profileを利用しているがgetリクエストが来ているかdeleteリクエストが来たかで違うため対応が変わってくる。

今回はnameで'profile'と呼ぶか'profile.destroy'で呼ぶかで変わる。


### コントローラーを作成

    php artisan make:controller ProfileController

コントローラ−を作成

ProfileController.php

    namespace App\Http\Controllers;
    
    use Illuminate\Support\Facades\Auth;
    use Illuminate\Http\Request;
    
    class ProfileController extends Controller
    {
        /**
         * Display the user's profile.
         */
        public function show()
        {
            // ログイン中のユーザー情報をビューに渡す
            $user = Auth::user();
            return view('profile.show', compact('user'));
        }
    
        /**
         * Delete the authenticated user's account.
         */
        public function destroy(Request $request)
        {
            $user = Auth::user();
    
            // ユーザーの削除処理
            $user->delete();
    
            // ログアウトしてトップページにリダイレクト
            Auth::logout();
    
            return redirect('/')->with('status', 'アカウントが削除されました');
        }
    }

### ビューの作成

resources/views/profile/show.blade.php

    <x-app-layout>
    @push('styles')
        <link rel="stylesheet" href="{{ asset('css/profile.css') }}">
    @endpush
    <!-- ヘッダーのスロット -->
    <x-slot name="header">
        <h2 class="profile-header">
            プロフィール情報
        </h2>
    </x-slot>
    <div class="profile-card">
        <h1>プロフィール情報</h1>
        <table class="table">
            <thead>
                <tr>
                    <th>項目</th>
                    <th>情報</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <th>名前</th>
                    <td>{{ $user->name }}</td>
                </tr>
                <tr>
                    <th>初期体重</th>
                    <td>{{ $user->initial_weight }} kg</td>
                </tr>
                <tr>
                    <th>目標体重</th>
                    <td>{{ $user->target_weight }} kg</td>
                </tr>
                <tr>
                    <th>身長</th>
                    <td>{{ $user->height }} cm</td>
                </tr>
                <tr>
                    <th>年齢</th>
                    <td>{{ $user->age }} 歳</td>
                </tr>
                <tr>
                    <th>性別</th>
                    <td>{{ $user->gender === 'male' ? '男性' : '女性' }}</td>
                </tr>
            </tbody>
        </table>
        <div>
            <a href="/dashboard" class="link-button-gray">トップページへ戻る</a>
        </div>
        <div>
            <form method="POST" action="{{ route('profile.destroy') }}">
                @csrf
                @method('DELETE')
                <button type="submit" class="delete-button">アカウント削除</button>
            </form>
        </div>
    </div>
</x-app-layout>

一番下のaction="{{ route('profile.destroy') }}で先程のdeleteリクエストに飛ばすことができる。


    git add .
    git commit -m "Add account deletion functionality with flash message"

コミット！！
次はメインの画面を作成する！！
実は今日から開発案件を手伝わせてもらっている。
ファイルを見た時かなり混乱したが、今日ここで復習している。

自信を持って挑もう。
明日は案件側の理解も上がって望めるだろう。