0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Webアプリ開発 記事の新規登録編

Last updated at Posted at 2024-05-09

初めに

webアプリ開発ができたので、どんな感じで作成したのかをまとめたいと思います。
今回はマイページ編集についてです。

開発環境

macOS Sonoma 14.4.1
CentoOS Stream X_86_64
Apache/2.4.57
PHP 8.3.6
mysql Ver 8.0.36
phpMyAdmin 5.2.1
composer version 2.7.2
Laravel Installer 5.7.1
Laravel Framework 11.0.5

ソースコード

考えたこと

記事の新規登録

実装事例

author.png

権限があるユーザーには投稿一覧ボタンが出てきます。
押すと

dashboard.png

記事一覧が表示されます

dashboardDropdown.png

ダッシュボードを押すと「新しい記事を作る」ボタンが出てきます。

createArticle.png

新規登録画面でタイトル、スラッグ、サムネイル、要約、内容、カテゴリーを指定すると記事が新しくできます

ビュー

create.blade.php
<x-layout>
    <x-setting heading="新規投稿">
        <form method="POST" action="/admin/posts" enctype="multipart/form-data">
            @csrf

            <div class="py-2">
                <x-form.label name="タイトル"/>  
                    <input class="border border-gray-200 p-2 w-full rounded"
                        name="title"
                        id="title"
                    >
                <x-form.error name="title"/>
            </div>      
            <div class="py-2">
                <x-form.label name="スラッグ"/>  
                    <input class="border border-gray-200 p-2 w-full rounded"
                        name="slug"
                        id="slug"
                    >
                <x-form.error name="slug"/>
            </div>
            <div class="py-2">
                <x-form.label name="サムネイル"/>  
                    <input class="border border-gray-200 p-2 w-full rounded"
                        name="thumbnail"
                        id="thumbnail"
                        type="file"
                    >
                <x-form.error name="thumbnail"/>
            </div>
            <div class="py-2">
                <x-form.label name="要約"/>  
                    <textarea class="border border-gray-200 p-2 w-full rounded"
                        name="excerpt"
                        id="excerpt"
                    ></textarea>
                <x-form.error name="excerpt"/>
            </div>
            <div class="py-2">
                <x-form.label name="内容"/>  
                    <textarea class="border border-gray-200 p-2 w-full rounded"
                        name="body"
                        id="body"
                    ></textarea>
                <x-form.error name="body"/>
            </div>

            <x-form.field>
                <x-form.label name="カテゴリー"/>

                <select name="category_id" id="category_id" required>
                    @foreach (\App\Models\Category::all() as $category)
                        <option
                            value="{{ $category->id }}"
                            {{ old('category_id') == $category->id ? 'selected' : '' }}
                        >{{ ucwords($category->name) }}</option>
                    @endforeach
                </select>

                <x-form.error name="category"/>
            </x-form.field>

            <x-form.button>投稿</x-form.button>
        </form>
    </x-setting>
</x-layout>

記事の新規登録画面はフォームのラベルとエラーをコンポーネント化して左上のドロップダウンボタンもコンポーネントしました

コントローラ

AdminPostController.php
<?php

namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;


class AdminPostController extends Controller
{
    public function index()
    {
        return view('admin.posts.index', [
            'posts' => Post::paginate(7)
        ]);
    }

    public function create()
    {
        return view('admin.posts.create');
    }

    
    public function store()
    {
        Post::create(array_merge($this->validatePost(), [
            'user_id' => request()->user()->id,
            'thumbnail' => request()->file('thumbnail')->store('thumbnails') 
        ]));

        return redirect('/')->with('success', '記事を作成しました。');
    }

    protected function validatePost(?Post $post = null): array
    {
        $post ??= new Post();

        return request()->validate([
            'title' => 'required|max:20',
            'thumbnail' => $post->exists ? ['image'] : ['image'],
            'slug' => ['required', Rule::unique('posts', 'slug')->ignore($post), 'alpha_dash' , 'lowercase', 'max:10'],
            'excerpt' => 'required|max:40',
            'body' => 'required|max:500',
            'category_id' => ['required', Rule::exists('categories', 'id')]
        ]);

    }
}

indexメソッドは投稿記事一覧画面の表示に使います。7記事ごとにページネーションされます

createメソッドは新規登録画面の表示をしています。

storeメソッドではPostモデルでカラムの登録をします。
array_mergeメソッドでvalidatePostメソッドのバリデーションと連結させています

ルート

web.php
    Route::middleware('can:admin')->group(function () {
    Route::resource('admin/posts', AdminPostController::class)->except('show','destroy');
});

記事のcrudの処理のルートが共通化できそうだったのでグループ化しておきました。
showはホーム画面で作っているので除きました。
destroyはajax処理で実装したかったので別で作成しました。

レスポンシブ対応

使われるスマホがiPhone8以上の画面サイズなのでiPhone8に対応させました。
res_create_article.gif

改善していきたいこと

ビューで書いたcreate.blade.phpのactionのルートをベタ書きしているのでweb.phpのルートに置き換えられるのなら置き換えたいと思います。
カテゴリーを登録する画面がないので、データベースに直接登録するしか方法がありません。
記事を登録する際にカテゴリーも一緒に登録できるように変更していきたいと思います。

最後に

記事の新規登録画面ではあまり改善点が発見できなかったので、他の機能の修正や新規機能の追加に時間を当てたいと思います!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?