トップページ
Laravel学習サイトLaravelやるばい

目次

ログイン・ユーザー登録をしてつぶやきを作成する

 今回のアプリから難易度を少し上げます。

何のアプリを作る解説にしようか迷いましたが第3回のつぶやきアプリの作成の復習も兼ねてユーザー登録・ログイン機能が入っていてリソースコントローラーを使わないつぶやきアプリにすることにしました。


プロジェクトの作成とMAMPの設定

Laravelのプロジェクトを作成して動作するようにMAMPの設定をして下さい。

やり方が分からない人は第3回の解説を読んで下さい。

今回使うアプリ名は「tweet」とします。


ユーザー登録・ログイン機能

Breezeというライブラリを使います。

tweetプロジェクトに移動してターミナルで下記のコマンドを入力します。

composer require laravel/breeze --dev

そして下記のコマンドを入力します。

php artisan breeze:install

すると下記の選択が表示されます。

┌ Which Breeze stack would you like to install? ───────────────┐
 │ › ● Blade with Alpine                                        │
 │   ○ Livewire (Volt Class API) with Alpine                    │
 │   ○ Livewire (Volt Functional API) with Alpine               │
 │   ○ React with Inertia                                       │
 │   ○ Vue with Inertia                                         │
 │   ○ API only                                                 │
 └──────────────────────────────────────────────────────────────┘

私は「Blade with Alpine」を選択しましたがLaravelを始めたばかりの人はこれで問題ないです。

下記の選択は「No」にしました。

┌ Would you like dark mode support? ───────────────────────────┐
 │ ○ Yes / ● No                                                 │
 └──────────────────────────────────────────────────────────────┘


下記の選択は「PHPUnit」にしました。

┌ Which testing framework do you prefer? ──────────────────────┐
 │ › ● PHPUnit                                                  │
 │   ○ Pest                                                     │
 └──────────────────────────────────────────────────────────────┘


選択が全て終わるとBreezeがインストールされます。

そしてLaravelのトップページに移動するとログインとユーザー登録のリンクが作成されます。

20241209_205246_tweet21.jpg

ユーザーを作成・またはログインすると下記のページにリダイレクトするので確認してください。

20241209_222949_tweet22.jpg

phpMyAdminのusersテーブルでユーザーが作成されているかを確認して下さい。

20241209_223530_tweet23.jpg

それではつぶやきを作成するのに使うコントローラーの作成から始めます。

前回作ったつぶやきアプリの解説でLaravelではルーティング・コントローラー・ビューがありこの順に考えますと言ったのでこの順に考えていきましょう。


ルーティング

「tweet > routes > web.php」に記述します。

最初の状態は下記になっています。

<?php

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

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider and all of them will
| be assigned to the "web" middleware group. Make something great!
|
*/

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

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

Route::middleware('auth')->group(function () {
    Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');
    Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update');
    Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy');
});

require __DIR__.'/auth.php';

つぶやきを作成する時は作成するページを表示してつぶやきを保存するのでページの表示とつぶやきの保存用の2つのURLが必要になります。

まずはページの表示をします。

下記の記述をします。

<?php

use App\Http\Controllers\ProfileController;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\TweetController;        //この行を追加

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider and all of them will
| be assigned to the "web" middleware group. Make something great!
|
*/

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

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

Route::middleware('auth')->group(function () {
    Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');
    Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update');
    Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy');
});


// ここから追加
Route::controller(TweetController::class)->group(function() {
    Route::get('/tweet/create', 'create')->name('tweet.create');
});
// ここまで追加


require __DIR__.'/auth.php';

前回のアプリ作成の時の復習も含めてもう一度解説します。

use App\Http\Controllers\TweetController;」は使用するコントローラーがある場合は記述しないといけません。

新しいコントローラーを使うたびに「TweetController」の名称を変えて記述していきます。

コントローラー名は「Tweet」とします。

Route::controller(TweetController::class)->group(function()〜」の部分はコントローラーに対するURL・アクション・Httpリクエストを設定しています。

コントローラーを指定する時は下記の記述をします。

Route::controller(TweetController::class)->group(function() {
    // ここでURL・アクション・Httpリクエストの設定
});

「TweetController」の部分にコントローラー名を記述します。
Route::get('/tweet/create', 'create')->name('tweet.create');」の「/tweet/create」はURLの設定で「create」はアクションの設定で「get」はHttpリクエストの設定です。

理解するのが難しいのはHttpリクエストだと思います。(私が初めてLaravelを勉強した時はこれを理解するのに苦労しました)

Httpリクエストは表示・保存・更新・削除の時に書かないといけない記号みたいな感じです。

下記の対応をさせれば題ないと思います。

今回はつぶやきを作成するページを表示するのでgetを使います。

ルーティングの設定をここで終わるとログインしてなくてもつぶやきを作成するページに移動できます。

ログインしてからじゃないとページに移動できないのが普通だと思うのでログインした場合だけページに移動できるようにします。

web.phpのコードに追記します。

Route::middleware('auth')->group(function () {            //この行を追加
    Route::controller(TweetController::class)->group(function() {
        Route::get('/tweet/create')->name('tweet.create');
    });
});           //この行を追加

追加した行の「middleware('auth')」でログインしている場合という意味になります。

ログインした状態じゃないと作成ページに移動できないことを確認する為にログイン直後のページ(http://localhost:8888/dashboard)にアクセスします。(まだコントローラーを作成してないので今アクセスするとエラーになります。コントローラーを作成してcreateアクションの記述をしてから確認してください)

右上の「Log Out」からログアウトできます。

20241210_201307_tweet24.jpg

そしてつぶやきを作成するページ(http://localhost:8888/tweet/create)にアクセスするとログイン画面にリダイレクトするのを確認して下さい。

ちなみにつぶやきを作成するページのURLですが以前つぶやきアプリを作成した時は下記のコマンドで確認しています。

php artisan route:list

リソースコントローラーを使う場合はURLが自動的に作成されるからこのコマンドを使わないとURLが分からないですが今回はリソースコントローラーを使ってないのでルーティングから判断します。

Route::get('/tweet/create')->name('tweet.create');

「/tweet/create」を見てURLを判断しています。

話を戻して「tweet.create」はtweetフォルダの下にcreate.blade.pを作成するという意味でした。

tweetフォルダの作成場所は「tweet  > resources > views」の下です。

create.blade.phpの記述はコントローラーのcreateアクションの記述をしてからにします。

次はコントローラーです。

まだ作成していないので作成してから記述します。


コントローラーの作成

下記のコマンドを入力します。

php artisan make:controller TweetController

コマンドの最後に「--resource」を付けるとリソースコントローラーになりますが今回は使わないので付けません。

これで「tweet > app > Http > Controllers > TweetController.php」が作成されて中身が下記になっています。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class TweetController extends Controller
{
    //
}

リソースコントローラーの時はアクションが指定されていましたが通常のコントローラーはアクション名を自由に決めることができます。

前回のアプリ作成の時につぶやきを表示するページのアクションはcreateアクションだったのでその時に合わせてこれを記述します。(合わせなくてもいいです)

下記の記述をして下さい。

class TweetController extends Controller
{


    //ここから追加
    public function create()
    {
        return view('tweet.create');
    }
    //ここまで追加

    
}

create.blade.phpに下記の記述をします。

<div class="wrap">
    <h1>つぶやきの作成</h1>
    <form method="post" action="">
        @csrf
        <div>
            <textarea name="body" cols="40" rows="10" placeholder="ここにつぶやきの内容を書く"></textarea>
        </div>
        <button type="submit">つぶやく</button>
    </form>
</div>

<style>
    .wrap{
        width: 1000px;
        margin-left:auto;
        margin-right:auto;
        margin-top: 100px;
    }
    button{
        margin-top: 50px;
    }
</style>

「http://localhost:8888/tweet/create」にアクセスして下記の表示になっていたら成功です。

20241210_203426_tweet25.jpg
それでは保存の処理をします。


ルーティング

web.phpのコードを下記にします。

Route::middleware('auth', 'verified')->group(function () {
    Route::controller(TweetController::class)->group(function() {
        Route::get('/tweet/create', 'create')->name('tweet.create');

        Route::post('/tweet/store', 'store')->name('tweet.store');       //この行を追加
    });
});

Httpリクエスト(Route::postの部分)は保存なのでpostです。

「->name('tweet.stoer')」の部分に違和感を感じませんか?

つぶやきを保存するのは処理だからファイルは必要ないじゃないですか?

create.blade.phpで必要になるから記述しているだけでstore.blade.phpは作成しません。


コントローラー

TweetController.phpにstoreアクションの記述を下記にします。

use App\Models\Tweet;         //この行を追加


class TweetController extends Controller
{
    public function create()
    {
        return view('tweet.create');
    }
    

    //ここから追加
    public function store(Request $request)
    {
        $tweets = new Tweet();
        $tweets->body = $request->body;
        $tweets->save();
        return back()->with('message', 'つぶやきを作成しました');
    }
    //ここまで追加


}

以前作成したつぶやきアプリでは「$request->body」がフォームに入力した内容と解説したと思いますが「$request」を使う為にはstoreメソッドの引数に「Request $request」を記述しないといけないと覚えましょう。

ちゃんとした意味はありますが今はこれ位の認識で問題ないです。

つぶやきを保存する為のtweetsテーブルをまだ作成していないのでマイグレーションファイルを作成してテーブルを作成します。

下記のコマンドを入力します。

php artisan make:model Tweet -m

マイグレーションファイルに下記の記述をします。

<?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('tweets', function (Blueprint $table) {
            $table->id();
            $table->string('body');      //この行を追加
            $table->timestamps();
        });
    }

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

記述が終わったら下記のコマンドを入力します。

php artisan migrate

場合によっては下記のエラーが出るかもしれません。

SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'tweets' already exists (Connection: mysql, SQL: create table `tweets` (`id` bigint unsigned not null auto_increment primary key, `body` varchar(255) not null, `created_at` timestamp null, `updated_at` timestamp null) default character set utf8mb4 collate 'utf8mb4_unicode_ci')

これは以前作成したつぶやきアプリのtweetsテーブルが残っていることによるエラーです。

削除して新しくtweetsテーブルを作成しましょう。

phpMyAdminのページでtweets(下記赤枠)をクリックして削除ボタン(下記青枠)をクリックすれば削除できます。

20241210_223545_tweet26.jpg

テーブルを作成したらTweetモデルにテーブルに追加を許可するカラムの設定をする為に下記の記述をします。

<?php

namespace App\Models;

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

class Tweet extends Model
{
    use HasFactory;


    //ここから追加
    protected $fillable = [
        'body'
    ];
    //ここまで追加

    
}

「body」の部分にはテーブルに保存するカラムを全て記述しないといけないと思いましょう。

私がLaravelを勉強したての時にここの記述をよく忘れていてテーブルに値を保存できなくなって悩んでいました。

複数のカラムを登録する場合は下記の記述にすればいいです。

protected $fillable = [
    'body',
    'カラム2',
    'カラム3',
       ・
       ・
];

最後にweb.phpの「tweet.store」をcreate.blade.phpに反映させます。

Route::post('/tweet/store', 'store')->name('tweet.store');     //「->name('tweet.store')」のこと

create.blade.phpのコードを下記に変更します。

<div class="wrap">


    //ここから追加
    @if(session('message'))
        <p class="flash">{{ session('message') }}</p>
    @endif
    //ここまで追加


    <h1>つぶやきの作成</h1>
    <form method="post" action="{{ route('tweet.store') }}">       //この行を修正
        @csrf
        <div>
            <textarea name="body" cols="40" rows="10" placeholder="ここにつぶやきの内容を書く"></textarea>
        </div>
        <button type="submit">つぶやく</button>
    </form>
</div>

<style>
    .wrap{
        width: 1000px;
        margin-left:auto;
        margin-right:auto;
        margin-top: 100px;
    }


    //ここから追加
    .flash{
        border:1px solid red;
        text-align: center;
        padding: 5px;
    }
    //ここまで追加

    
    button{
        margin-top: 50px;
    }
</style>

「@if(session('message')〜」はTweetController.phpのstoreアクションの「->with('message', 'つぶやきを作成しました')」を反映させる為の記述です。

public function store(Request $request)
{
    $tweets = new Tweet();
    $tweets->body = $request->body;
    $tweets->save();
    return back()->with('message', 'つぶやきを作成しました');       //←これ
}

「action="{{ route('tweet.store') }}"」の「tweet.store」はweb.phpの「->name('tweet.store')」を記述しています。

web.phpに必要がない「->name('tweet.store')」をわざわざ記述したのはcreate.blade.phpで使う為です。

これで完成なので「http://localhost:8888/tweet/create」でつぶやきを作成して下さい。

つぶやきを作成できたら下記の赤枠のメッセージが表示されるのを確認して下さい。

20241211_092154_tweet27.jpg
今回はここまでです。












 


戻る