サンプル
このような管理者画面で登録する際のコードを備忘録として残します。
フロント側(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_at
とupdated_at
は自動的に管理されるので、手動で設定する必要はありません。
参考サイト
フォーム inputのpatternを使って、電話番号・郵便番号・フリガナ・空白などを判別する方法
Laravelでパスワードに強くなろう!ハッシュ化・パスワード照会
Laravelの困る機能を解決!テーブル名とモデル名が一致しない・IDで自動採番したくない時の対処法
Laravelでハッシュ化したいんですけどっ!!?
Laravelでuuidをidとするモデルを作りたいとき
テーブルののユニーク制約について
Laravel公式サイトののUUIDライブラリ