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?

Next.jsとLaravelを連携して管理者登録する方法

Posted at

サンプル

このような管理者画面で登録する際のコードを備忘録として残します。
image.png

フロント側(Next.js)のコード

frontend/app/adminInformation/adminRegistration/page.tsx
'use client'
import { useRouter } from "next/navigation"
import { useState } from "react"
import { useForm } from "react-hook-form"
import axios from "axios"

export default function RegisterationAdmin(){
    //Set default valu
    const defaultValues = {
        userName:'',
        emailAddress:'',
        password:'',
        phoneNumber:'',
        country:'',
        streetAddress:'',
        city:'',
        stateProvince:'',
        zip:''
    }

    //Initialise formdata
    const {register,handleSubmit,formState:{errors}} = useForm({defaultValues});

    //Set route
    const router = useRouter();

    //Click registeration button
    const clickRegistration = ()=>{
        router.push('');
    }

    const backToTopPage = ()=>{
        router.push('/');
    }

    const [userName,setUserName] = useState('');
    const [emailAddress,setEmailAddress] = useState('');
    const [phoneNumber,setPhoneNumber] = useState('');
    const [password,setPassword] = useState('');
    const [country,setCountry] = useState('');
    const [streetAddress,setStreetAddress] = useState('');
    const [city,setCity] = useState('');
    const [stateProvince,setStateProvince] = useState('');
    const [zipCode,setZipCode] = useState('');

    const onSubmit = async(data:any)=>{
        //e.preventDefault();
        const formData = new FormData();
        formData.append('userName',data.userName);
        formData.append('emailAddress',data.emailAddress);
        formData.append('phoneNumber',data.phoneNumber);
        formData.append('password',data.password);
        formData.append('country',data.country);
        formData.append('streetAddress',data.streetAddress);
        formData.append('city',data.city);
        formData.append('stateProvince',data.stateProvince);
        formData.append('zipCode',data.zip);

        formData.forEach((value, key) => {
            console.log(key, value);
        });

        try{
            const response = await axios.post('http://localhost:8000/api/adminRegistration',formData,{               
            });
            console.log(response.data); // レスポンスの確認
        }catch(error){
            alert('Error happend.');
        }

    }

    return (
        <div className="shadow-md flex items-center justify-center rounded-md border border-gray-700">
            <form onSubmit={handleSubmit(onSubmit)} className="w-xl shadow-md min-h-screen rounded-md border border-gray-700 px-10 py-10">
                <div>
                    <h2 className="text-base/7 text-gray-900">
                        Admin account profile
                    </h2>
                </div>
                <div className="w-full grid grid-cols-1 gap-x-6">
                    <label className="block text-sm/6 font-medium text-gray-900">UserName</label>
                    <input
                        type="text"
                        className="text-gray-700 border border-gray-300 rounded-md"
                        defaultValue={defaultValues.userName}
                        {...register('userName',{
                            required:'UserName must be input.',                           
                        })}
                        onChange={(e)=>setUserName(e.target.value)}
                    />
                    <div className="text-red-500">{errors.userName?.message}</div>
                </div>
                <div className="w-full grid grid-cols-1 gap-x-6">
                    <label className="block text-sm/6 font-medium text-gray-900">Email address</label>
                    <input
                        type="email"
                        className="text-gray-700 border border-gray-300 rounded-md"
                        defaultValue={defaultValues.emailAddress}
                        {...register('emailAddress',{
                            required:'EmailAddress must be input.',
                            pattern:{
                                value:/([a-z\d+\-.]@[a-z\d-]+(?:\.[a-z]+)*)/i,
                                message:'Your Email Format is invalid.'
                            }
                        })}
                        onChange={(e)=>setEmailAddress(e.target.value)}
                    />
                    <div className="text-red-500">{errors.emailAddress?.message}</div>
                </div>
                <div className="w-full grid grid-cols-1 gap-x-6">
                    <label className="block text-sm/6 font-medium text-gray-900">Phone number</label>
                    <input
                        type="text"
                        className="text-gray-700 border border-gray-300 rounded-md"
                        defaultValue={defaultValues.phoneNumber}
                        {...register('phoneNumber',{
                            required:'Phone number must be input.'
                        })}
                        onChange={(e)=>setPhoneNumber(e.target.value)}
                    />
                    <div className="text-red-500">{errors.phoneNumber?.message}</div>
                </div>
                <div className="w-full grid grid-cols-1 gap-x-6">
                    <label className="block text-sm/6 font-medium text-gray-900">Password</label>
                    <input
                        type="password"
                        className="text-gray-700 border border-gray-300 rounded-md"
                        {...register('password',{
                            required:'Password must be input.',
                        })}
                        onChange={(e)=>{setPassword(e.target.value)}}
                    />
                    <div className="text-red-500">{errors.password?.message}</div>
                </div>
                <div className="w-full grid grid-cols-1 gap-x-6">
                    <label className="block text-sm/6 font-medium text-gray-900">Country</label>
                    <select className="border border-gray-300 rounded-md" 
                        {...register('country',{required:'Country must be required.'})}
                        onChange={(e)=>{setCountry(e.target.value)}}
                        >
                        <option></option>
                        <option>United States</option>
                        <option>Canada</option>
                        <option>Mexico</option>
                        <option>Australia</option>
                        <option>England</option>
                    </select>
                    <div className="text-red-500">{errors.country?.message}</div>
                </div>
                <div className="w-full grid grid-cols-1 gap-x-6">
                    <label>Street address</label>
                    <input
                        type="text"
                        className="text-gray-700 border border-gray-300 rounded-md"
                        defaultValue={defaultValues.streetAddress}
                        {...register('streetAddress',{
                            required:'StreetAddress must be input.',
                        })}
                        onChange={(e)=>setStreetAddress(e.target.value)}
                    />
                    <div className="text-red-500">{errors.streetAddress?.message}</div>
                </div>
                <div className="w-full grid grid-cols-1 gap-x-6">
                    <label className="block text-sm/6 font-medium text-gray-900">City</label>
                    <input
                        type="text"
                        className="text-gray-700 border border-gray-300 rounded-md"
                        defaultValue={defaultValues.city}
                        {...register('city',{
                            required:'City must be input.',
                        })}
                        onChange={(e)=>setCity(e.target.value)}
                    />
                    <div className="text-red-500">{errors.city?.message}</div>
                </div>
                <div className="w-full grid grid-cols-1 gap-x-6">
                    <label className="block text-sm/6 font-medium text-gray-900">State / Province</label>
                    <input
                        type="text"
                        className="text-gray-700 border border-gray-300 rounded-md"
                        defaultValue={defaultValues.stateProvince}
                        {...register('stateProvince',{
                            required:'StateProvince must be input.'
                        })}
                        onChange={(e)=>setStateProvince(e.target.value)}
                    />
                    <div className="text-red-500">{errors.stateProvince?.message}</div>
                </div>
                <div className="w-full grid grid-cols-1 gap-x-6">
                    <label className="block text-sm/6 font-medium text-gray-900">ZIP / Postal code</label>
                    <input
                        type="text"
                        className="text-gray-700 border border-gray-300 rounded-md"
                        defaultValue={defaultValues.zip}
                        {...register('zip',{
                            required:'ZipCode must be required.'
                        })}
                        onChange={(e)=>setZipCode(e.target.value)}
                    />
                    <div className="text-red-500">{errors.zip?.message}</div>
                </div>
                <div className="flex items-center">
                    <button 
                        type="submit" 
                        className="bg bg-blue-500 text-white px-4 py-4 rounded-md cursor:text-pointer hover:bg-blue-700"
                        onClick={clickRegistration}
                        >
                        Register
                    </button>
                    <button
                        type="button"
                        className="bg bg-rose-500 text-white px-4 py-4 rounded-md cursor:text-pointer hover:bg-rose-700"
                        onClick={backToTopPage}
                        >
                        Home
                    </button>
                </div>
            </form>
        </div>
    )
}

サーバ側(Laravel)のコード

Modelクラスとテーブルを紐づけるために$tableプロパティにテーブル名を指定します。

protected $table = 'adminusers';

さらに、カラムadminIdを主キーと認識させるために次の処理を追加します。

protected $primaryKey = 'adminId';

さいごにオートインクリメントさせないように下記の処理を追加します。

public $incrementing = false;

以上を踏まえたAdminUser.phpの全体ソースは下記です。

backend/app/Models/Adminuser.php
<?php

namespace App\Models;

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

class AdminUser extends Model
{
    use HasFactory;

    protected $table = 'adminusers';//Add
    protected $primaryKey = 'adminId';// Assign Column'adminId' primarykey
    public $incrementing = false;//Not AutoIncrement
    protected $keyType = 'string';//UUID type is String

    public function getAdminUserId()
    {
        return $this->attributes['adminId'];
    }

    public function setAdminUserId($adminId)
    {
        $this->attributes['adminId'] = $adminId;
    }

    public function getAdminUserName()
    {
        return $this->attributes['adminUserName'];
    }

    public function setAdminUserName($adminUserName)
    {
        $this->attributes['adminUserName'] = $adminUserName;
    }

    public function getAdminUserEmail()
    {
        return $this->attributes['adminUserEmail'];
    }

    public function setAdminUserEmail($adminUserEmail)
    {
        $this->attributes['adminUserEmail'] = $adminUserEmail;
    }

    public function getAdminUserPassword()
    {
        return $this->attributes['adminUserPassword'];
    }

    public function setAdminUserPassword($adminUserPassword)
    {
        $this->attributes['adminUserPassword'] = $adminUserPassword;
    }

    public function getAdminUserPhoneNumber()
    {
        return $this->attributes['adminUserPhoneNumber'];
    }

    public function setAdminUserPhoneNumber($adminUserPhoneNumber)
    {
        $this->attributes['adminUserPhoneNumber'] = $adminUserPhoneNumber;
    }

    public function getAdminUserCountry()
    {
        return $this->attributes['adminUserCountry'];
    }

    public function setAdminUserCountry($adminUserCountry)
    {
        $this->attributes['adminUserCountry'] = $adminUserCountry;
    }

    public function getAdminUserStreetAddress()
    {
        return $this->attributes['adminUserStreetAddress'];
    }

    public function setAdminUserStreetAddress($adminUserStreetAddress)
    {
        $this->attributes['adminUserStreetAddress'] = $adminUserStreetAddress;
    }

    public function getAdminUserCity()
    {
        return $this->attributes['adminUserCity'];
    }

    public function setAdminUserCity($adminUserCity)
    {
        $this->attributes['adminUserCity'] = $adminUserCity;
    }

    public function getAdminUserStateProvince()
    {
        $this->attributes['adminUserStateProvince'];
    }

    public function setAdminUserStateProvince($adminUserStateProvince)
    {
        $this->attributes['adminUserStateProvince'] = $adminUserStateProvince;
    }

    public function getAdminUserZipCode()
    {
        return $this->attributes['adminUserZipCode'];
    }

    public function setAdminUserZipCode($adminUserZipCode)
    {
        $this->attributes['adminUserZipCode'] = $adminUserZipCode;
    }

    public function getCreatedAt()
    {
        return $this->attributes['created_at'];
    }

    public function setCreatedAt($createdAt)
    {
        $this->attributes['created_at'] = $createdAt;
    }

    public function getUpdatedAt()
    {
        return $this->attributes['updated_at'];
    }

    public function setUpdatedAt($updatedAt)
    {
        $this->attributes['updated_at'] = $updatedAt;
    }
}

マイグレーションクラスは貝のとおりです。
まず、管理者のIDは、セキュリティの観点からUUIDとしました。
つぎに、これから作るログイン画面でも使用するE-mail addressをユニーク製薬としました。

create_AdminUser_table.php
<?php

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

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('adminusers', function (Blueprint $table) {
            $table->uuid('adminId')->primary(); //Primary key
            $table->string('adminUserName');
            $table->string('adminUserEmail')->unique();
            $table->string('adminUserPassword');
            $table->integer('adminUserPhoneNumber');
            $table->string('adminUserCountry');
            $table->string('adminUserStreetAddress');
            $table->string('adminUserCity');
            $table->string('adminUserStateProvince');
            $table->integer('adminUserZipCode');
            $table->timestamps();
        });
    }

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

さいごにコントローラです。

手動でのトランザクション処理を施すため下記のライブラリを追加しました。

sample.php
use Illuminate\Support\Facades\DB;//Add
use Illuminate\Support\Facades\Log;//Add

UUIDを生成するため下記のライブラリを追加しました。

sample.php
use Illuminate\Support\Str; // Add to use uuid
backend/app/Http/Controllers/AdminRegisterController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash; // Add hashd library
use App\Models\AdminUser; //Add AdminUser
use Illuminate\Support\Facades\DB;//Add
use Illuminate\Support\Facades\Log;//Add
use Illuminate\Support\Str; // Add to use uuid

class AdminRegisterController extends Controller
{
    public function createAdminUser(Request $request)
    {
        //\Log::info('リクエストデータ:', $request->all());
        // Get Requested Data
        $userName = $request->input('userName');
        $emailAddress = $request->input('emailAddress');
        $phoneNumber = $request->input('phoneNumber');
        $password = $request->input('password');
        //Make hashedPassword
        $hashedPassword = Hash::make($password);
        $country = $request->input('country');
        $streetAddress = $request->input('streetAddress');
        $city = $request->input('city');
        $stateProvince = $request->input('stateProvince');
        $zipCode = $request->input('zipCode');

        DB::beginTransaction();
        try{
            $adminUser = new AdminUser();
            $adminUser->adminId = Str::uuid();
            $adminUser->adminUserName = $userName;
            $adminUser->adminUserEmail = $emailAddress;
            $adminUser->adminUserPassword = $hashedPassword;
            $adminUser->adminUserPhoneNumber = $phoneNumber;
            $adminUser->adminUserCountry = $country;
            $adminUser->adminUserStreetAddress = $streetAddress;
            $adminUser->adminUserCity = $city;
            $adminUser->adminUserStateProvince = $stateProvince;
            $adminUser->adminUserZipCode = $zipCode;
    
            //Save the AdminUser
            $adminUser->save();
            // Commit
            DB::commit();

        }catch(\Throwable $e){
            DB::rollBack();
            Log::error('Admin user creation failed: ' . $e->getMessage());
            return response()->json([
                'error' => 'Admin user creation failed.',
                'message' => $e->getMessage(),
            ], 500);
            throw $e;
        }

        //$adminUser = new AdminUser();
        $createdAdminuserId = AdminUser::where('adminUserEmail', $emailAddress)->first();

        return response()->json([
            'adminUserId' => $createdAdminuserId->adminId,
            'username'=>$userName,
            'emailAddress'=>$emailAddress,
            'password'=>$password,
            'country'=>$country
        ]);
    }
}

LaravelコマンドのTips

マイグレーションのリセットは下記のコマンドで実行します。
テーブルのカラム情報の更新に使用します。

php artisan migrate:refresh

LaravelのマイグレーションのTips

timestampsの自動管理

timestamps()メソッドにより、created_atupdated_atは自動的に管理されるので、手動で設定する必要はありません。

参考サイト

フォーム inputのpatternを使って、電話番号・郵便番号・フリガナ・空白などを判別する方法

Laravelでパスワードに強くなろう!ハッシュ化・パスワード照会

Laravelの困る機能を解決!テーブル名とモデル名が一致しない・IDで自動採番したくない時の対処法

Laravelでハッシュ化したいんですけどっ!!?

Laravelでuuidをidとするモデルを作りたいとき

テーブルののユニーク制約について

Laravel公式サイトののUUIDライブラリ

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?