Github ローカルからリモートへpush

ローカルのプロジェクトをGithubで管理

  1. CLIで該当プロジェクトディレクトリに移動
  2. Git管理下に置く
    1. git init
    2. git add .
    3. git commit -m 'first commit'
  3. リモートリポジトリにプッシュ

Quick setup
…or push an existing repository from the command line

  git remote add origin git@github.com:Username/ProjectName
  git branch -M main
  git push -u origin main

以後は、pushで上流リポジトリにpushされる。

Laravel ミニブログ作成3 投稿用テーブルとモデル

postsテーブルの作成

カラム名 内容
id(主キー) ID
user_id(外部キー) ユーザーのID
title タイトル
content 本文
created_at 作成日時
updated_at 更新日時

database/migrations/****_**_**_******_create_posts_table.php

<?php

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

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
+            $table->foreignId('user_id')->constrained()->cascadeOnDelete();
+            $table->string('title');
+            $table->text('content');
            $table->timestamps();
        });
    }

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

外部キーの設定
$table->foreignId('user_id')->constrained()->cascadeOnDelete();

  • マイグレーションの実行
    sail artisan migrate

    Postモデルの作成

  • モデルファイルの作成
    sail artisan make:model Post

    リレーションシップの設定

    「1人のユーザーは複数の投稿を作成できるが、1つの投稿は1人のユーザーに属する」という1対多のリレーションシップ(ユーザーが「1」で、投稿が「多」)。

  • Userモデル
    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;
use Illuminate\Contracts\Auth\MustVerifyEmail;

class User extends Authenticatable implements MustVerifyEmail
{
    //======== 中略 ========

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

+    // 1人のユーザーは複数の投稿を作成できる
+    public function posts()
+    {
+        return $this->hasMany(Post::class);
+    }
}
  • Postモデル
    app/Models/Post.php
<?php

namespace App\Models;

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

class Post extends Model
{
    use HasFactory;

+    // 1つの投稿は1人のユーザーに属する
+    public function user()
+    {
+        return $this->belongsTo(User::class);
+    }
}

Laravel ミニブログ作成2 認証を実装

Laravel Breezeパッケージで実装

Laravel Breezeパッケージの追加

プロジェクトディレクトリで

sail composer require laravel/breeze --dev

Laravel Breezeパッケージのインストール

sail artisan breeze:install

マイグレーションの実行

sail artisan migrate

依存関係のインストール

package.jsonにTailwind CSS とAlpine.jsが追記されるので、npm でパッケージを一括インストール

npm install

アセットのビルド

npm run build

ログインの確認

localhost/

  • 会員登録
  • ログイン
    を確認

認証を日本語化

エラーメッセージの日本語化

CLIで以下のコマンドを実行

php -r "copy('https://readouble.com/laravel/8.x/ja/install-ja-lang-files.php', 'install-ja-lang.php');"
php -f install-ja-lang.php
php -r "unlink('install-ja-lang.php');"
  1. 日本語化ファイルをインストールするためのスクリプトを、install-ja-lang.phpという名前でダウンロードする
  2. 1でダウンロードしたinstall-ja-lang.phpファイルを実行する(resources/lang/jaフォルダの中に各種日本語化ファイルが生成される)
  3. 不要になったinstall-ja-lang.phpファイルを削除する

resources/lang/jaフォルダの中に生成されたvalidation.phpというファイルには、日本語化されたエラーメッセージが記述されている。

次にconfigディレクトリのapp.phpを編集する。

- 'locale' => 'en'
+'locale' => ja 

各ページの表記の日本語化

各ページの__()ヘルパー関数が指定したキーに一致した値を返す。
config/app.phpファイルのlocalejaを指定した場合はresource/langディレクトリ内のja.jsonファイルが参照される。

resouces/langディレクトリにja.jsonファイルを作成。__()に対応する文字列を登録しておく。
ja.json

{
      "Email": "メールアドレス",
      "Password": "パスワード",
      "Remember me": "ログイン状態を保存する",
      "Log in": "ログイン",
      "Forgot your password?": "パスワードをお忘れですか?",
      "Name": "ユーザー名",
      "Confirm Password": "パスワード(確認用)",
      "Register": "登録",
      "Already registered?": "すでに登録済みですか?",
      "Forgot your password? No problem. Just let us know your email address and we will email you a password reset link that will allow you to choose a new one.": "パスワードをお忘れですか?ご心配なく。メールアドレスをお知らせいただければ、パスワード再設定用のリンクをメールでお送りします。",
      "Email Password Reset Link": "パスワード再設定用リンクの送信",
      "Reset Password": "パスワード再設定",
      "Thanks for signing up! Before getting started, could you verify your email address by clicking on the link we just emailed to you? If you didn't receive the email, we will gladly send you another.": "ご登録ありがとうございます!ご利用を開始する前に、メールアドレスをご確認ください。メールが届いていない場合は、再度お送りいたします。",
      "A new verification link has been sent to the email address you provided during registration.": "ご登録いただいたメールアドレスに新しい認証リンクを送信しました。",
      "Resend Verification Email": "認証メールの再送信",
      "Profile": "アカウント",
      "Log Out": "ログアウト",
      "Dashboard": "ダッシュボード",
      "You're logged in!": "ログインしました!",
      "Profile Information": "アカウント情報",
      "Update your account's profile information and email address.": "アカウント情報とメールアドレスを更新できます。",
      "Your email address is unverified.": "メールアドレスが未確認です。",
      "Click here to re-send the verification email.": "こちらをクリックして認証メールを再送信してください。",
      "A new verification link has been sent to your email address.": "あなたのメールアドレスに新しい認証リンクを送信しました。",
      "Save": "保存",
      "Saved.": "保存しました。",
      "Update Password": "パスワード更新",
      "Ensure your account is using a long, random password to stay secure.": "アカウントの安全性を保つために、長くてランダムなパスワードを使用してください。",
      "Current Password": "現在のパスワード",
      "New Password": "新しいパスワード",
      "Delete Account": "アカウント削除",
      "Once your account is deleted, all of its resources and data will be permanently deleted. Before deleting your account, please download any data or information that you wish to retain.": "アカウントを削除すると、関連するすべてのデータが永久に削除されます。アカウントを削除する前に、必要に応じてデータをバックアップしてください。",
      "Are you sure you want to delete your account?": "本当にアカウントを削除してもよろしいですか?",
      "Once your account is deleted, all of its resources and data will be permanently deleted. Please enter your password to confirm you would like to permanently delete your account.": "アカウントを削除すると、関連するすべてのデータが永久に削除されます。アカウントを削除してよろしければ、パスワードを入力してください。",
      "Cancel": "キャンセル",
      "Verify Email Address": "メールアドレス確認",
      "Hello!": "こんにちは!",
      "Please click the button below to verify your email address.": "下のボタンをクリックしてメールアドレスを確認してください。",
      "If you did not create an account, no further action is required.": "心当たりがない場合は、本メールを破棄してください。",
      "Regards": "よろしくお願いいたします",
      "If you're having trouble clicking the \":actionText\" button, copy and paste the URL below\ninto your web browser:": "「:actionText」ボタンを押しても何も起きない場合、以下のURLをコピーしてWebブラウザに貼り付けてください。",
      "Reset Password Notification": "パスワード再設定のお知らせ",
      "You are receiving this email because we received a password reset request for your account.": "あなたのアカウントでパスワード再設定のリクエストがありました。",
      "This password reset link will expire in :count minutes.": "このパスワード再設定リンクの有効期限は :count 分です。",
      "If you did not request a password reset, no further action is required.": "心当たりがない場合は、本メールを破棄してください。"
    }

メール認証

メール認証機能を有効

LaravelにはMustVerifyEmailというインターフェースがもともと用意されており、これをUserモデルに実装するだけ
インターフェース=メソッドやプロパティの名前のみを定義したもの(メソッドやプロパティの具体的な中身は記述しない)。複数のクラスに共通の機能を持たせたいときに使う 。

app/Models/User.php

<?php

namespace App\Models;

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

+ class User extends Authenticatable implements MustVerifyEmail
{
    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',
        'password' => 'hashed',
    ];
}

Gmailでメールの送信処理を実装

  1. Googleアカウントの2段階認証プロセスを有効にする
    Googleアカウントのトプページ
    「セキュリティ」->「2段階承認プロセス」から2段階承認を設定完了させる
  2. アプリパスワードを生成する
    「アプリパスワード」の>をクリック、「App name」にアプリ名を入力し「作成」
    パスワードが生成されるのでコピー
  3. GmailSMTPサーバーに設定
    .envファイルのMAIL設定を編集
MAIL_MAILER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME="アプリパスワードを発行したアカウントのGmailアドレス"
MAIL_PASSWORD="アプリパスワード"
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS="アプリパスワードを発行したアカウントのGmailアドレス"
MAIL_FROM_NAME="${APP_NAME}"

Laravel ミニブログ作成1 プロジェクトの作成

プロジェクト作成とタイムゾーン設定

プロジェクト作成

WSL上でのLaravelプロジェクト作成
WSL2上のDockerコンテナでsailを動かして開発を始める。

phpMyAdmin

プロジェクトディレクトリ直下のdocker-compose.yml のservicesにphpmyadminを追記

 phpmyadmin:
        image: phpmyadmin/phpmyadmin
        links:
            - mysql:mysql
        ports:
            - 8080:80
        environment:
            #PMA_USER: "${DB_USERNAME}"
            #PMA_PASSWORD: "${DB_PASSWORD}"
            PMA_HOST: mysql
        networks:
            - sail

http://localhost:8080でログイン画面が開く。
.envに記載している、DBのユーザとパスワードでログイン

DB_USERNAME=sail
DB_PASSWORD=password

タイムゾーンJST日本標準時)に変更

config/app.php

- 'timezone' => 'UTC',
+ 'timezone' => 'Asia/Tokyo',

Laravel パッケージLaravel

Laravelの代表的なパッケージ

パッケージ 説明
Laravel Breeze 認証機能を作成するためのパッケージ。導入コストが低く、従来のLaravel UIに近い感覚で利用できる。
Laravel Fortify 認証機能を作成するためのパッケージ。フロントエンドは自分で実装する必要があるが、実装方法を自由に選べるのが強み。
Laravel Jetstream 認証機能を作成するためのパッケージ。2段階認証やチーム機能など、多様な機能を提供するが、学習コストが高い。
Laravel Cashier Stripe オンライン決済サービスのStripeとLaravelプロジェクトを連携するためのパッケージ。サブスクリプション機能などを簡単に実装できる。
Laravel Socialite Facebook、X(旧Twitter)、GoogleGitHubなど、外部サービスを使った認証機能を追加するためのパッケージ。
Laravel Debugbar 開発環境において、ブラウザのページ上にデバッグ用のバーを表示するためのパッケージ。ビューに渡された変数や発行されたクエリ、セッションなどさまざまな情報を確認できる。
kyslik/column-sortable 並び替え機能を作成するためのパッケージ。
Laravel Scout モデルに全文検索機能を追加するためのパッケージ。
laravel-permission 「管理者」「一般ユーザー」など、ロールによるアクセス制御を実装するためのパッケージ。
laravelcollective/html Bladeテンプレートにおいてフォームの生成をサポートするためのパッケージ。Bladeテンプレート内でFormファサードが使えるようになり、コードがスッキリする。

パッケージの導入方法

sail composer require パッケージ名

Laravel ファイルのアップロード

アップロード機能の手順

  1. テーブル(カラム)を用意する
  2. アップロード先を設定する
  3. フォームを作成する
  4. アクションを作成する

テーブル(カラム)を用意する

テーブルにはVARCHARなど文字列型のカラム(例:file_nameカラム)を用意し、ファイル名やファイルパスの保存に使う。

アップロード先を設定する

Laravelでは、アップロードされたファイルの保存先はconfig/filesystems.phpファイルに設定されている。

保存先
'local ' storage/appフォルダ
'public' storage/app/publicフォルダ
's3' Amazon S3(接続先は.envファイルの環境変数で設定)

保存先を変更する場合、'default'キーに設定されている環境変数FILESYSTEM_DISKの値を.envファイルで編集します。デフォルトはFILESYSTEM_DISK=localなので、保存先はstorage/appフォルダになります。

フォームを作成する

ビューファイル内でアップロード用のフォームを作成します。重要なのは以下の2点です。 1. form要素にenctype="multipart/form-data"を設定し、ファイルも一緒に送信できるようにする 1. input要素にtype="file"を設定し、ファイルをアップロードするための入力欄を作成する 例

<form action="送信先のURL" method="POST" enctype="multipart/form-data">
    @csrf
    <input type="file" name="image">
    <input type="submit" value="アップロード">
</form>

アクションを作成する

コントローラのアクション(store、updateなど)では、主に以下の処理を行います。 1. アップロードされたファイルをRequestインスタンスのfile()メソッドで取得する 1. 取得したファイルをstore()メソッドで保存する 1. 保存先のファイル名やファイルパスをテーブルに保存する 例

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class SampleController extends Controller
{
    public function store(Request $request) {
        $sample = new Sample();

        // アップロードされたファイル(name="image")をstorage/app/samplesフォルダに保存し、戻り値(ファイルパス)を変数$image_pathに代入する
        $image_path = $request->file('image')->store('samples');

        // ファイルパスからファイル名のみを取得し、Sampleインスタンスのimage_nameプロパティに代入する
        $sample->image_name = basename($image_path);

        $sample->save();

        return redirect('/samples');
    }    
}
  • file()メソッドの引数:取得するファイルに対応するname属性の値
  • store()メソッドの引数:config/filesystems.phpファイルに設定した保存先(デフォルトはstorage/appフォルダ)より後のパス
    store()メソッドの戻り値は保存先のファイルパスなので、上記のサンプルコードのように変数($image_path)に代入しておくことで、その後の処理に使えます。

basename()はパスからファイル名を取得するPHPの関数です。例えば引数に'samples/sample.jpg'を渡した場合、戻り値は'sample.jpg'になります。

上記のサンプルコードのように、ファイル名を保存したい場合はとても便利な関数です。

アップロードしたファイルの表示方法

  1. シンボリックリンクを作成する(シンボリックリンクについては後述)
  2. ファイルのURLを取得する

シンボリックリンクを作成する

storage/app/publicフォルダへのシンボリックリンクpublic/storageフォルダに作成

sail artisan storage:link

アップロードされたファイルのデフォルトの保存先はstorage/appフォルダです。

しかし、Laravelではstorageフォルダ以下のファイルは外部に公開することができません。Laravelで外部に公開できるのは、publicフォルダ以下のファイルのみです。

そこで、storage/app/publicフォルダへのシンボリックリンクをpublic/storageフォルダに作成し、storage/app/publicフォルダ以下のファイルを参照することで、間接的にファイルを公開します。

ファイルのURLを取得

ビューファイル内でasset()ヘルパ関数を使い、ファイルのURLを取得すればOKです

<img src="{{ asset('storage/samples/' . $sample->image_name) }}" alt="アップロードした画像ファイル">
// http://example.com/public/s

asset('ファイルパス')はpublicディレクトリのパスを返す関数

.envと合わせて

asset()関数は、現在のリクエストのスキーマ(HTTPかHTTPS)を使い、アセットへのURLを生成します。
.envファイルのASSET_URL変数で、アセットURLホストを設定できます。

// ASSET_URL=http://example.com/assets

$url = asset('img/photo.jpg'); // http://example.com/assets/img/photo.jpg

Laravel Breezeパッケージを使って認証と認可

認可(Authorization)とは、「あなたはこのアクションを実行する権限がありますか?」という権限確認を行うこと。

例えば「誰でも閲覧できる」「ログイン中のユーザーのみが閲覧できる」「管理者のみがデータを作成できる」など、ルーティングの各ルートにアクセス権限を設定するのが認可です。

  • 認証(Authentication)=「あなたは本当に○○さんですか?」という本人確認を行う
  • 認可(Authorization)=「あなたはこのアクションを実行する権限がありますか?」という権限確認を行う

Laravel Breezeパッケージの追加

プロジェクトディレクトリ上でコマンド

composer require laravel/breeze --dev

Laravel Breezeパッケージのインストール

php artisan breeze:install

コマンドを実行すると3つの質問が続くので、それぞれ以下のように入力してエンターキー

質問 回答
Which Breeze stack would you like to install?(どのBreezeスタックをインストールしますか?) blade
Would you like dark mode support?(ダークモードをサポートしますか?) no
Which testing framework do you prefer?(テスト用のフレームワークはどちらを使いますか?) 0

Laravel Breezeパッケージのインストールによって生成・編集される主なファイル

  • コントローラ
    • app/Http/Controllers/Auth
      • ログイン、会員登録、パスワードリセットなど、認証関連の各種コントローラを配置
    • app/Http/Controllers/ProfileController.php
      • 会員情報の更新・削除に関するコントローラ
  • フォームリクエス
    • app/Http/Requests/Auth/LoginRequest.php
      • ログイン時のバリデーションルールを定義
    • app/Http/Requests/ProfileUpdateRequest.php
      • 会員情報を更新する際のバリデーションルールを定義
  • ビュー
    • resources/views/auth
      • ログイン、会員登録、パスワードリセットなど、認証関連の各種ビューファイルを配置
    • resources/views/dashboard.blade.php
      • ログイン後にリダイレクトされるダッシュボード
    • resources/views/components
      • ボタンやドロップダウンなど、ページの部品を配置
    • resources/views/layouts
      • ナビゲーションメニューなど、複数のページで共有するビューファイルを配置
    • resources/views/profile
      • 会員情報の更新・削除に関するビューファイルを配置
  • ルーティング
    • routes/auth.php
      • 認証関連のルートを定義
    • routes/web.php
      • ダッシュボードや会員情報の更新・削除に関するルートを定義 ※既存のweb.phpファイルが上書きされるため、アプリ開発の途中でインストールする場合は注意が必要
  • テスト(テストについては31章で学習)
    • tests/Feature/ProfileTest.php
      • 認証関連のテストを定義
  • その他
    • tailwind.config.js
      • Tailwind CSSの設定ファイル
    • package.json
      • リストにTailwind CSSやAlpine.jsなどを追記

ルーティング

Laravel Breezeをインストールすると、既存のroutes/web.phpファイルが上書きされる。そのため、Laravel Breezeは新規のLaravelプロジェクトにインストールするのが一般的
開発途中でインストールする場合はルーティングしなおす。

マイグレーションの実行

Laravel Breezeでは、Laravelがデフォルトでマイグレーションファイルを用意しているusersテーブルとassword_reset_tokensテーブルを利用し、認証機能を実装しています。

新規のLaravelプロジェクトの場合はこのタイミングでマイグレーションを実行し、マイグレーションファイルを適用する必要があります。

依存関係のインストールとアセットのビルド

インストール

npm install

ビルド

npm run build

認証の日本語化


resources/views/auth/login.blade.php

<x-guest-layout>
    <!-- Session Status -->
    <x-auth-session-status class="mb-4" :status="session('status')" />

    <form method="POST" action="{{ route('login') }}">
        @csrf

        <!-- Email Address -->
        <div>
            <x-input-label for="email" :value="__('Email')" />
            <x-text-input id="email" class="block mt-1 w-full" type="email" name="email" :value="old('email')" required autofocus autocomplete="username" />
            <x-input-error :messages="$errors->get('email')" class="mt-2" />
        </div>

<!--======== 後略 ========-->

__()ヘルパ関数
__()ヘルパーは、config/app.phpファイルの'locale'に設定中の言語ファイルから、指定したキー(上記の場合は'Email')に対応する値を呼び出す。

例えばconfig/app.phpファイルの'locale'に'ja'を指定した場合、resources/langフォルダ内にあるja.jsonというファイルが参照される。

resources/lang/ja.json

{
  "Email": "メールアドレス",
  "Password": "パスワード",
  "Remember me": "ログイン状態を保存する",
  "Log in": "ログイン",
  "Forgot your password?": "パスワードをお忘れですか?",
  "Name": "ユーザー名",
  "Confirm Password": "パスワード(確認用)",
  "Register": "登録",
  "Already registered?": "すでに登録済みですか?"
}

認証機能が追加されている。

ルート/

laravel-breeze-/

Login

laravel-breeze-login

3 認可の実装

Laravelにおいて、特定のルートで認可やその他の前処理を行うには、middleware()メソッドを使います。引数として渡すエイリアス(別名、あだ名)によって、その前処理の内容が決まります。

エイリアス 説明
'auth' ユーザーがログイン済みであることを確認する。未ログインの場合、デフォルトではログインページ(/login)にリダイレクトされる。
'guest' ユーザーがゲスト(未ログイン)であることを確認する。ログイン済みの場合、デフォルトではダッシュボード(/dashboard)にリダイレクトされる(Laravel Breezeを利用している場合)。
'verified' ユーザーがメール認証済みであることを確認する(メール認証機能を有効にしている場合のみ)。メール認証済みでない場合、デフォルトではメール認証を促すページ(/verify-email)にリダイレクトされる(Laravel Breezeを利用している場合)。

認可の例

Route::get('/vendors/create', [VendorController::class, 'create'])->middleware('auth');

vendors/createにGETメソッドでリクエストが来たらミドルウェアに引数authが渡されてるので、上記の通りにログインされていれば表示、ログインされていなければログインページにリダイレクトされる。