副業におすすめなサイトを見る→

Laravel9ニュースサイト11下書き保存・公開中・予約公開一覧【Laravel9×TailwindCSS】

アプリリリースのお知らせ

予定を探すアプリyoteipickerをリリースしました。

アプリの利用用途:暇だから何か予定入れたいけど今週の土日は何しようかな〜?ってときに使えるアプリです。

前回までの記事

  1. ニュースサイト概要
  2. 環境構築
  3. 総合トップ画面の作成
  4. マイページの作成
  5. ユーザー新規登録・ログイン・ログアウト
  6. マイページの投稿リスト
  7. 記事投稿
  8. 記事の詳細
  9. 記事の編集・更新
  10. ゴミ箱・記事の削除

開発環境

環境バージョン
MacBook AirMonterey 12.2.1
Docker20.10.7
PHP8.1
composer2.2.9
Laravel9.5.1
apache2.4
MySQL8.0
phpmyadmin
npm8.5
node12.22.11
React17
TailwindCSS3
Laravel/breezeログイン認証機能で使用
※Laravel8以降の場合に使用可。
Laravel6や7系はreact –authとか使います。

開発+α

◆dockerコンテナの情報を確認する
→docker ps

◆dockerのphpコンテナに入る
→docker exec -it コンテナIDまたはNAMES bash

◆var/www# はphpコンテナ内を表します。php artisanやnpm run devなどはphpコンテナ内で実行しましょう。

◆tailwindcssでスタイルを変更する前に
→npm run watchを実行していると開発が楽。
※ある程度スタイルが整ったら、npm run devでビルドしましょう。
すると、不要なcssを削除してくれるのでcssファイルが軽くなります。

◆スタイルが適用されないときは….
npm run devで一旦ビルドしてみるか、スーパーリロードでキャッシュの削除をしてみましょう。

もし実装で困ったことがあれば、記事下のコメントでお知らせください。

この記事でやること
  • 記事のステータスが下書き保存の記事一覧画面
  • ステータスが公開の記事一覧画面
  • 予約公開の記事一覧画面
  • 記事を投稿・編集・ゴミ箱・復元・削除した時にフラッシュメッセージを表示させる

最終的なゴール

  • 下書き保存一覧
  • 公開記事一覧
  • 予約公開記事一覧
  • フラッシュメッセージ

>>ココナラと似てるおすすめの副業サイトを確認する

>>リモートワークもあるおすすめの転職サイトを確認する

休日で空いた時間の暇つぶしを探せるアプリを公開しています。

Contents

下書き保存一覧を実装する

流れとしては、

マイページのサイドバーにある下書き保存をクリック→記事のステータスが下書き保存のみの記事を一覧で表示する

といった内容になります。

下書き保存一覧のルーティングを追加する

まずは、画面に遷移させるのでメソッドはGETでルーティングを追加します。

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\TopController;
use App\Http\Controllers\User\PostController;
use App\Http\Controllers\User\TrashController;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/dashboard', function () {
    return view('dashboard');
})->middleware(['auth'])->name('dashboard');

require __DIR__.'/auth.php';

// 総合トップ
Route::controller(TopController::class)->group(function() {
    // 総合トップ画面
    Route::get('/', 'top')
        ->name('top');
    // 総合トップ記事詳細画面
    Route::get('/article/{post_id}', 'articleShow')
        ->name('top.article.show');
    // 総合トップカテゴリーごとの記事一覧
    Route::get('/article/category/{category_id}', 'articleCategory')
        ->name('top.article.category');
});

// マイページ投稿関係
Route::controller(PostController::class)->group(function() {
    // マイページトップ・投稿
    Route::get('/user/{id}/index', 'index')
        ->name('user.index');

    // 投稿登録画面
    Route::get('/post/create', 'create')
        ->name('post.create');

    // 投稿登録処理
    Route::post('/post/store', 'store')
        ->name('post.store');

    // 投稿詳細
    Route::get('/post/show/{post_id}', 'show')
        ->name('post.show');

    // 記事編集
    Route::get('/post/edit/{post_id}', 'edit')
        ->name('post.edit');

    // 記事更新
    Route::post('/post/edit/{post_id}', 'update')
        ->name('post.update');

    // 下書き保存一覧
    Route::get('/post/saveDraft', 'saveDraft')
        ->name('post.saveDraft');
});

// ゴミ箱関係
Route::controller(TrashController::class)->group(function() {
    // 記事のゴミ箱
    Route::get('/post/trash', 'trashList')
        ->name('post.trash');

    // 記事論理削除(ゴミ箱に移動)
    Route::post('/post/trash/{post_id}', 'moveTrash')
        ->name('post.move.trash');

    // 記事の復元(ゴミ箱から投稿リストに戻す)
    Route::post('/post/restore/{post_id}', 'restore')
        ->name('post.restore');

    // 記事を完全に削除
    Route::post('/post/delete/{post_id}', 'delete')
        ->name('post.delete');
});

マイページのサイドバーの下書き保存をクリックしたら下書き保存一覧に遷移するようにします。

@section('sidebar')
<div class="h-screen hidden lg:block shadow-lg relative w-50">
    <div class="bg-amber-100 h-full">
        <div class="pt-3 pl-3">こんにちは、<br>{{ Auth::user()->name }}さん</div>
        <div class="flex items-center justify-start pt-6 ml-8">
            <p class="font-bold text-xl">
                Laratto
            </p>
        </div>
        <nav class="mt-6">
            <div>
                <a class="flex items-center px-4 py-2 mt-2 text-gray-600 transition-colors duration-200 transform hover:bg-sky-500 hover:text-white"
                href="{{ route('top') }}">
                    <span class="text-left">
                        <svg width="20" height="20" fill="currentColor" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg">
                            <path d="M1472 992v480q0 26-19 45t-45 19h-384v-384h-256v384h-384q-26 0-45-19t-19-45v-480q0-1 .5-3t.5-3l575-474 575 474q1 2 1 6zm223-69l-62 74q-8 9-21 11h-3q-13 0-21-7l-692-577-692 577q-12 8-24 7-13-2-21-11l-62-74q-8-10-7-23.5t11-21.5l719-599q32-26 76-26t76 26l244 204v-195q0-14 9-23t23-9h192q14 0 23 9t9 23v408l219 182q10 8 11 21.5t-7 23.5z">
                            </path>
                        </svg>
                    </span>
                    <span class="mx-2 text-md font-normal">
                        総合トップへ戻る
                    </span>
                </a>
            </div>
            <div>
                <a class="flex items-center px-4 py-2 mt-2 text-gray-600 transition-colors duration-200 transform hover:bg-sky-500 hover:text-white"
                href="#">
                    <span class="text-left">
                        <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
                            <path d="M5 4a2 2 0 012-2h6a2 2 0 012 2v14l-5-2.5L5 18V4z" />
                        </svg>
                    </span>
                    <span class="mx-2 text-md font-normal">
                        マイニュース
                    </span>
                </a>
            </div>
            <div>
                <a class="flex items-center px-4 py-2 mt-2 text-gray-600 transition-colors duration-200 transform hover:bg-sky-500 hover:text-white"
                href="{{ route('user.index', ['id' => Auth::user()->id]) }}">
                    <span class="text-left">
                        <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
                            <path fill-rule="evenodd" d="M18 13V5a2 2 0 00-2-2H4a2 2 0 00-2 2v8a2 2 0 002 2h3l3 3 3-3h3a2 2 0 002-2zM5 7a1 1 0 011-1h8a1 1 0 110 2H6a1 1 0 01-1-1zm1 3a1 1 0 100 2h3a1 1 0 100-2H6z" clip-rule="evenodd" />
                        </svg>
                    </span>
                    <span class="mx-2 text-md font-normal">
                        投稿
                    </span>
                </a>
            </div>
            <div>
                <a class="flex items-center px-4 py-2 mt-2 text-gray-600 transition-colors duration-200 transform hover:bg-sky-500 hover:text-white"
                href="{{ route('post.saveDraft') }}">
                    <span class="text-left">
                        <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
                            <path fill-rule="evenodd" d="M2 9.5A3.5 3.5 0 005.5 13H9v2.586l-1.293-1.293a1 1 0 00-1.414 1.414l3 3a1 1 0 001.414 0l3-3a1 1 0 00-1.414-1.414L11 15.586V13h2.5a4.5 4.5 0 10-.616-8.958 4.002 4.002 0 10-7.753 1.977A3.5 3.5 0 002 9.5zm9 3.5H9V8a1 1 0 012 0v5z" clip-rule="evenodd" />
                        </svg>
                    </span>
                    <span class="mx-2 text-md font-normal">
                        下書き保存
                    </span>
                </a>
            </div>
            <div>
                <a class="flex items-center px-4 py-2 mt-2 text-gray-600 transition-colors duration-200 transform hover:bg-sky-500 hover:text-white"
                href="#">
                    <span class="text-left">
                        <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
                            <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm1-12a1 1 0 10-2 0v4a1 1 0 00.293.707l2.828 2.829a1 1 0 101.415-1.415L11 9.586V6z" clip-rule="evenodd" />
                        </svg>
                    </span>
                    <span class="mx-2 text-md font-normal">
                        公開予約
                    </span>
                </a>
            </div>
            <div>
                <a class="flex items-center px-4 py-2 mt-2 text-gray-600 transition-colors duration-200 transform hover:bg-sky-500 hover:text-white"
                href="{{ route('post.trash') }}">
                    <span class="text-left">
                        <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
                            <path d="M4 3a2 2 0 100 4h12a2 2 0 100-4H4z" />
                            <path fill-rule="evenodd" d="M3 8h14v7a2 2 0 01-2 2H5a2 2 0 01-2-2V8zm5 3a1 1 0 011-1h2a1 1 0 110 2H9a1 1 0 01-1-1z" clip-rule="evenodd" />
                          </svg>
                    </span>
                    <span class="mx-2 text-md font-normal">
                        ゴミ箱
                    </span>
                </a>
            </div>
            <div>
                <a class="flex items-center px-4 py-2 mt-2 text-gray-600 transition-colors duration-200 transform hover:bg-sky-500 hover:text-white"
                href="#">
                    <span class="text-left">
                        <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
                            <path d="M2 11a1 1 0 011-1h2a1 1 0 011 1v5a1 1 0 01-1 1H3a1 1 0 01-1-1v-5zM8 7a1 1 0 011-1h2a1 1 0 011 1v9a1 1 0 01-1 1H9a1 1 0 01-1-1V7zM14 4a1 1 0 011-1h2a1 1 0 011 1v12a1 1 0 01-1 1h-2a1 1 0 01-1-1V4z" />
                        </svg>
                    </span>
                    <span class="mx-2 text-md font-normal">
                        統計データ
                    </span>
                </a>
            </div>
            <div>
                <a class="flex items-center px-4 py-2 mt-2 text-gray-600 transition-colors duration-200 transform hover:bg-sky-500 hover:text-white"
                href="#">
                    <span class="text-left">
                        <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
                            <path d="M11 3a1 1 0 100 2h2.586l-6.293 6.293a1 1 0 101.414 1.414L15 6.414V9a1 1 0 102 0V4a1 1 0 00-1-1h-5z" />
                            <path d="M5 5a2 2 0 00-2 2v8a2 2 0 002 2h8a2 2 0 002-2v-3a1 1 0 10-2 0v3H5V7h3a1 1 0 000-2H5z" />
                        </svg>
                    </span>
                    <form action="{{ route('logout') }}" method="POST">
                    @csrf
                        <button>
                            <span class="mx-2 text-md font-normal">
                                ログアウト
                            </span>
                        </button>
                    </form>
                </a>
            </div>
        </nav>
    </div>
</div>
@endsection

Postコントローラーに下書き保存一覧のアクションを追加する

PostコントローラーにsaveDraftアクションを追加します。

<?php

namespace App\Http\Controllers\User;

use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;
use App\Models\Post;
use App\Models\Category;
use App\Http\Requests\PostRequest;

class PostController extends Controller
{
    private $post;
    private $category;

    public function __construct()
    {
        $this->post = new Post();
        $this->category = new Category();
    }

    /**
     * 投稿リスト
     *
     * @param int $id ユーザーID
     * @return Response src/resources/views/user/list/index.blade.phpを表示
     */
    public function index(int $id)
    {
        // ユーザーIDと一致する投稿データを取得
        $posts = $this->post->getAllPostsByUserId($id);
        return view('user.list.index', compact(
            'posts',
        ));
    }

    /**
     * 記事投稿画面
     *
     * @return Response src/resources/views/user/list/create.blade.phpを表示
     */
    public function create()
    {
        // カテゴリーデータを全件取得
        $categories = $this->category->getAllCategories();
        return view('user.list.create', compact(
            'categories',
        ));
    }

    /**
     * 記事投稿処理
     *
     * @param string $request リクエストデータ
     * @return Response src/resources/views/user/list/index.blade.phpを表示
     */
    public function store(PostRequest $request)
    {
        // ログインしているユーザー情報を取得
        $user = Auth::user();
        // ログインユーザー情報からユーザーIDを取得
        $user_id = $user->id;

        switch (true) {
            // 下書き保存クリック時の処理
            case $request->has('save_draft'):
                $this->post->insertPostToSaveDraft($user_id, $request);
                break;
            // 公開クリック時の処理
            case $request->has('release'):
                $this->post->insertPostToRelease($user_id, $request);
                break;
            // 予約公開クリック時の処理
            case $request->has('reservation_release'):
                $this->post->insertPostToReservationRelease($user_id, $request);
                break;
            // 上記以外の処理
            default:
                $this->post->insertPostToSaveDraft($user_id, $request);
                break;
        }

        return to_route('user.index', ['id' => $user_id]);
    }

    /**
     * 記事詳細
     *
     * @param int $post_id 投稿ID
     * @return Response src/resources/views/user/list/show.blade.phpを表示
     */
    public function show($post_id) {
        // リクエストされた投稿IDをもとにpostsテーブルから一意のデータを取得
        $showPostData = $this->post->feachPostDateByPostId($post_id);
        return view('user.list.show', compact(
            'showPostData',
        ));
    }

    /**
     * 記事編集
     *
     * @param int $post_id 投稿ID
     * @return Response src/resources/views/user/list/edit.blade.phpを表示
     */
    public function edit($post_id)
    {
        // カテゴリーデータを全件取得
        $categories = $this->category->getAllCategories();
        // 投稿IDをもとに特定の投稿データを取得
        $post = $this->post->feachPostDateByPostId($post_id);
        return view('user.list.edit', compact(
            'categories',
            'post',
        ));
    }

    /**
     * 記事の更新
     *
     * @param int $post_id 投稿ID
     * @return Response src/resources/views/user/list/index.blade.phpを表示
     */
    public function update(PostRequest $request, $post_id)
    {
        // ログインしているユーザー情報を取得
        $user = Auth::user();
        // ログインユーザー情報からユーザーIDを取得
        $user_id = $user->id;

        // 投稿IDをもとに特定の投稿データを取得
        $post = $this->post->feachPostDateByPostId($post_id);

        switch (true) {
            // 下書き保存クリック時の処理
            case $request->has('save_draft'):
                $this->post->updatePostToSaveDraft($request, $post);
                break;
            // 公開クリック時の処理
            case $request->has('release'):
                $this->post->updatePostToRelease($request, $post);
                break;
            // 予約公開クリック時の処理
            case $request->has('reservation_release'):
                $this->post->updatePostToReservationRelease($request, $post);
                break;
            // 上記以外の処理
            default:
                $this->post->updatePostToSaveDraft($request, $post);
                break;
        }

        return to_route('user.index', ['id' => $user_id]);
    }

    /**
     * 下書き保存一覧
     *
     * @return Response src/resources/views/user/list/saveDraft.blade.phpを表示
     */
    public function saveDraft()
    {
        // ログインしているユーザー情報を取得
        $user = Auth::user();
        // ログインユーザー情報からユーザーIDを取得
        $user_id = $user->id;
        // 下書き保存の記事一覧を取得
        $saveDrafts = $this->post->getSaveDraftPosts($user_id);
        return view('user.list.saveDraft', compact(
            'saveDrafts',
        ));
    }
}

Postモデルに下書き保存一覧のロジックをかく

PostモデルにgetSaveDraftPostsメソッドを追加します。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use App\Models\User;
use App\Models\Category;
use Illuminate\Support\Carbon;

/**
 * 投稿モデル
 */
class Post extends Model
{
    /**
     * モデルに関連付けるテーブル
     *
     * @var string
     */
    protected $table = 'posts';

    /**
     * 複数代入可能な属性
     *
     * @var array
     */
    protected $fillable = [
        'user_id',
        'category_id',
        'title',
        'body',
        'publish_flg',
        'view_counter',
        'favorite_counter',
        'delete_flg',
        'created_at',
        'updated_at'
    ];

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

    /**
     * Categoryモデルとリレーション
     */
    public function category()
    {
        return $this->belongsTo(Category::class);
    }

    /**
     * 投稿データを全て取得し、最新更新日時順にソート
     */
    public function getPostsSortByLatestUpdate()
    {
        $result = $this->where([
                            ['publish_flg', 1],
                            ['delete_flg', 0],
                        ])
                       ->orderBy('updated_at', 'DESC')
                       ->with('user')
                       ->with('category')
                       ->get();
        return $result;
    }

    /**
     * カテゴリーごとの記事を全て取得
     *
     * @param int $category_id カテゴリーID
     */
    public function getPostByCategoryId($category_id)
    {
        $result = $this->where([
                            ['category_id', $category_id],
                            ['delete_flg', 0],
                        ])
                       ->get();
        return $result;
    }

    /**
     * ユーザーIDに紐づいた投稿リストを全て取得する
     *
     * @param int $user_id ユーザーID
     * @return Post
     */
    public function getAllPostsByUserId($user_id)
    {
        $result = $this->where([
                            ['user_id', $user_id],
                            ['delete_flg', 0],
                        ])
                       ->with('category')
                       ->orderBy('updated_at', 'DESC')
                       ->get();
        return $result;
    }

    /**
     * 下書き保存=>publish_flg=0
     * リクエストされたデータをpostsテーブルにinsertする
     *
     * @param int $user_id ログインユーザーID
     * @param array $request リクエストデータ
     * @return object $result App\Models\Post
     */
    public function insertPostToSaveDraft($user_id, $request)
    {
        $result = $this->create([
            'user_id'          => $user_id,
            'category_id'      => $request->category,
            'title'            => $request->title,
            'body'             => $request->body,
            'publish_flg'      => 0,
            'view_counter'     => 0,
            'favorite_counter' => 0,
            'delete_flg'       => 0,
        ]);
        return $result;
    }

    /**
     * 公開=>publish_flg=1
     * リクエストされたデータをpostsテーブルにinsertする
     *
     * @param int $user_id ログインユーザーID
     * @param array $request リクエストデータ
     * @return object $result App\Models\Post
     */
    public function insertPostToRelease($user_id, $request)
    {
        $result = $this->create([
            'user_id'          => $user_id,
            'category_id'      => $request->category,
            'title'            => $request->title,
            'body'             => $request->body,
            'publish_flg'      => 1,
            'view_counter'     => 0,
            'favorite_counter' => 0,
            'delete_flg'       => 0,
        ]);
        return $result;
    }

    /**
     * 予約公開=>publish_flg=2
     * リクエストされたデータをpostsテーブルにinsertする
     *
     * @param int $user_id ログインユーザーID
     * @param array $request リクエストデータ
     * @return object $result App\Models\Post
     */
    public function insertPostToReservationRelease($user_id, $request)
    {
        $result = $this->create([
            'user_id'          => $user_id,
            'category_id'      => $request->category,
            'title'            => $request->title,
            'body'             => $request->body,
            'publish_flg'      => 2,
            'view_counter'     => 0,
            'favorite_counter' => 0,
            'delete_flg'       => 0,
        ]);
        return $result;
    }

    /**
     * 投稿IDをもとにpostsテーブルから一意の投稿データを取得
     *
     * @param int $post_id 投稿ID
     * @return object $result App\Models\Post
     */
    public function feachPostDateByPostId($post_id)
    {
        $result = $this->find($post_id);
        return $result;
    }

    /**
     * 記事の更新処理
     * 下書き保存=>publish_flg=0
     * リクエストされたデータをもとにpostデータを更新する
     *
     * @param array $post 投稿データ
     * @return object $result App\Models\Post
     */
    public function updatePostToSaveDraft($request, $post)
    {
        $result = $post->fill([
            'category_id'      => $request->category,
            'title'            => $request->title,
            'body'             => $request->body,
            'publish_flg'      => 0,
        ]);

        $result->save();

        return $result;
    }

    /**
     * 記事の更新処理
     * 公開=>publish_flg=1
     * リクエストされたデータをもとにpostデータを更新する
     *
     * @param array $post 投稿データ
     * @return object $result App\Models\Post
     */
    public function updatePostToRelease($request, $post)
    {
        $result = $post->fill([
            'category_id'      => $request->category,
            'title'            => $request->title,
            'body'             => $request->body,
            'publish_flg'      => 1,
        ]);

        $result->save();

        return $result;
    }

    /**
     * 記事の更新処理
     * 公開予約=>publish_flg=0
     * リクエストされたデータをもとにpostデータを更新する
     *
     * @param array $post 投稿データ
     * @return object $result App\Models\Post
     */
    public function updatePostToReservationRelease($request, $post)
    {
        $result = $post->fill([
            'category_id'      => $request->category,
            'title'            => $request->title,
            'body'             => $request->body,
            'publish_flg'      => 2,
        ]);

        $result->save();

        return $result;
    }

    /**
     * ゴミ箱一覧の記事を取得
     *
     * @param int $user_id ユーザーID
     * @return object $result App\Models\Post
     */
    public function getTrashPostLists($user_id)
    {
        $result = $this->where([
                            ['user_id', $user_id],
                            ['delete_flg', 1],
                        ])
                        ->get();

        return $result;
    }

    /**
     * 記事の論理削除(ゴミ箱に移動)
     *
     * @param array $post 投稿データ
     * @return object $result App\Models\Post
     */
    public function moveTrashPostData($post)
    {
        $result = $post->fill([
            'publish_flg' => 0,
            'delete_flg' => 1
        ]);
        $result->save();
        return $result;
    }

    /**
     * 記事の復元
     *
     * @param array $post 投稿データ
     * @return object $result App\Models\Post
     */
    public function restorePostData($post)
    {
        $result = $post->fill([
            'publish_flg' => 0,
            'delete_flg' => 0
        ]);
        $result->save();
        return $result;
    }

    /**
     * 記事の削除
     *
     * @param array $post 投稿データ
     * @return object $result App\Models\Post
     */
    public function deletePostData($post)
    {
        $result = $post->delete();
        return $result;
    }

    /**
     * 下書き保存の記事一覧を取得
     *
     * @param int $user_id ログイン中のユーザーID
     * @return object $result App\Models\Post
     */
    public function getSaveDraftPosts($user_id)
    {
        $result = $this->where([
                            ['user_id', $user_id],
                            ['publish_flg', 0],
                            ['delete_flg', 0]
                        ])
                        ->orderBy('updated_at', 'DESC')
                        ->get();
        return $result;
    }
}

下書き保存一覧画面を作成する

下書き保存一覧の画面であるresources > views > user > list > saveDraft.blade.phpを新規作成しましょう。

{{-- src/resources/views/layouts/common.blade.php継承 --}}
@extends('layouts.common')

@include('user.parts.sidebar_user')
@section('content')
<div class="h-screen overflow-y-scroll">
    <div class="px-4 sm:px-4">
        <div class="flex justify-between">
            <div class="text-2xl font-bold pt-7">下書き保存一覧</div>
        </div>
        <div class="py-4">
            <div class="overflow-x-auto">
                <div class="inline-block min-w-full shadow rounded-lg overflow-hidden">
                    <table class="min-w-full leading-normal">
                        <thead>
                            <tr>
                                <th scope="col" class="px-5 py-3 bg-white  border-b border-gray-200 text-gray-800  text-center text-sm uppercase font-normal">
                                    タイトル
                                </th>
                                <th scope="col" class="px-5 py-3 bg-white  border-b border-gray-200 text-gray-800  text-center text-sm uppercase font-normal">
                                    投稿ID
                                </th>
                                <th scope="col" class="px-5 py-3 bg-white  border-b border-gray-200 text-gray-800  text-center text-sm uppercase font-normal">
                                    カテゴリー
                                </th>
                                <th scope="col" class="px-5 py-3 bg-white  border-b border-gray-200 text-gray-800  text-center text-sm uppercase font-normal">
                                    ステータス
                                </th>
                                <th scope="col" class="px-5 py-3 bg-white  border-b border-gray-200 text-gray-800  text-center text-sm uppercase font-normal">
                                    最終更新日時
                                </th>
                                <th scope="col" class="px-5 py-3 bg-white  border-b border-gray-200 text-gray-800  text-left text-sm uppercase font-normal">
                                    操作
                                </th>
                                <th scope="col" class="px-5 py-3 bg-white  border-b border-gray-200 text-gray-800  text-center text-sm uppercase font-normal">
                                    PV数
                                </th>
                                <th scope="col" class="px-5 py-3 bg-white  border-b border-gray-200 text-gray-800  text-center text-sm uppercase font-normal">
                                    お気に入り数
                                </th>
                            </tr>
                        </thead>
                        <tbody>
                            @foreach ($saveDrafts as $post)
                            <tr>
                                <td class="px-5 py-5 border-b border-gray-200 bg-white text-sm w-40">
                                    <a href="{{ route('post.show', ['post_id' => $post->id]) }}" class="hover:underline">
                                        <p class="text-left text-gray-900 whitespace-no-wrap">
                                            {{ $post->title }}
                                        </p>
                                    </a>
                                </td>
                                <td class="px-5 py-5 border-b border-gray-200 bg-white text-sm">
                                    <p class="text-center text-gray-900 whitespace-no-wrap">
                                        {{ $post->id }}
                                    </p>
                                </td>
                                <td class="px-5 py-5 border-b border-gray-200 bg-white text-sm text-center">
                                    <span class="relative inline-block px-3 py-1 font-semibold text-white leading-tight">
                                        <span aria-hidden="true" class="absolute inset-0 bg-green-500 rounded-full">
                                        </span>
                                        <span class="relative">
                                            @if (isset($post->category_id))
                                                {{ $post->category->category_name }}
                                            @else
                                                カテゴリーなし
                                            @endif
                                        </span>
                                    </span>
                                </td>
                                <td class="px-5 py-5 border-b border-gray-200 bg-white text-sm text-center">
                                    @if ($post->publish_flg === 0)
                                        <span class="relative inline-block px-3 py-1 font-semibold text-blue-900 leading-tight">
                                            <span aria-hidden="true" class="absolute inset-0 bg-blue-200 opacity-50 rounded-full">
                                            </span>
                                            <span class="relative">
                                                下書き保存
                                            </span>
                                        </span>
                                    @elseif ($post->publish_flg === 1)
                                        <span class="relative inline-block px-3 py-1 font-semibold text-green-900 leading-tight">
                                            <span aria-hidden="true" class="absolute inset-0 bg-green-200 opacity-50 rounded-full">
                                            </span>
                                            <span class="relative">公開済み</span>
                                        </span>
                                    @elseif ($post->publish_flg === 2)
                                        <span class="relative inline-block px-3 py-1 font-semibold text-amber-900 leading-tight">
                                            <span aria-hidden="true" class="absolute inset-0 bg-amber-200 opacity-50 rounded-full">
                                            </span>
                                            <span class="relative">予約公開</span>
                                        </span>
                                    @else
                                        <span class="relative inline-block px-3 py-1 font-semibold text-green-900 leading-tight">
                                            <span aria-hidden="true" class="absolute inset-0 bg-green-200 opacity-50 rounded-full">
                                            </span>
                                            <span class="relative">下書き保存</span>
                                        </span>
                                    @endif
                                </td>
                                <td class="px-5 py-5 border-b border-gray-200 bg-white text-sm">
                                    <p class="text-center text-gray-900 whitespace-no-wrap">
                                        {{ $post->updated_at }}
                                    </p>
                                </td>
                                <td class="px-5 py-5 mr-5 border-b border-gray-200 bg-white text-sm">
                                    <div class="flex">
                                        <a class="mr-3 text-blue-700 whitespace-no-wrap underline" href="{{ route('post.edit', ['post_id' => $post->id]) }}">
                                            Edit
                                        </a>
                                        <form action="{{ route('post.move.trash', ['post_id' => $post->id]) }}" method="POST" onSubmit="return is_move_trash()">
                                        @csrf
                                            <button type="submit" class="underline text-red-700 whitespace-no-wrap">
                                                Trash
                                            </button>
                                        </form>
                                    </div>
                                </td>
                                <td class="px-5 py-5 border-b border-gray-200 bg-white text-sm">
                                    <p class="text-center text-gray-900 whitespace-no-wrap">
                                        {{ $post->view_counter }}
                                    </p>
                                </td>
                                <td class="px-5 py-5 border-b border-gray-200 bg-white text-sm">
                                    <p class="text-center text-gray-900 whitespace-no-wrap">
                                        {{ $post->favorite_counter }}
                                    </p>
                                </td>
                            </tr>
                            @endforeach
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>
</div>
<script>
    function is_move_trash() {
        const moveTarashMessage = 'ゴミ箱に移動しますか?';
        const cancelMessage = 'キャンセルされました';
        // trashをクリックした時に確認ダイアログを表示。OKで実行、キャンセルで実行しない。
        if(window.confirm(moveTarashMessage)){
            return true;
        } else {
            window.alert(cancelMessage);
            return false;
        }
    }
</script>
@endsection

下書き保存一覧ができました。

公開中の記事一覧を実装する

流れとしては、下書き保存一覧と同じですが、

マイページのサイドバー公開中をクリック→公開中の記事一覧を表示です。
※マイページのサイドバーに公開中がないと思うので、ルーティングを追加した後に追加します。

公開一覧記事のルーティングを追加する

公開中一覧記事の画面なので、メソッドはGETでルーティングを追加します。

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\TopController;
use App\Http\Controllers\User\PostController;
use App\Http\Controllers\User\TrashController;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/dashboard', function () {
    return view('dashboard');
})->middleware(['auth'])->name('dashboard');

require __DIR__.'/auth.php';

// 総合トップ
Route::controller(TopController::class)->group(function() {
    // 総合トップ画面
    Route::get('/', 'top')
        ->name('top');
    // 総合トップ記事詳細画面
    Route::get('/article/{post_id}', 'articleShow')
        ->name('top.article.show');
    // 総合トップカテゴリーごとの記事一覧
    Route::get('/article/category/{category_id}', 'articleCategory')
        ->name('top.article.category');
});

// マイページ投稿関係
Route::controller(PostController::class)->group(function() {
    // マイページトップ・投稿
    Route::get('/user/{id}/index', 'index')
        ->name('user.index');

    // 投稿登録画面
    Route::get('/post/create', 'create')
        ->name('post.create');

    // 投稿登録処理
    Route::post('/post/store', 'store')
        ->name('post.store');

    // 投稿詳細
    Route::get('/post/show/{post_id}', 'show')
        ->name('post.show');

    // 記事編集
    Route::get('/post/edit/{post_id}', 'edit')
        ->name('post.edit');

    // 記事更新
    Route::post('/post/edit/{post_id}', 'update')
        ->name('post.update');

    // 下書き保存一覧
    Route::get('/post/saveDraft', 'saveDraft')
        ->name('post.saveDraft');

    // 公開中記事一覧
    Route::get('/post/release', 'release')
      ->name('post.release');
});

// ゴミ箱関係
Route::controller(TrashController::class)->group(function() {
    // 記事のゴミ箱
    Route::get('/post/trash', 'trashList')
        ->name('post.trash');

    // 記事論理削除(ゴミ箱に移動)
    Route::post('/post/trash/{post_id}', 'moveTrash')
        ->name('post.move.trash');

    // 記事の復元(ゴミ箱から投稿リストに戻す)
    Route::post('/post/restore/{post_id}', 'restore')
        ->name('post.restore');

    // 記事を完全に削除
    Route::post('/post/delete/{post_id}', 'delete')
        ->name('post.delete');
});

マイページのサイドバーにはまだ公開中はないと思うので、追加しましょう。

@section('sidebar')
<div class="h-screen hidden lg:block shadow-lg relative w-50">
    <div class="bg-amber-100 h-full">
        <div class="pt-3 pl-3">こんにちは、<br>{{ Auth::user()->name }}さん</div>
        <div class="flex items-center justify-start pt-6 ml-8">
            <p class="font-bold text-xl">
                Laratto
            </p>
        </div>
        <nav class="mt-6">
            <div>
                <a class="flex items-center px-4 py-2 mt-2 text-gray-600 transition-colors duration-200 transform hover:bg-sky-500 hover:text-white"
                href="{{ route('top') }}">
                    <span class="text-left">
                        <svg width="20" height="20" fill="currentColor" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg">
                            <path d="M1472 992v480q0 26-19 45t-45 19h-384v-384h-256v384h-384q-26 0-45-19t-19-45v-480q0-1 .5-3t.5-3l575-474 575 474q1 2 1 6zm223-69l-62 74q-8 9-21 11h-3q-13 0-21-7l-692-577-692 577q-12 8-24 7-13-2-21-11l-62-74q-8-10-7-23.5t11-21.5l719-599q32-26 76-26t76 26l244 204v-195q0-14 9-23t23-9h192q14 0 23 9t9 23v408l219 182q10 8 11 21.5t-7 23.5z">
                            </path>
                        </svg>
                    </span>
                    <span class="mx-2 text-md font-normal">
                        総合トップへ戻る
                    </span>
                </a>
            </div>
            <div>
                <a class="flex items-center px-4 py-2 mt-2 text-gray-600 transition-colors duration-200 transform hover:bg-sky-500 hover:text-white"
                href="#">
                    <span class="text-left">
                        <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
                            <path d="M5 4a2 2 0 012-2h6a2 2 0 012 2v14l-5-2.5L5 18V4z" />
                        </svg>
                    </span>
                    <span class="mx-2 text-md font-normal">
                        マイニュース
                    </span>
                </a>
            </div>
            <div>
                <a class="flex items-center px-4 py-2 mt-2 text-gray-600 transition-colors duration-200 transform hover:bg-sky-500 hover:text-white"
                href="{{ route('user.index', ['id' => Auth::user()->id]) }}">
                    <span class="text-left">
                        <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
                            <path fill-rule="evenodd" d="M18 13V5a2 2 0 00-2-2H4a2 2 0 00-2 2v8a2 2 0 002 2h3l3 3 3-3h3a2 2 0 002-2zM5 7a1 1 0 011-1h8a1 1 0 110 2H6a1 1 0 01-1-1zm1 3a1 1 0 100 2h3a1 1 0 100-2H6z" clip-rule="evenodd" />
                        </svg>
                    </span>
                    <span class="mx-2 text-md font-normal">
                        投稿
                    </span>
                </a>
            </div>
            <div>
                <a class="flex items-center px-4 py-2 mt-2 text-gray-600 transition-colors duration-200 transform hover:bg-sky-500 hover:text-white"
                href="{{ route('post.saveDraft') }}">
                    <span class="text-left">
                        <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
                            <path fill-rule="evenodd" d="M2 9.5A3.5 3.5 0 005.5 13H9v2.586l-1.293-1.293a1 1 0 00-1.414 1.414l3 3a1 1 0 001.414 0l3-3a1 1 0 00-1.414-1.414L11 15.586V13h2.5a4.5 4.5 0 10-.616-8.958 4.002 4.002 0 10-7.753 1.977A3.5 3.5 0 002 9.5zm9 3.5H9V8a1 1 0 012 0v5z" clip-rule="evenodd" />
                        </svg>
                    </span>
                    <span class="mx-2 text-md font-normal">
                        下書き保存
                    </span>
                </a>
            </div>
            <div>
                <a class="flex items-center px-4 py-2 mt-2 text-gray-600 transition-colors duration-200 transform hover:bg-sky-500 hover:text-white"
                href="{{ route('post.release') }}">
                    <span class="text-left">
                        <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
                            <path fill-rule="evenodd" d="M3 6a3 3 0 013-3h10a1 1 0 01.8 1.6L14.25 8l2.55 3.4A1 1 0 0116 13H6a1 1 0 00-1 1v3a1 1 0 11-2 0V6z" clip-rule="evenodd" />
                        </svg>
                    </span>
                    <span class="mx-2 text-md font-normal">
                        公開中
                    </span>
                </a>
            </div>
            <div>
                <a class="flex items-center px-4 py-2 mt-2 text-gray-600 transition-colors duration-200 transform hover:bg-sky-500 hover:text-white"
                href="#">
                    <span class="text-left">
                        <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
                            <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm1-12a1 1 0 10-2 0v4a1 1 0 00.293.707l2.828 2.829a1 1 0 101.415-1.415L11 9.586V6z" clip-rule="evenodd" />
                        </svg>
                    </span>
                    <span class="mx-2 text-md font-normal">
                        公開予約
                    </span>
                </a>
            </div>
            <div>
                <a class="flex items-center px-4 py-2 mt-2 text-gray-600 transition-colors duration-200 transform hover:bg-sky-500 hover:text-white"
                href="{{ route('post.trash') }}">
                    <span class="text-left">
                        <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
                            <path d="M4 3a2 2 0 100 4h12a2 2 0 100-4H4z" />
                            <path fill-rule="evenodd" d="M3 8h14v7a2 2 0 01-2 2H5a2 2 0 01-2-2V8zm5 3a1 1 0 011-1h2a1 1 0 110 2H9a1 1 0 01-1-1z" clip-rule="evenodd" />
                          </svg>
                    </span>
                    <span class="mx-2 text-md font-normal">
                        ゴミ箱
                    </span>
                </a>
            </div>
            <div>
                <a class="flex items-center px-4 py-2 mt-2 text-gray-600 transition-colors duration-200 transform hover:bg-sky-500 hover:text-white"
                href="#">
                    <span class="text-left">
                        <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
                            <path d="M2 11a1 1 0 011-1h2a1 1 0 011 1v5a1 1 0 01-1 1H3a1 1 0 01-1-1v-5zM8 7a1 1 0 011-1h2a1 1 0 011 1v9a1 1 0 01-1 1H9a1 1 0 01-1-1V7zM14 4a1 1 0 011-1h2a1 1 0 011 1v12a1 1 0 01-1 1h-2a1 1 0 01-1-1V4z" />
                        </svg>
                    </span>
                    <span class="mx-2 text-md font-normal">
                        統計データ
                    </span>
                </a>
            </div>
            <div>
                <a class="flex items-center px-4 py-2 mt-2 text-gray-600 transition-colors duration-200 transform hover:bg-sky-500 hover:text-white"
                href="#">
                    <span class="text-left">
                        <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
                            <path d="M11 3a1 1 0 100 2h2.586l-6.293 6.293a1 1 0 101.414 1.414L15 6.414V9a1 1 0 102 0V4a1 1 0 00-1-1h-5z" />
                            <path d="M5 5a2 2 0 00-2 2v8a2 2 0 002 2h8a2 2 0 002-2v-3a1 1 0 10-2 0v3H5V7h3a1 1 0 000-2H5z" />
                        </svg>
                    </span>
                    <form action="{{ route('logout') }}" method="POST">
                    @csrf
                        <button>
                            <span class="mx-2 text-md font-normal">
                                ログアウト
                            </span>
                        </button>
                    </form>
                </a>
            </div>
        </nav>
    </div>
</div>
@endsection

Postコントローラーに公開一覧のアクションを追加する

Postコントローラーにreleaseアクションを追加します。

<?php

namespace App\Http\Controllers\User;

use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;
use App\Models\Post;
use App\Models\Category;
use App\Http\Requests\PostRequest;

class PostController extends Controller
{
    private $post;
    private $category;

    public function __construct()
    {
        $this->post = new Post();
        $this->category = new Category();
    }

    /**
     * 投稿リスト
     *
     * @param int $id ユーザーID
     * @return Response src/resources/views/user/list/index.blade.phpを表示
     */
    public function index(int $id)
    {
        // ユーザーIDと一致する投稿データを取得
        $posts = $this->post->getAllPostsByUserId($id);
        return view('user.list.index', compact(
            'posts',
        ));
    }

    /**
     * 記事投稿画面
     *
     * @return Response src/resources/views/user/list/create.blade.phpを表示
     */
    public function create()
    {
        // カテゴリーデータを全件取得
        $categories = $this->category->getAllCategories();
        return view('user.list.create', compact(
            'categories',
        ));
    }

    /**
     * 記事投稿処理
     *
     * @param string $request リクエストデータ
     * @return Response src/resources/views/user/list/index.blade.phpを表示
     */
    public function store(PostRequest $request)
    {
        // ログインしているユーザー情報を取得
        $user = Auth::user();
        // ログインユーザー情報からユーザーIDを取得
        $user_id = $user->id;

        switch (true) {
            // 下書き保存クリック時の処理
            case $request->has('save_draft'):
                $this->post->insertPostToSaveDraft($user_id, $request);
                break;
            // 公開クリック時の処理
            case $request->has('release'):
                $this->post->insertPostToRelease($user_id, $request);
                break;
            // 予約公開クリック時の処理
            case $request->has('reservation_release'):
                $this->post->insertPostToReservationRelease($user_id, $request);
                break;
            // 上記以外の処理
            default:
                $this->post->insertPostToSaveDraft($user_id, $request);
                break;
        }

        return to_route('user.index', ['id' => $user_id]);
    }

    /**
     * 記事詳細
     *
     * @param int $post_id 投稿ID
     * @return Response src/resources/views/user/list/show.blade.phpを表示
     */
    public function show($post_id) {
        // リクエストされた投稿IDをもとにpostsテーブルから一意のデータを取得
        $showPostData = $this->post->feachPostDateByPostId($post_id);
        return view('user.list.show', compact(
            'showPostData',
        ));
    }

    /**
     * 記事編集
     *
     * @param int $post_id 投稿ID
     * @return Response src/resources/views/user/list/edit.blade.phpを表示
     */
    public function edit($post_id)
    {
        // カテゴリーデータを全件取得
        $categories = $this->category->getAllCategories();
        // 投稿IDをもとに特定の投稿データを取得
        $post = $this->post->feachPostDateByPostId($post_id);
        return view('user.list.edit', compact(
            'categories',
            'post',
        ));
    }

    /**
     * 記事の更新
     *
     * @param int $post_id 投稿ID
     * @return Response src/resources/views/user/list/index.blade.phpを表示
     */
    public function update(PostRequest $request, $post_id)
    {
        // ログインしているユーザー情報を取得
        $user = Auth::user();
        // ログインユーザー情報からユーザーIDを取得
        $user_id = $user->id;

        // 投稿IDをもとに特定の投稿データを取得
        $post = $this->post->feachPostDateByPostId($post_id);

        switch (true) {
            // 下書き保存クリック時の処理
            case $request->has('save_draft'):
                $this->post->updatePostToSaveDraft($request, $post);
                break;
            // 公開クリック時の処理
            case $request->has('release'):
                $this->post->updatePostToRelease($request, $post);
                break;
            // 予約公開クリック時の処理
            case $request->has('reservation_release'):
                $this->post->updatePostToReservationRelease($request, $post);
                break;
            // 上記以外の処理
            default:
                $this->post->updatePostToSaveDraft($request, $post);
                break;
        }

        return to_route('user.index', ['id' => $user_id]);
    }

    /**
     * 下書き保存一覧
     *
     * @return Response src/resources/views/user/list/saveDraft.blade.phpを表示
     */
    public function saveDraft()
    {
        // ログインしているユーザー情報を取得
        $user = Auth::user();
        // ログインユーザー情報からユーザーIDを取得
        $user_id = $user->id;
        // 下書き保存の記事一覧を取得
        $saveDrafts = $this->post->getSaveDraftPosts($user_id);
        return view('user.list.saveDraft', compact(
            'saveDrafts',
        ));
    }

    /**
     * 公開中記事一覧
     *
     * @return Response src/resources/views/user/list/release.blade.phpを表示
     */
    public function release()
    {
        // ログインしているユーザー情報を取得
        $user = Auth::user();
        // ログインユーザー情報からユーザーIDを取得
        $user_id = $user->id;
        // 公開中の記事一覧を取得
        $releases = $this->post->getReleasePosts($user_id);
        return view('user.list.release', compact(
            'releases',
        ));
    }
}

Postモデルに公開中一覧取得のロジックをかく

PostモデルにgetReleasePostsメソッドを追加します。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use App\Models\User;
use App\Models\Category;
use Illuminate\Support\Carbon;

/**
 * 投稿モデル
 */
class Post extends Model
{
    /**
     * モデルに関連付けるテーブル
     *
     * @var string
     */
    protected $table = 'posts';

    /**
     * 複数代入可能な属性
     *
     * @var array
     */
    protected $fillable = [
        'user_id',
        'category_id',
        'title',
        'body',
        'publish_flg',
        'view_counter',
        'favorite_counter',
        'delete_flg',
        'created_at',
        'updated_at'
    ];

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

    /**
     * Categoryモデルとリレーション
     */
    public function category()
    {
        return $this->belongsTo(Category::class);
    }

    /**
     * 投稿データを全て取得し、最新更新日時順にソート
     */
    public function getPostsSortByLatestUpdate()
    {
        $result = $this->where([
                            ['publish_flg', 1],
                            ['delete_flg', 0],
                        ])
                       ->orderBy('updated_at', 'DESC')
                       ->with('user')
                       ->with('category')
                       ->get();
        return $result;
    }

    /**
     * カテゴリーごとの記事を全て取得
     *
     * @param int $category_id カテゴリーID
     */
    public function getPostByCategoryId($category_id)
    {
        $result = $this->where([
                            ['category_id', $category_id],
                            ['delete_flg', 0],
                        ])
                       ->get();
        return $result;
    }

    /**
     * ユーザーIDに紐づいた投稿リストを全て取得する
     *
     * @param int $user_id ユーザーID
     * @return Post
     */
    public function getAllPostsByUserId($user_id)
    {
        $result = $this->where([
                            ['user_id', $user_id],
                            ['delete_flg', 0],
                        ])
                       ->with('category')
                       ->orderBy('updated_at', 'DESC')
                       ->get();
        return $result;
    }

    /**
     * 下書き保存=>publish_flg=0
     * リクエストされたデータをpostsテーブルにinsertする
     *
     * @param int $user_id ログインユーザーID
     * @param array $request リクエストデータ
     * @return object $result App\Models\Post
     */
    public function insertPostToSaveDraft($user_id, $request)
    {
        $result = $this->create([
            'user_id'          => $user_id,
            'category_id'      => $request->category,
            'title'            => $request->title,
            'body'             => $request->body,
            'publish_flg'      => 0,
            'view_counter'     => 0,
            'favorite_counter' => 0,
            'delete_flg'       => 0,
        ]);
        return $result;
    }

    /**
     * 公開=>publish_flg=1
     * リクエストされたデータをpostsテーブルにinsertする
     *
     * @param int $user_id ログインユーザーID
     * @param array $request リクエストデータ
     * @return object $result App\Models\Post
     */
    public function insertPostToRelease($user_id, $request)
    {
        $result = $this->create([
            'user_id'          => $user_id,
            'category_id'      => $request->category,
            'title'            => $request->title,
            'body'             => $request->body,
            'publish_flg'      => 1,
            'view_counter'     => 0,
            'favorite_counter' => 0,
            'delete_flg'       => 0,
        ]);
        return $result;
    }

    /**
     * 予約公開=>publish_flg=2
     * リクエストされたデータをpostsテーブルにinsertする
     *
     * @param int $user_id ログインユーザーID
     * @param array $request リクエストデータ
     * @return object $result App\Models\Post
     */
    public function insertPostToReservationRelease($user_id, $request)
    {
        $result = $this->create([
            'user_id'          => $user_id,
            'category_id'      => $request->category,
            'title'            => $request->title,
            'body'             => $request->body,
            'publish_flg'      => 2,
            'view_counter'     => 0,
            'favorite_counter' => 0,
            'delete_flg'       => 0,
        ]);
        return $result;
    }

    /**
     * 投稿IDをもとにpostsテーブルから一意の投稿データを取得
     *
     * @param int $post_id 投稿ID
     * @return object $result App\Models\Post
     */
    public function feachPostDateByPostId($post_id)
    {
        $result = $this->find($post_id);
        return $result;
    }

    /**
     * 記事の更新処理
     * 下書き保存=>publish_flg=0
     * リクエストされたデータをもとにpostデータを更新する
     *
     * @param array $post 投稿データ
     * @return object $result App\Models\Post
     */
    public function updatePostToSaveDraft($request, $post)
    {
        $result = $post->fill([
            'category_id'      => $request->category,
            'title'            => $request->title,
            'body'             => $request->body,
            'publish_flg'      => 0,
        ]);

        $result->save();

        return $result;
    }

    /**
     * 記事の更新処理
     * 公開=>publish_flg=1
     * リクエストされたデータをもとにpostデータを更新する
     *
     * @param array $post 投稿データ
     * @return object $result App\Models\Post
     */
    public function updatePostToRelease($request, $post)
    {
        $result = $post->fill([
            'category_id'      => $request->category,
            'title'            => $request->title,
            'body'             => $request->body,
            'publish_flg'      => 1,
        ]);

        $result->save();

        return $result;
    }

    /**
     * 記事の更新処理
     * 公開予約=>publish_flg=0
     * リクエストされたデータをもとにpostデータを更新する
     *
     * @param array $post 投稿データ
     * @return object $result App\Models\Post
     */
    public function updatePostToReservationRelease($request, $post)
    {
        $result = $post->fill([
            'category_id'      => $request->category,
            'title'            => $request->title,
            'body'             => $request->body,
            'publish_flg'      => 2,
        ]);

        $result->save();

        return $result;
    }

    /**
     * ゴミ箱一覧の記事を取得
     *
     * @param int $user_id ユーザーID
     * @return object $result App\Models\Post
     */
    public function getTrashPostLists($user_id)
    {
        $result = $this->where([
                            ['user_id', $user_id],
                            ['delete_flg', 1],
                        ])
                        ->get();

        return $result;
    }

    /**
     * 記事の論理削除(ゴミ箱に移動)
     *
     * @param array $post 投稿データ
     * @return object $result App\Models\Post
     */
    public function moveTrashPostData($post)
    {
        $result = $post->fill([
            'publish_flg' => 0,
            'delete_flg' => 1
        ]);
        $result->save();
        return $result;
    }

    /**
     * 記事の復元
     *
     * @param array $post 投稿データ
     * @return object $result App\Models\Post
     */
    public function restorePostData($post)
    {
        $result = $post->fill([
            'publish_flg' => 0,
            'delete_flg' => 0
        ]);
        $result->save();
        return $result;
    }

    /**
     * 記事の削除
     *
     * @param array $post 投稿データ
     * @return object $result App\Models\Post
     */
    public function deletePostData($post)
    {
        $result = $post->delete();
        return $result;
    }

    /**
     * 下書き保存の記事一覧を取得
     *
     * @param int $user_id ログイン中のユーザーID
     * @return object $result App\Models\Post
     */
    public function getSaveDraftPosts($user_id)
    {
        $result = $this->where([
                            ['user_id', $user_id],
                            ['publish_flg', 0],
                            ['delete_flg', 0]
                        ])
                        ->orderBy('updated_at', 'DESC')
                        ->get();
        return $result;
    }

    /**
     * 公開中の記事一覧を取得
     *
     * @param int $user_id ログイン中のユーザーID
     * @return object $result App\Models\Post
     */
    public function getReleasePosts($user_id)
    {
        $result = $this->where([
                            ['user_id', $user_id],
                            ['publish_flg', 1],
                            ['delete_flg', 0]
                        ])
                        ->orderBy('updated_at', 'DESC')
                        ->get();
        return $result;
    }
}

サイドバーの公開中をクリックした時の公開中記事一覧の画面を作成しましょう。

公開中記事一覧の画面を作成する

resources > views > user > list > release.blade.phpを新規で作ります。

{{-- src/resources/views/layouts/common.blade.php継承 --}}
@extends('layouts.common')

@include('user.parts.sidebar_user')
@section('content')
<div class="h-screen overflow-y-scroll">
    <div class="px-4 sm:px-4">
        <div class="flex justify-between">
            <div class="text-2xl font-bold pt-7">公開中一覧</div>
        </div>
        <div class="py-4">
            <div class="overflow-x-auto">
                <div class="inline-block min-w-full shadow rounded-lg overflow-hidden">
                    <table class="min-w-full leading-normal">
                        <thead>
                            <tr>
                                <th scope="col" class="px-5 py-3 bg-white  border-b border-gray-200 text-gray-800  text-center text-sm uppercase font-normal">
                                    タイトル
                                </th>
                                <th scope="col" class="px-5 py-3 bg-white  border-b border-gray-200 text-gray-800  text-center text-sm uppercase font-normal">
                                    投稿ID
                                </th>
                                <th scope="col" class="px-5 py-3 bg-white  border-b border-gray-200 text-gray-800  text-center text-sm uppercase font-normal">
                                    カテゴリー
                                </th>
                                <th scope="col" class="px-5 py-3 bg-white  border-b border-gray-200 text-gray-800  text-center text-sm uppercase font-normal">
                                    ステータス
                                </th>
                                <th scope="col" class="px-5 py-3 bg-white  border-b border-gray-200 text-gray-800  text-center text-sm uppercase font-normal">
                                    最終更新日時
                                </th>
                                <th scope="col" class="px-5 py-3 bg-white  border-b border-gray-200 text-gray-800  text-left text-sm uppercase font-normal">
                                    操作
                                </th>
                                <th scope="col" class="px-5 py-3 bg-white  border-b border-gray-200 text-gray-800  text-center text-sm uppercase font-normal">
                                    PV数
                                </th>
                                <th scope="col" class="px-5 py-3 bg-white  border-b border-gray-200 text-gray-800  text-center text-sm uppercase font-normal">
                                    お気に入り数
                                </th>
                            </tr>
                        </thead>
                        <tbody>
                            @foreach ($releases as $post)
                            <tr>
                                <td class="px-5 py-5 border-b border-gray-200 bg-white text-sm w-40">
                                    <a href="{{ route('post.show', ['post_id' => $post->id]) }}" class="hover:underline">
                                        <p class="text-left text-gray-900 whitespace-no-wrap">
                                            {{ $post->title }}
                                        </p>
                                    </a>
                                </td>
                                <td class="px-5 py-5 border-b border-gray-200 bg-white text-sm">
                                    <p class="text-center text-gray-900 whitespace-no-wrap">
                                        {{ $post->id }}
                                    </p>
                                </td>
                                <td class="px-5 py-5 border-b border-gray-200 bg-white text-sm text-center">
                                    <span class="relative inline-block px-3 py-1 font-semibold text-white leading-tight">
                                        <span aria-hidden="true" class="absolute inset-0 bg-green-500 rounded-full">
                                        </span>
                                        <span class="relative">
                                            @if (isset($post->category_id))
                                                {{ $post->category->category_name }}
                                            @else
                                                カテゴリーなし
                                            @endif
                                        </span>
                                    </span>
                                </td>
                                <td class="px-5 py-5 border-b border-gray-200 bg-white text-sm text-center">
                                    @if ($post->publish_flg === 0)
                                        <span class="relative inline-block px-3 py-1 font-semibold text-blue-900 leading-tight">
                                            <span aria-hidden="true" class="absolute inset-0 bg-blue-200 opacity-50 rounded-full">
                                            </span>
                                            <span class="relative">
                                                下書き保存
                                            </span>
                                        </span>
                                    @elseif ($post->publish_flg === 1)
                                        <span class="relative inline-block px-3 py-1 font-semibold text-green-900 leading-tight">
                                            <span aria-hidden="true" class="absolute inset-0 bg-green-200 opacity-50 rounded-full">
                                            </span>
                                            <span class="relative">公開済み</span>
                                        </span>
                                    @elseif ($post->publish_flg === 2)
                                        <span class="relative inline-block px-3 py-1 font-semibold text-amber-900 leading-tight">
                                            <span aria-hidden="true" class="absolute inset-0 bg-amber-200 opacity-50 rounded-full">
                                            </span>
                                            <span class="relative">予約公開</span>
                                        </span>
                                    @else
                                        <span class="relative inline-block px-3 py-1 font-semibold text-green-900 leading-tight">
                                            <span aria-hidden="true" class="absolute inset-0 bg-green-200 opacity-50 rounded-full">
                                            </span>
                                            <span class="relative">下書き保存</span>
                                        </span>
                                    @endif
                                </td>
                                <td class="px-5 py-5 border-b border-gray-200 bg-white text-sm">
                                    <p class="text-center text-gray-900 whitespace-no-wrap">
                                        {{ $post->updated_at }}
                                    </p>
                                </td>
                                <td class="px-5 py-5 mr-5 border-b border-gray-200 bg-white text-sm">
                                    <div class="flex">
                                        <a class="mr-3 text-blue-700 whitespace-no-wrap underline" href="{{ route('post.edit', ['post_id' => $post->id]) }}">
                                            Edit
                                        </a>
                                        <form action="{{ route('post.move.trash', ['post_id' => $post->id]) }}" method="POST" onSubmit="return is_move_trash()">
                                        @csrf
                                            <button type="submit" class="underline text-red-700 whitespace-no-wrap">
                                                Trash
                                            </button>
                                        </form>
                                    </div>
                                </td>
                                <td class="px-5 py-5 border-b border-gray-200 bg-white text-sm">
                                    <p class="text-center text-gray-900 whitespace-no-wrap">
                                        {{ $post->view_counter }}
                                    </p>
                                </td>
                                <td class="px-5 py-5 border-b border-gray-200 bg-white text-sm">
                                    <p class="text-center text-gray-900 whitespace-no-wrap">
                                        {{ $post->favorite_counter }}
                                    </p>
                                </td>
                            </tr>
                            @endforeach
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>
</div>
<script>
    function is_move_trash() {
        const moveTarashMessage = 'ゴミ箱に移動しますか?';
        const cancelMessage = 'キャンセルされました';
        // trashをクリックした時に確認ダイアログを表示。OKで実行、キャンセルで実行しない。
        if(window.confirm(moveTarashMessage)){
            return true;
        } else {
            window.alert(cancelMessage);
            return false;
        }
    }
</script>
@endsection

公開中の記事一覧も表示できました。

予約公開の記事一覧

下書き保存と公開中一覧ができたと思うので、予約公開も同じ要領でやっていきましょう。

予約公開一覧のルーティングを追加する

ルーティングを追加します。

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\TopController;
use App\Http\Controllers\User\PostController;
use App\Http\Controllers\User\TrashController;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/dashboard', function () {
    return view('dashboard');
})->middleware(['auth'])->name('dashboard');

require __DIR__.'/auth.php';

// 総合トップ
Route::controller(TopController::class)->group(function() {
    // 総合トップ画面
    Route::get('/', 'top')
        ->name('top');
    // 総合トップ記事詳細画面
    Route::get('/article/{post_id}', 'articleShow')
        ->name('top.article.show');
    // 総合トップカテゴリーごとの記事一覧
    Route::get('/article/category/{category_id}', 'articleCategory')
        ->name('top.article.category');
});

// マイページ投稿関係
Route::controller(PostController::class)->group(function() {
    // マイページトップ・投稿
    Route::get('/user/{id}/index', 'index')
        ->name('user.index');

    // 投稿登録画面
    Route::get('/post/create', 'create')
        ->name('post.create');

    // 投稿登録処理
    Route::post('/post/store', 'store')
        ->name('post.store');

    // 投稿詳細
    Route::get('/post/show/{post_id}', 'show')
        ->name('post.show');

    // 記事編集
    Route::get('/post/edit/{post_id}', 'edit')
        ->name('post.edit');

    // 記事更新
    Route::post('/post/edit/{post_id}', 'update')
        ->name('post.update');

    // 下書き保存一覧
    Route::get('/post/saveDraft', 'saveDraft')
        ->name('post.saveDraft');

    // 公開中記事一覧
    Route::get('/post/release', 'release')
        ->name('post.release');

    // 予約公開記事一覧
    Route::get('/post/reservationRelease', 'reservationRelease')
        ->name('post.reservationRelease');
});

// ゴミ箱関係
Route::controller(TrashController::class)->group(function() {
    // 記事のゴミ箱
    Route::get('/post/trash', 'trashList')
        ->name('post.trash');

    // 記事論理削除(ゴミ箱に移動)
    Route::post('/post/trash/{post_id}', 'moveTrash')
        ->name('post.move.trash');

    // 記事の復元(ゴミ箱から投稿リストに戻す)
    Route::post('/post/restore/{post_id}', 'restore')
        ->name('post.restore');

    // 記事を完全に削除
    Route::post('/post/delete/{post_id}', 'delete')
        ->name('post.delete');
});

サイドバーの予約公開をクリックしたときに、予約公開一覧に遷移するようにしましょう。

@section('sidebar')
<div class="h-screen hidden lg:block shadow-lg relative w-50">
    <div class="bg-amber-100 h-full">
        <div class="pt-3 pl-3">こんにちは、<br>{{ Auth::user()->name }}さん</div>
        <div class="flex items-center justify-start pt-6 ml-8">
            <p class="font-bold text-xl">
                Laratto
            </p>
        </div>
        <nav class="mt-6">
            <div>
                <a class="flex items-center px-4 py-2 mt-2 text-gray-600 transition-colors duration-200 transform hover:bg-sky-500 hover:text-white"
                href="{{ route('top') }}">
                    <span class="text-left">
                        <svg width="20" height="20" fill="currentColor" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg">
                            <path d="M1472 992v480q0 26-19 45t-45 19h-384v-384h-256v384h-384q-26 0-45-19t-19-45v-480q0-1 .5-3t.5-3l575-474 575 474q1 2 1 6zm223-69l-62 74q-8 9-21 11h-3q-13 0-21-7l-692-577-692 577q-12 8-24 7-13-2-21-11l-62-74q-8-10-7-23.5t11-21.5l719-599q32-26 76-26t76 26l244 204v-195q0-14 9-23t23-9h192q14 0 23 9t9 23v408l219 182q10 8 11 21.5t-7 23.5z">
                            </path>
                        </svg>
                    </span>
                    <span class="mx-2 text-md font-normal">
                        総合トップへ戻る
                    </span>
                </a>
            </div>
            <div>
                <a class="flex items-center px-4 py-2 mt-2 text-gray-600 transition-colors duration-200 transform hover:bg-sky-500 hover:text-white"
                href="#">
                    <span class="text-left">
                        <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
                            <path d="M5 4a2 2 0 012-2h6a2 2 0 012 2v14l-5-2.5L5 18V4z" />
                        </svg>
                    </span>
                    <span class="mx-2 text-md font-normal">
                        マイニュース
                    </span>
                </a>
            </div>
            <div>
                <a class="flex items-center px-4 py-2 mt-2 text-gray-600 transition-colors duration-200 transform hover:bg-sky-500 hover:text-white"
                href="{{ route('user.index', ['id' => Auth::user()->id]) }}">
                    <span class="text-left">
                        <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
                            <path fill-rule="evenodd" d="M18 13V5a2 2 0 00-2-2H4a2 2 0 00-2 2v8a2 2 0 002 2h3l3 3 3-3h3a2 2 0 002-2zM5 7a1 1 0 011-1h8a1 1 0 110 2H6a1 1 0 01-1-1zm1 3a1 1 0 100 2h3a1 1 0 100-2H6z" clip-rule="evenodd" />
                        </svg>
                    </span>
                    <span class="mx-2 text-md font-normal">
                        投稿
                    </span>
                </a>
            </div>
            <div>
                <a class="flex items-center px-4 py-2 mt-2 text-gray-600 transition-colors duration-200 transform hover:bg-sky-500 hover:text-white"
                href="{{ route('post.saveDraft') }}">
                    <span class="text-left">
                        <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
                            <path fill-rule="evenodd" d="M2 9.5A3.5 3.5 0 005.5 13H9v2.586l-1.293-1.293a1 1 0 00-1.414 1.414l3 3a1 1 0 001.414 0l3-3a1 1 0 00-1.414-1.414L11 15.586V13h2.5a4.5 4.5 0 10-.616-8.958 4.002 4.002 0 10-7.753 1.977A3.5 3.5 0 002 9.5zm9 3.5H9V8a1 1 0 012 0v5z" clip-rule="evenodd" />
                        </svg>
                    </span>
                    <span class="mx-2 text-md font-normal">
                        下書き保存
                    </span>
                </a>
            </div>
            <div>
                <a class="flex items-center px-4 py-2 mt-2 text-gray-600 transition-colors duration-200 transform hover:bg-sky-500 hover:text-white"
                href="{{ route('post.release') }}">
                    <span class="text-left">
                        <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
                            <path fill-rule="evenodd" d="M3 6a3 3 0 013-3h10a1 1 0 01.8 1.6L14.25 8l2.55 3.4A1 1 0 0116 13H6a1 1 0 00-1 1v3a1 1 0 11-2 0V6z" clip-rule="evenodd" />
                        </svg>
                    </span>
                    <span class="mx-2 text-md font-normal">
                        公開中
                    </span>
                </a>
            </div>
            <div>
                <a class="flex items-center px-4 py-2 mt-2 text-gray-600 transition-colors duration-200 transform hover:bg-sky-500 hover:text-white"
                href="{{ route('post.reservationRelease') }}">
                    <span class="text-left">
                        <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
                            <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zm1-12a1 1 0 10-2 0v4a1 1 0 00.293.707l2.828 2.829a1 1 0 101.415-1.415L11 9.586V6z" clip-rule="evenodd" />
                        </svg>
                    </span>
                    <span class="mx-2 text-md font-normal">
                        公開予約
                    </span>
                </a>
            </div>
            <div>
                <a class="flex items-center px-4 py-2 mt-2 text-gray-600 transition-colors duration-200 transform hover:bg-sky-500 hover:text-white"
                href="{{ route('post.trash') }}">
                    <span class="text-left">
                        <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
                            <path d="M4 3a2 2 0 100 4h12a2 2 0 100-4H4z" />
                            <path fill-rule="evenodd" d="M3 8h14v7a2 2 0 01-2 2H5a2 2 0 01-2-2V8zm5 3a1 1 0 011-1h2a1 1 0 110 2H9a1 1 0 01-1-1z" clip-rule="evenodd" />
                          </svg>
                    </span>
                    <span class="mx-2 text-md font-normal">
                        ゴミ箱
                    </span>
                </a>
            </div>
            <div>
                <a class="flex items-center px-4 py-2 mt-2 text-gray-600 transition-colors duration-200 transform hover:bg-sky-500 hover:text-white"
                href="#">
                    <span class="text-left">
                        <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
                            <path d="M2 11a1 1 0 011-1h2a1 1 0 011 1v5a1 1 0 01-1 1H3a1 1 0 01-1-1v-5zM8 7a1 1 0 011-1h2a1 1 0 011 1v9a1 1 0 01-1 1H9a1 1 0 01-1-1V7zM14 4a1 1 0 011-1h2a1 1 0 011 1v12a1 1 0 01-1 1h-2a1 1 0 01-1-1V4z" />
                        </svg>
                    </span>
                    <span class="mx-2 text-md font-normal">
                        統計データ
                    </span>
                </a>
            </div>
            <div>
                <a class="flex items-center px-4 py-2 mt-2 text-gray-600 transition-colors duration-200 transform hover:bg-sky-500 hover:text-white"
                href="#">
                    <span class="text-left">
                        <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
                            <path d="M11 3a1 1 0 100 2h2.586l-6.293 6.293a1 1 0 101.414 1.414L15 6.414V9a1 1 0 102 0V4a1 1 0 00-1-1h-5z" />
                            <path d="M5 5a2 2 0 00-2 2v8a2 2 0 002 2h8a2 2 0 002-2v-3a1 1 0 10-2 0v3H5V7h3a1 1 0 000-2H5z" />
                        </svg>
                    </span>
                    <form action="{{ route('logout') }}" method="POST">
                    @csrf
                        <button>
                            <span class="mx-2 text-md font-normal">
                                ログアウト
                            </span>
                        </button>
                    </form>
                </a>
            </div>
        </nav>
    </div>
</div>
@endsection

Postコントローラーに予約公開一覧のアクションを追加する

PostコントローラーにreservationReleaseアクションを追加します。

<?php

namespace App\Http\Controllers\User;

use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;
use App\Models\Post;
use App\Models\Category;
use App\Http\Requests\PostRequest;

class PostController extends Controller
{
    private $post;
    private $category;

    public function __construct()
    {
        $this->post = new Post();
        $this->category = new Category();
    }

    /**
     * 投稿リスト
     *
     * @param int $id ユーザーID
     * @return Response src/resources/views/user/list/index.blade.phpを表示
     */
    public function index(int $id)
    {
        // ユーザーIDと一致する投稿データを取得
        $posts = $this->post->getAllPostsByUserId($id);
        return view('user.list.index', compact(
            'posts',
        ));
    }

    /**
     * 記事投稿画面
     *
     * @return Response src/resources/views/user/list/create.blade.phpを表示
     */
    public function create()
    {
        // カテゴリーデータを全件取得
        $categories = $this->category->getAllCategories();
        return view('user.list.create', compact(
            'categories',
        ));
    }

    /**
     * 記事投稿処理
     *
     * @param string $request リクエストデータ
     * @return Response src/resources/views/user/list/index.blade.phpを表示
     */
    public function store(PostRequest $request)
    {
        // ログインしているユーザー情報を取得
        $user = Auth::user();
        // ログインユーザー情報からユーザーIDを取得
        $user_id = $user->id;

        switch (true) {
            // 下書き保存クリック時の処理
            case $request->has('save_draft'):
                $this->post->insertPostToSaveDraft($user_id, $request);
                break;
            // 公開クリック時の処理
            case $request->has('release'):
                $this->post->insertPostToRelease($user_id, $request);
                break;
            // 予約公開クリック時の処理
            case $request->has('reservation_release'):
                $this->post->insertPostToReservationRelease($user_id, $request);
                break;
            // 上記以外の処理
            default:
                $this->post->insertPostToSaveDraft($user_id, $request);
                break;
        }

        return to_route('user.index', ['id' => $user_id]);
    }

    /**
     * 記事詳細
     *
     * @param int $post_id 投稿ID
     * @return Response src/resources/views/user/list/show.blade.phpを表示
     */
    public function show($post_id) {
        // リクエストされた投稿IDをもとにpostsテーブルから一意のデータを取得
        $showPostData = $this->post->feachPostDateByPostId($post_id);
        return view('user.list.show', compact(
            'showPostData',
        ));
    }

    /**
     * 記事編集
     *
     * @param int $post_id 投稿ID
     * @return Response src/resources/views/user/list/edit.blade.phpを表示
     */
    public function edit($post_id)
    {
        // カテゴリーデータを全件取得
        $categories = $this->category->getAllCategories();
        // 投稿IDをもとに特定の投稿データを取得
        $post = $this->post->feachPostDateByPostId($post_id);
        return view('user.list.edit', compact(
            'categories',
            'post',
        ));
    }

    /**
     * 記事の更新
     *
     * @param int $post_id 投稿ID
     * @return Response src/resources/views/user/list/index.blade.phpを表示
     */
    public function update(PostRequest $request, $post_id)
    {
        // ログインしているユーザー情報を取得
        $user = Auth::user();
        // ログインユーザー情報からユーザーIDを取得
        $user_id = $user->id;

        // 投稿IDをもとに特定の投稿データを取得
        $post = $this->post->feachPostDateByPostId($post_id);

        switch (true) {
            // 下書き保存クリック時の処理
            case $request->has('save_draft'):
                $this->post->updatePostToSaveDraft($request, $post);
                break;
            // 公開クリック時の処理
            case $request->has('release'):
                $this->post->updatePostToRelease($request, $post);
                break;
            // 予約公開クリック時の処理
            case $request->has('reservation_release'):
                $this->post->updatePostToReservationRelease($request, $post);
                break;
            // 上記以外の処理
            default:
                $this->post->updatePostToSaveDraft($request, $post);
                break;
        }

        return to_route('user.index', ['id' => $user_id]);
    }

    /**
     * 下書き保存一覧
     *
     * @return Response src/resources/views/user/list/saveDraft.blade.phpを表示
     */
    public function saveDraft()
    {
        // ログインしているユーザー情報を取得
        $user = Auth::user();
        // ログインユーザー情報からユーザーIDを取得
        $user_id = $user->id;
        // 下書き保存の記事一覧を取得
        $saveDrafts = $this->post->getSaveDraftPosts($user_id);
        return view('user.list.saveDraft', compact(
            'saveDrafts',
        ));
    }

    /**
     * 公開中記事一覧
     *
     * @return Response src/resources/views/user/list/release.blade.phpを表示
     */
    public function release()
    {
        // ログインしているユーザー情報を取得
        $user = Auth::user();
        // ログインユーザー情報からユーザーIDを取得
        $user_id = $user->id;
        // 公開中の記事一覧を取得
        $releases = $this->post->getReleasePosts($user_id);
        return view('user.list.release', compact(
            'releases',
        ));
    }

    /**
     * 予約公開記事一覧
     *
     * @return Response src/resources/views/user/list/release.blade.phpを表示
     */
    public function reservationRelease()
    {
        // ログインしているユーザー情報を取得
        $user = Auth::user();
        // ログインユーザー情報からユーザーIDを取得
        $user_id = $user->id;
        // 予約公開の記事一覧を取得
        $reservationPosts = $this->post->getReservationReleasePosts($user_id);
        return view('user.list.reservationRelease', compact(
            'reservationPosts',
        ));
    }
}

postモデルに予約公開一覧を取得するロジックをかく

PostモデルにgetReservationReleasePostsメソッドを追加します。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use App\Models\User;
use App\Models\Category;
use Illuminate\Support\Carbon;

/**
 * 投稿モデル
 */
class Post extends Model
{
    /**
     * モデルに関連付けるテーブル
     *
     * @var string
     */
    protected $table = 'posts';

    /**
     * 複数代入可能な属性
     *
     * @var array
     */
    protected $fillable = [
        'user_id',
        'category_id',
        'title',
        'body',
        'publish_flg',
        'view_counter',
        'favorite_counter',
        'delete_flg',
        'created_at',
        'updated_at'
    ];

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

    /**
     * Categoryモデルとリレーション
     */
    public function category()
    {
        return $this->belongsTo(Category::class);
    }

    /**
     * 投稿データを全て取得し、最新更新日時順にソート
     */
    public function getPostsSortByLatestUpdate()
    {
        $result = $this->where([
                            ['publish_flg', 1],
                            ['delete_flg', 0],
                        ])
                       ->orderBy('updated_at', 'DESC')
                       ->with('user')
                       ->with('category')
                       ->get();
        return $result;
    }

    /**
     * カテゴリーごとの記事を全て取得
     *
     * @param int $category_id カテゴリーID
     */
    public function getPostByCategoryId($category_id)
    {
        $result = $this->where([
                            ['category_id', $category_id],
                            ['delete_flg', 0],
                        ])
                       ->get();
        return $result;
    }

    /**
     * ユーザーIDに紐づいた投稿リストを全て取得する
     *
     * @param int $user_id ユーザーID
     * @return Post
     */
    public function getAllPostsByUserId($user_id)
    {
        $result = $this->where([
                            ['user_id', $user_id],
                            ['delete_flg', 0],
                        ])
                       ->with('category')
                       ->orderBy('updated_at', 'DESC')
                       ->get();
        return $result;
    }

    /**
     * 下書き保存=>publish_flg=0
     * リクエストされたデータをpostsテーブルにinsertする
     *
     * @param int $user_id ログインユーザーID
     * @param array $request リクエストデータ
     * @return object $result App\Models\Post
     */
    public function insertPostToSaveDraft($user_id, $request)
    {
        $result = $this->create([
            'user_id'          => $user_id,
            'category_id'      => $request->category,
            'title'            => $request->title,
            'body'             => $request->body,
            'publish_flg'      => 0,
            'view_counter'     => 0,
            'favorite_counter' => 0,
            'delete_flg'       => 0,
        ]);
        return $result;
    }

    /**
     * 公開=>publish_flg=1
     * リクエストされたデータをpostsテーブルにinsertする
     *
     * @param int $user_id ログインユーザーID
     * @param array $request リクエストデータ
     * @return object $result App\Models\Post
     */
    public function insertPostToRelease($user_id, $request)
    {
        $result = $this->create([
            'user_id'          => $user_id,
            'category_id'      => $request->category,
            'title'            => $request->title,
            'body'             => $request->body,
            'publish_flg'      => 1,
            'view_counter'     => 0,
            'favorite_counter' => 0,
            'delete_flg'       => 0,
        ]);
        return $result;
    }

    /**
     * 予約公開=>publish_flg=2
     * リクエストされたデータをpostsテーブルにinsertする
     *
     * @param int $user_id ログインユーザーID
     * @param array $request リクエストデータ
     * @return object $result App\Models\Post
     */
    public function insertPostToReservationRelease($user_id, $request)
    {
        $result = $this->create([
            'user_id'          => $user_id,
            'category_id'      => $request->category,
            'title'            => $request->title,
            'body'             => $request->body,
            'publish_flg'      => 2,
            'view_counter'     => 0,
            'favorite_counter' => 0,
            'delete_flg'       => 0,
        ]);
        return $result;
    }

    /**
     * 投稿IDをもとにpostsテーブルから一意の投稿データを取得
     *
     * @param int $post_id 投稿ID
     * @return object $result App\Models\Post
     */
    public function feachPostDateByPostId($post_id)
    {
        $result = $this->find($post_id);
        return $result;
    }

    /**
     * 記事の更新処理
     * 下書き保存=>publish_flg=0
     * リクエストされたデータをもとにpostデータを更新する
     *
     * @param array $post 投稿データ
     * @return object $result App\Models\Post
     */
    public function updatePostToSaveDraft($request, $post)
    {
        $result = $post->fill([
            'category_id'      => $request->category,
            'title'            => $request->title,
            'body'             => $request->body,
            'publish_flg'      => 0,
        ]);

        $result->save();

        return $result;
    }

    /**
     * 記事の更新処理
     * 公開=>publish_flg=1
     * リクエストされたデータをもとにpostデータを更新する
     *
     * @param array $post 投稿データ
     * @return object $result App\Models\Post
     */
    public function updatePostToRelease($request, $post)
    {
        $result = $post->fill([
            'category_id'      => $request->category,
            'title'            => $request->title,
            'body'             => $request->body,
            'publish_flg'      => 1,
        ]);

        $result->save();

        return $result;
    }

    /**
     * 記事の更新処理
     * 公開予約=>publish_flg=0
     * リクエストされたデータをもとにpostデータを更新する
     *
     * @param array $post 投稿データ
     * @return object $result App\Models\Post
     */
    public function updatePostToReservationRelease($request, $post)
    {
        $result = $post->fill([
            'category_id'      => $request->category,
            'title'            => $request->title,
            'body'             => $request->body,
            'publish_flg'      => 2,
        ]);

        $result->save();

        return $result;
    }

    /**
     * ゴミ箱一覧の記事を取得
     *
     * @param int $user_id ユーザーID
     * @return object $result App\Models\Post
     */
    public function getTrashPostLists($user_id)
    {
        $result = $this->where([
                            ['user_id', $user_id],
                            ['delete_flg', 1],
                        ])
                        ->get();

        return $result;
    }

    /**
     * 記事の論理削除(ゴミ箱に移動)
     *
     * @param array $post 投稿データ
     * @return object $result App\Models\Post
     */
    public function moveTrashPostData($post)
    {
        $result = $post->fill([
            'publish_flg' => 0,
            'delete_flg' => 1
        ]);
        $result->save();
        return $result;
    }

    /**
     * 記事の復元
     *
     * @param array $post 投稿データ
     * @return object $result App\Models\Post
     */
    public function restorePostData($post)
    {
        $result = $post->fill([
            'publish_flg' => 0,
            'delete_flg' => 0
        ]);
        $result->save();
        return $result;
    }

    /**
     * 記事の削除
     *
     * @param array $post 投稿データ
     * @return object $result App\Models\Post
     */
    public function deletePostData($post)
    {
        $result = $post->delete();
        return $result;
    }

    /**
     * 下書き保存の記事一覧を取得
     *
     * @param int $user_id ログイン中のユーザーID
     * @return object $result App\Models\Post
     */
    public function getSaveDraftPosts($user_id)
    {
        $result = $this->where([
                            ['user_id', $user_id],
                            ['publish_flg', 0],
                            ['delete_flg', 0]
                        ])
                        ->orderBy('updated_at', 'DESC')
                        ->get();
        return $result;
    }

    /**
     * 公開中の記事一覧を取得
     *
     * @param int $user_id ログイン中のユーザーID
     * @return object $result App\Models\Post
     */
    public function getReleasePosts($user_id)
    {
        $result = $this->where([
                            ['user_id', $user_id],
                            ['publish_flg', 1],
                            ['delete_flg', 0]
                        ])
                        ->orderBy('updated_at', 'DESC')
                        ->get();
        return $result;
    }

    /**
     * 予約公開の記事一覧を取得
     *
     * @param int $user_id ログイン中のユーザーID
     * @return object $result App\Models\Post
     */
    public function getReservationReleasePosts($user_id)
    {
        $result = $this->where([
                            ['user_id', $user_id],
                            ['publish_flg', 2],
                            ['delete_flg', 0]
                        ])
                        ->orderBy('updated_at', 'DESC')
                        ->get();
        return $result;
    }
}

予約公開一覧画面を作成する

予約公開の記事一覧画面を作成するので、resources > views > user > list > reservationRelease.blade.phpを新規で作ります。

{{-- src/resources/views/layouts/common.blade.php継承 --}}
@extends('layouts.common')

@include('user.parts.sidebar_user')
@section('content')
<div class="h-screen overflow-y-scroll">
    <div class="px-4 sm:px-4">
        <div class="flex justify-between">
            <div class="text-2xl font-bold pt-7">予約公開一覧</div>
        </div>
        <div class="py-4">
            <div class="overflow-x-auto">
                <div class="inline-block min-w-full shadow rounded-lg overflow-hidden">
                    <table class="min-w-full leading-normal">
                        <thead>
                            <tr>
                                <th scope="col" class="px-5 py-3 bg-white  border-b border-gray-200 text-gray-800  text-center text-sm uppercase font-normal">
                                    タイトル
                                </th>
                                <th scope="col" class="px-5 py-3 bg-white  border-b border-gray-200 text-gray-800  text-center text-sm uppercase font-normal">
                                    投稿ID
                                </th>
                                <th scope="col" class="px-5 py-3 bg-white  border-b border-gray-200 text-gray-800  text-center text-sm uppercase font-normal">
                                    カテゴリー
                                </th>
                                <th scope="col" class="px-5 py-3 bg-white  border-b border-gray-200 text-gray-800  text-center text-sm uppercase font-normal">
                                    ステータス
                                </th>
                                <th scope="col" class="px-5 py-3 bg-white  border-b border-gray-200 text-gray-800  text-center text-sm uppercase font-normal">
                                    最終更新日時
                                </th>
                                <th scope="col" class="px-5 py-3 bg-white  border-b border-gray-200 text-gray-800  text-left text-sm uppercase font-normal">
                                    操作
                                </th>
                                <th scope="col" class="px-5 py-3 bg-white  border-b border-gray-200 text-gray-800  text-center text-sm uppercase font-normal">
                                    PV数
                                </th>
                                <th scope="col" class="px-5 py-3 bg-white  border-b border-gray-200 text-gray-800  text-center text-sm uppercase font-normal">
                                    お気に入り数
                                </th>
                            </tr>
                        </thead>
                        <tbody>
                            @foreach ($reservationPosts as $post)
                            <tr>
                                <td class="px-5 py-5 border-b border-gray-200 bg-white text-sm w-40">
                                    <a href="{{ route('post.show', ['post_id' => $post->id]) }}" class="hover:underline">
                                        <p class="text-left text-gray-900 whitespace-no-wrap">
                                            {{ $post->title }}
                                        </p>
                                    </a>
                                </td>
                                <td class="px-5 py-5 border-b border-gray-200 bg-white text-sm">
                                    <p class="text-center text-gray-900 whitespace-no-wrap">
                                        {{ $post->id }}
                                    </p>
                                </td>
                                <td class="px-5 py-5 border-b border-gray-200 bg-white text-sm text-center">
                                    <span class="relative inline-block px-3 py-1 font-semibold text-white leading-tight">
                                        <span aria-hidden="true" class="absolute inset-0 bg-green-500 rounded-full">
                                        </span>
                                        <span class="relative">
                                            @if (isset($post->category_id))
                                                {{ $post->category->category_name }}
                                            @else
                                                カテゴリーなし
                                            @endif
                                        </span>
                                    </span>
                                </td>
                                <td class="px-5 py-5 border-b border-gray-200 bg-white text-sm text-center">
                                    @if ($post->publish_flg === 0)
                                        <span class="relative inline-block px-3 py-1 font-semibold text-blue-900 leading-tight">
                                            <span aria-hidden="true" class="absolute inset-0 bg-blue-200 opacity-50 rounded-full">
                                            </span>
                                            <span class="relative">
                                                下書き保存
                                            </span>
                                        </span>
                                    @elseif ($post->publish_flg === 1)
                                        <span class="relative inline-block px-3 py-1 font-semibold text-green-900 leading-tight">
                                            <span aria-hidden="true" class="absolute inset-0 bg-green-200 opacity-50 rounded-full">
                                            </span>
                                            <span class="relative">公開済み</span>
                                        </span>
                                    @elseif ($post->publish_flg === 2)
                                        <span class="relative inline-block px-3 py-1 font-semibold text-amber-900 leading-tight">
                                            <span aria-hidden="true" class="absolute inset-0 bg-amber-200 opacity-50 rounded-full">
                                            </span>
                                            <span class="relative">予約公開</span>
                                        </span>
                                    @else
                                        <span class="relative inline-block px-3 py-1 font-semibold text-green-900 leading-tight">
                                            <span aria-hidden="true" class="absolute inset-0 bg-green-200 opacity-50 rounded-full">
                                            </span>
                                            <span class="relative">下書き保存</span>
                                        </span>
                                    @endif
                                </td>
                                <td class="px-5 py-5 border-b border-gray-200 bg-white text-sm">
                                    <p class="text-center text-gray-900 whitespace-no-wrap">
                                        {{ $post->updated_at }}
                                    </p>
                                </td>
                                <td class="px-5 py-5 mr-5 border-b border-gray-200 bg-white text-sm">
                                    <div class="flex">
                                        <a class="mr-3 text-blue-700 whitespace-no-wrap underline" href="{{ route('post.edit', ['post_id' => $post->id]) }}">
                                            Edit
                                        </a>
                                        <form action="{{ route('post.move.trash', ['post_id' => $post->id]) }}" method="POST" onSubmit="return is_move_trash()">
                                        @csrf
                                            <button type="submit" class="underline text-red-700 whitespace-no-wrap">
                                                Trash
                                            </button>
                                        </form>
                                    </div>
                                </td>
                                <td class="px-5 py-5 border-b border-gray-200 bg-white text-sm">
                                    <p class="text-center text-gray-900 whitespace-no-wrap">
                                        {{ $post->view_counter }}
                                    </p>
                                </td>
                                <td class="px-5 py-5 border-b border-gray-200 bg-white text-sm">
                                    <p class="text-center text-gray-900 whitespace-no-wrap">
                                        {{ $post->favorite_counter }}
                                    </p>
                                </td>
                            </tr>
                            @endforeach
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>
</div>
<script>
    function is_move_trash() {
        const moveTarashMessage = 'ゴミ箱に移動しますか?';
        const cancelMessage = 'キャンセルされました';
        // trashをクリックした時に確認ダイアログを表示。OKで実行、キャンセルで実行しない。
        if(window.confirm(moveTarashMessage)){
            return true;
        } else {
            window.alert(cancelMessage);
            return false;
        }
    }
</script>
@endsection

予約公開記事の一覧も表示ができました。

フラッシュメッセージ

ここからはフラッシュメッセージを実装していきたいと思います。

完成図

こんな感じで、フラッシュメッセージが出来上がります。

Laravelでフラッシュメッセージを実装するためには、いろいろなやり方がありますが、今回はセッションの知識を使います。

流れとしては、例えば記事の登録をする際に、

登録→セッションに登録が成功したメッセージを保存→記事一覧画面にリダイレクト→一覧画面にフラッシュメッセージを表示となります。

フラッシュメッセージは、セッションに一時補損すればいいので、結論、$request->session()->flash(‘…メッセージ内容’)とすればOKです。

過去記事:Laravelでフラッシュメッセージを表示する

Laravel公式:HTTPセッション_データの一時保存

投稿-フラッシュメッセージ

    /**
     * 記事投稿処理
     *
     * @param string $request リクエストデータ
     * @return Response src/resources/views/user/list/index.blade.phpを表示
     */
    public function store(PostRequest $request)
    {
        // ログインしているユーザー情報を取得
        $user = Auth::user();
        // ログインユーザー情報からユーザーIDを取得
        $user_id = $user->id;

        switch (true) {
            // 下書き保存クリック時の処理
            case $request->has('save_draft'):
                $this->post->insertPostToSaveDraft($user_id, $request);
                $request->session()->flash('saveDraft', '記事を下書きで保存しました。');
                break;
            // 公開クリック時の処理
            case $request->has('release'):
                $this->post->insertPostToRelease($user_id, $request);
                break;
            // 予約公開クリック時の処理
            case $request->has('reservation_release'):
                $this->post->insertPostToReservationRelease($user_id, $request);
                break;
            // 上記以外の処理
            default:
                $this->post->insertPostToSaveDraft($user_id, $request);
                break;
        }

        return to_route('user.index', ['id' => $user_id]);
    }

マイページの投稿一覧でフラッシュメッセージを表示するようにします。

画面で制御する場合は、session関数が使えます。

{{-- src/resources/views/layouts/common.blade.php継承 --}}
@extends('layouts.common')

@include('user.parts.sidebar_user')
@section('content')
{{-- 投稿:下書き保存 --}}
@if (session('saveDraft'))
    <div class="bg-blue-200 border-t border-b border-blue-500 text-blue-700 text-center px-4 py-3 font-bold">
        {{ session('saveDraft') }}
    </div>
@endif
<div class="h-screen overflow-y-scroll">
    <div class="px-4 sm:px-4">
        <div class="flex justify-between">
            <div class="text-2xl font-bold pt-7">投稿</div>
            <div class="pt-4">
                <a href="{{ route('post.create') }}">
                    <button class="bg-blue-500 text-white px-4 py-2 rounded-md text-1xl font-medium hover:bg-blue-700 transition duration-300">
                        新規追加
                    </button>
                </a>
            </div>
        </div>
        <div class="py-4">
            <div class="overflow-x-auto">
                <div class="inline-block min-w-full shadow rounded-lg overflow-hidden">
                    <table class="min-w-full leading-normal">
                        <thead>
                            <tr>
                                <th scope="col" class="px-5 py-3 bg-white  border-b border-gray-200 text-gray-800  text-center text-sm uppercase font-normal">
                                    タイトル
                                </th>
                                <th scope="col" class="px-5 py-3 bg-white  border-b border-gray-200 text-gray-800  text-center text-sm uppercase font-normal">
                                    投稿ID
                                </th>
                                <th scope="col" class="px-5 py-3 bg-white  border-b border-gray-200 text-gray-800  text-center text-sm uppercase font-normal">
                                    カテゴリー
                                </th>
                                <th scope="col" class="px-5 py-3 bg-white  border-b border-gray-200 text-gray-800  text-center text-sm uppercase font-normal">
                                    ステータス
                                </th>
                                <th scope="col" class="px-5 py-3 bg-white  border-b border-gray-200 text-gray-800  text-center text-sm uppercase font-normal">
                                    最終更新日時
                                </th>
                                <th scope="col" class="px-5 py-3 bg-white  border-b border-gray-200 text-gray-800  text-left text-sm uppercase font-normal">
                                    操作
                                </th>
                                <th scope="col" class="px-5 py-3 bg-white  border-b border-gray-200 text-gray-800  text-center text-sm uppercase font-normal">
                                    PV数
                                </th>
                                <th scope="col" class="px-5 py-3 bg-white  border-b border-gray-200 text-gray-800  text-center text-sm uppercase font-normal">
                                    お気に入り数
                                </th>
                            </tr>
                        </thead>
                        <tbody>
                            @foreach ($posts as $post)
                            <tr>
                                <td class="px-5 py-5 border-b border-gray-200 bg-white text-sm w-40">
                                    <a href="{{ route('post.show', ['post_id' => $post->id]) }}" class="hover:underline">
                                        <p class="text-left text-gray-900 whitespace-no-wrap">
                                            {{ $post->title }}
                                        </p>
                                    </a>
                                </td>
                                <td class="px-5 py-5 border-b border-gray-200 bg-white text-sm">
                                    <p class="text-center text-gray-900 whitespace-no-wrap">
                                        {{ $post->id }}
                                    </p>
                                </td>
                                <td class="px-5 py-5 border-b border-gray-200 bg-white text-sm text-center">
                                    <span class="relative inline-block px-3 py-1 font-semibold text-white leading-tight">
                                        <span aria-hidden="true" class="absolute inset-0 bg-green-500 rounded-full">
                                        </span>
                                        <span class="relative">
                                            @if (isset($post->category_id))
                                                {{ $post->category->category_name }}
                                            @else
                                                カテゴリーなし
                                            @endif
                                        </span>
                                    </span>
                                </td>
                                <td class="px-5 py-5 border-b border-gray-200 bg-white text-sm text-center">
                                    @if ($post->publish_flg === 0)
                                        <span class="relative inline-block px-3 py-1 font-semibold text-blue-900 leading-tight">
                                            <span aria-hidden="true" class="absolute inset-0 bg-blue-200 opacity-50 rounded-full">
                                            </span>
                                            <span class="relative">
                                                下書き保存
                                            </span>
                                        </span>
                                    @elseif ($post->publish_flg === 1)
                                        <span class="relative inline-block px-3 py-1 font-semibold text-green-900 leading-tight">
                                            <span aria-hidden="true" class="absolute inset-0 bg-green-200 opacity-50 rounded-full">
                                            </span>
                                            <span class="relative">公開済み</span>
                                        </span>
                                    @elseif ($post->publish_flg === 2)
                                        <span class="relative inline-block px-3 py-1 font-semibold text-amber-900 leading-tight">
                                            <span aria-hidden="true" class="absolute inset-0 bg-amber-200 opacity-50 rounded-full">
                                            </span>
                                            <span class="relative">予約公開</span>
                                        </span>
                                    @else
                                        <span class="relative inline-block px-3 py-1 font-semibold text-green-900 leading-tight">
                                            <span aria-hidden="true" class="absolute inset-0 bg-green-200 opacity-50 rounded-full">
                                            </span>
                                            <span class="relative">下書き保存</span>
                                        </span>
                                    @endif
                                </td>
                                <td class="px-5 py-5 border-b border-gray-200 bg-white text-sm">
                                    <p class="text-center text-gray-900 whitespace-no-wrap">
                                        {{ $post->updated_at }}
                                    </p>
                                </td>
                                <td class="px-5 py-5 mr-5 border-b border-gray-200 bg-white text-sm">
                                    <div class="flex">
                                        <a class="mr-3 text-blue-700 whitespace-no-wrap underline" href="{{ route('post.edit', ['post_id' => $post->id]) }}">
                                            Edit
                                        </a>
                                        <form action="{{ route('post.move.trash', ['post_id' => $post->id]) }}" method="POST" onSubmit="return is_move_trash()">
                                        @csrf
                                            <button type="submit" class="underline text-red-700 whitespace-no-wrap">
                                                Trash
                                            </button>
                                        </form>
                                    </div>
                                </td>
                                <td class="px-5 py-5 border-b border-gray-200 bg-white text-sm">
                                    <p class="text-center text-gray-900 whitespace-no-wrap">
                                        {{ $post->view_counter }}
                                    </p>
                                </td>
                                <td class="px-5 py-5 border-b border-gray-200 bg-white text-sm">
                                    <p class="text-center text-gray-900 whitespace-no-wrap">
                                        {{ $post->favorite_counter }}
                                    </p>
                                </td>
                            </tr>
                            @endforeach
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>
</div>
<script>
    function is_move_trash() {
        const moveTarashMessage = 'ゴミ箱に移動しますか?';
        const cancelMessage = 'キャンセルされました';
        // trashをクリックした時に確認ダイアログを表示。OKで実行、キャンセルで実行しない。
        if(window.confirm(moveTarashMessage)){
            return true;
        } else {
            window.alert(cancelMessage);
            return false;
        }
    }
</script>
@endsection

これで、記事を投稿する(下書き保存)→投稿一覧にリダイレクト→フラッシュメッセージが以下のように表示の流れができました。

フラッシュメッセージなので、リロードしたり他のページに移動して再度投稿一覧に戻ってきたらメッセージは消えます。

同様な手順で、他に必要なフラッシュメッセージを実装していきます。現時点で必要なのは以下です。

  • 記事の投稿:下書き保存、公開、公開予約
  • 記事の更新:下書き保存、公開、公開予約
  • ゴミ箱:ゴミ箱に移動、記事の復元、記事の削除

合計で同じような記述が9個も必要なので、画面には別のファイルにフラッシュメッセージのコンポーネントを作成し、そのコンポーネントを呼び出すように整理します。

    /**
     * 記事投稿処理
     *
     * @param string $request リクエストデータ
     * @return Response src/resources/views/user/list/index.blade.phpを表示
     */
    public function store(PostRequest $request)
    {
        // ログインしているユーザー情報を取得
        $user = Auth::user();
        // ログインユーザー情報からユーザーIDを取得
        $user_id = $user->id;

        switch (true) {
            // 下書き保存クリック時の処理
            case $request->has('save_draft'):
                $this->post->insertPostToSaveDraft($user_id, $request);
                $request->session()->flash('saveDraft', '記事を下書きで保存しました。');
                break;
            // 公開クリック時の処理
            case $request->has('release'):
                $this->post->insertPostToRelease($user_id, $request);
                $request->session()->flash('release', '記事を公開しました。');
                break;
            // 予約公開クリック時の処理
            case $request->has('reservation_release'):
                $this->post->insertPostToReservationRelease($user_id, $request);
                $request->session()->flash('reservationRelease', '記事を予約公開しました。');
                break;
            // 上記以外の処理
            default:
                $this->post->insertPostToSaveDraft($user_id, $request);
                $request->session()->flash('saveDraft', '記事を下書きで保存しました。');
                break;
        }

        return to_route('user.index', ['id' => $user_id]);
    }

resources > views > components > flash-message.blade.phpを新規で作成し、そこにフラッシュメッセージを書いていきましょう。

{{-- 投稿:下書き保存 --}}
@if (session('saveDraft'))
    <div class="bg-blue-200 border-t border-b border-blue-500 text-blue-700 text-center px-4 py-3 font-bold">
        {{ session('saveDraft') }}
    </div>
{{-- 投稿:公開 --}}
@elseif (session('release'))
    <div class="bg-green-200 border-t border-b border-green-500 text-green-700 text-center px-4 py-3 font-bold">
        {{ session('release') }}
    </div>
{{-- 投稿:公開予約 --}}
@elseif (session('reservationRelease'))
    <div class="bg-amber-200 border-t border-b border-amber-500 text-amber-700 text-center px-4 py-3 font-bold">
        {{ session('reservationRelease') }}
    </div>
@endif

あとは、上記のファイルを@componentを使って呼び出すだけです。

過去記事:Laravelでレイアウトを再利用する方法

また、@component以外にもLaravel8以降ではコンポーネントとして、x-slotなども書き方としてあります。

Laravel公式:Bladeテンプレート

{{-- src/resources/views/layouts/common.blade.php継承 --}}
@extends('layouts.common')

@include('user.parts.sidebar_user')
@section('content')
@component('components.flash-message')
@endcomponent
<div class="h-screen overflow-y-scroll">
    <div class="px-4 sm:px-4">
        <div class="flex justify-between">
            <div class="text-2xl font-bold pt-7">投稿</div>
            <div class="pt-4">
                <a href="{{ route('post.create') }}">
                    <button class="bg-blue-500 text-white px-4 py-2 rounded-md text-1xl font-medium hover:bg-blue-700 transition duration-300">
                        新規追加
                    </button>
                </a>
            </div>
        </div>
...省略

更新-フラッシュメッセージ

    /**
     * 記事の更新
     *
     * @param int $post_id 投稿ID
     * @return Response src/resources/views/user/list/index.blade.phpを表示
     */
    public function update(PostRequest $request, $post_id)
    {
        // ログインしているユーザー情報を取得
        $user = Auth::user();
        // ログインユーザー情報からユーザーIDを取得
        $user_id = $user->id;

        // 投稿IDをもとに特定の投稿データを取得
        $post = $this->post->feachPostDateByPostId($post_id);

        switch (true) {
            // 下書き保存クリック時の処理
            case $request->has('save_draft'):
                $this->post->updatePostToSaveDraft($request, $post);
                $request->session()->flash('updateSaveDraft', '記事を下書き保存で更新しました。');
                break;
            // 公開クリック時の処理
            case $request->has('release'):
                $this->post->updatePostToRelease($request, $post);
                $request->session()->flash('updateRelease', '記事を更新し公開しました。');
                break;
            // 予約公開クリック時の処理
            case $request->has('reservation_release'):
                $this->post->updatePostToReservationRelease($request, $post);
                $request->session()->flash('updateReservationRelease', '記事を予約公開で更新しました。');
                break;
            // 上記以外の処理
            default:
                $this->post->updatePostToSaveDraft($request, $post);
                $request->session()->flash('updateSaveDraft', '記事を下書きで保存しました。');
                break;
        }

        return to_route('user.index', ['id' => $user_id]);
    }

コンポーネントのflash-message.blade.phpに更新した際のフラッシュメッセージを追加します。

{{-- 投稿:下書き保存 --}}
@if (session('saveDraft'))
    <div class="bg-blue-200 border-t border-b border-blue-500 text-blue-700 text-center px-4 py-3 font-bold">
        {{ session('saveDraft') }}
    </div>
{{-- 投稿:公開 --}}
@elseif (session('release'))
    <div class="bg-green-200 border-t border-b border-green-500 text-green-700 text-center px-4 py-3 font-bold">
        {{ session('release') }}
    </div>
{{-- 投稿:公開予約 --}}
@elseif (session('reservationRelease'))
    <div class="bg-amber-200 border-t border-b border-amber-500 text-amber-700 text-center px-4 py-3 font-bold">
        {{ session('reservationRelease') }}
    </div>
@endif
{{-- 更新:下書き保存 --}}
@if (session('updateSaveDraft'))
    <div class="bg-blue-200 border-t border-b border-blue-500 text-blue-700 text-center px-4 py-3 font-bold">
        {{ session('updateSaveDraft') }}
    </div>
{{-- 更新:公開 --}}
@elseif (session('updateRelease'))
    <div class="bg-green-200 border-t border-b border-green-500 text-green-700 text-center px-4 py-3 font-bold">
        {{ session('updateRelease') }}
    </div>
{{-- 更新:公開予約 --}}
@elseif (session('updateReservationRelease'))
    <div class="bg-amber-200 border-t border-b border-amber-500 text-amber-700 text-center px-4 py-3 font-bold">
        {{ session('updateReservationRelease') }}
    </div>
@endif

ゴミ箱-フラッシュメッセージ

ゴミ箱の場合は、Postコントローラーのstoreやupdateアクションとは違い、$requestを引数に取っていないので使えません。なので、$requestを使わずにwithを使います。

<?php

namespace App\Http\Controllers\User;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Models\Post;
use App\Models\Category;

class TrashController extends Controller
{
    private $post;
    private $category;

    public function __construct()
    {
        $this->post = new Post();
        $this->category = new Category();
    }

    /**
     * ゴミ箱一覧
     *
     * @return Response src/resources/views/user/list/trash.blade.phpを表示
     */
    public function trashList()
    {
        // ログインしているユーザー情報を取得
        $user = Auth::user();
        // ログインユーザー情報からユーザーIDを取得
        $user_id = $user->id;

        // ユーザーIDをもとに、論理削除されているdelete_flg=1のデータを取得
        $trash_posts = $this->post->getTrashPostLists($user_id);
        return view('user.list.trash', compact(
            'user_id',
            'trash_posts',
        ));
    }

    /**
     * 記事の論理削除(ゴミ箱に移動)
     *
     * @param int $post_id 投稿ID
     */
    public function moveTrash($post_id)
    {
        // ログインしているユーザー情報を取得
        $user = Auth::user();
        // ログインユーザー情報からユーザーIDを取得
        $user_id = $user->id;

        // 投稿IDをもとに特定の投稿データを取得
        $post = $this->post->feachPostDateByPostId($post_id);

        // 記事を論理削除(ゴミ箱に移動)
        $trashPost = $this->post->moveTrashPostData($post);

        // マイページ投稿リストにリダイレクト
        return to_route('user.index', ['id' => $user_id])->with('moveTrash', '記事をゴミ箱に移動しました。');
    }

    /**
     * 記事の復元
     *
     * @param int $post_id 投稿ID
     */
    public function restore($post_id)
    {
        // ログインしているユーザー情報を取得
        $user = Auth::user();
        // ログインユーザー情報からユーザーIDを取得
        $user_id = $user->id;

        // ユーザーIDをもとに、論理削除されているdelete_flg=1のデータを取得
        $trash_posts = $this->post->getTrashPostLists($user_id);

        // 投稿IDをもとに特定の投稿データを取得
        $post = $this->post->feachPostDateByPostId($post_id);

        // 記事の復元
        $restorePost = $this->post->restorePostData($post);

        // ゴミ箱にリダイレクト
        return to_route('post.trash', compact(
            'user_id',
            'trash_posts',
        ))
        ->with('restore', '記事を復元しました。');
    }

    /**
     * 記事をゴミ箱から削除(物理削除なので、完全にデータを削除する)
     *
     * @param int $post_id 投稿ID
     */
    public function delete($post_id)
    {
        // ログインしているユーザー情報を取得
        $user = Auth::user();
        // ログインユーザー情報からユーザーIDを取得
        $user_id = $user->id;

        // ユーザーIDをもとに、論理削除されているdelete_flg=1のデータを取得
        $trash_posts = $this->post->getTrashPostLists($user_id);

        // 投稿IDをもとに特定の投稿データを取得
        $post = $this->post->feachPostDateByPostId($post_id);

        // 記事を物理削除(ゴミ箱からも削除)
        $deletePost = $this->post->deletePostData($post);
        // ゴミ箱にリダイレクト
        return to_route('post.trash', compact(
            'user_id',
            'trash_posts',
        ))
        ->with('delete', '記事を完全に削除しました。');
    }
}

ゴミ箱画面でも、投稿一覧のようにフラッシュメッセージのコンポーネントを呼び出します。

{{-- src/resources/views/layouts/common.blade.php継承 --}}
@extends('layouts.common')

@include('user.parts.sidebar_user')
@section('content')
@component('components.flash-message')
@endcomponent
<div class="h-screen overflow-y-scroll">
    <div class="px-4 sm:px-4">
        <div class="flex justify-between">
            <div class="text-2xl font-bold pt-7">ゴミ箱</div>
        </div>

コンポーネントにフラッシュメッセージを追加します。

{{-- 投稿:下書き保存 --}}
@if (session('saveDraft'))
    <div class="bg-blue-200 border-t border-b border-blue-500 text-blue-700 text-center px-4 py-3 font-bold">
        {{ session('saveDraft') }}
    </div>
{{-- 投稿:公開 --}}
@elseif (session('release'))
    <div class="bg-green-200 border-t border-b border-green-500 text-green-700 text-center px-4 py-3 font-bold">
        {{ session('release') }}
    </div>
{{-- 投稿:公開予約 --}}
@elseif (session('reservationRelease'))
    <div class="bg-amber-200 border-t border-b border-amber-500 text-amber-700 text-center px-4 py-3 font-bold">
        {{ session('reservationRelease') }}
    </div>
@endif
{{-- 更新:下書き保存 --}}
@if (session('updateSaveDraft'))
    <div class="bg-blue-200 border-t border-b border-blue-500 text-blue-700 text-center px-4 py-3 font-bold">
        {{ session('updateSaveDraft') }}
    </div>
{{-- 更新:公開 --}}
@elseif (session('updateRelease'))
    <div class="bg-green-200 border-t border-b border-green-500 text-green-700 text-center px-4 py-3 font-bold">
        {{ session('updateRelease') }}
    </div>
{{-- 更新:公開予約 --}}
@elseif (session('updateReservationRelease'))
    <div class="bg-amber-200 border-t border-b border-amber-500 text-amber-700 text-center px-4 py-3 font-bold">
        {{ session('updateReservationRelease') }}
    </div>
@endif
{{-- ゴミ箱:ゴミ箱に移動 --}}
@if (session('moveTrash'))
    <div class="bg-violet-200 border-t border-b border-violet-500 text-violet-700 text-center px-4 py-3 font-bold">
        {{ session('moveTrash') }}
    </div>
@endif
{{-- ゴミ箱:記事を復元 --}}
@if (session('restore'))
    <div class="bg-sky-200 border-t border-b border-sky-500 text-sky-700 text-center px-4 py-3 font-bold">
        {{ session('restore') }}
    </div>
{{-- ゴミ箱:記事を削除 --}}
@elseif (session('delete'))
    <div class="bg-red-200 border-t border-b border-red-500 text-red-700 text-center px-4 py-3 font-bold">
        {{ session('delete') }}
    </div>
@endif

これで割とアプリっぽくなってきたんじゃねぇか!!??

というわけで、次回は予約公開機能をいくつかの記事に分けてお送りいたします。

>>>予約公開機能①に進む

>>ココナラと似てるおすすめの副業サイトを確認する

>>リモートワークもあるおすすめの転職サイトを確認する

休日で空いた時間の暇つぶしを探せるアプリを公開しています。

スキルを売り買いするならココナラ

コメント

コメントする

CAPTCHA


Contents
閉じる