Users CRUD
This commit is contained in:
parent
8edb194a28
commit
e05ac5031b
@ -30,13 +30,15 @@ public function create(): View
|
||||
public function store(Request $request): RedirectResponse
|
||||
{
|
||||
$request->validate([
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
'first_name' => ['required', 'string', 'max:255'],
|
||||
'last_name' => ['required', 'string', 'max:255'],
|
||||
'email' => ['required', 'string', 'lowercase', 'email', 'max:255', 'unique:'.User::class],
|
||||
'password' => ['required', 'confirmed', Rules\Password::defaults()],
|
||||
]);
|
||||
|
||||
$user = User::create([
|
||||
'name' => $request->name,
|
||||
'first_name' => $request->first_name,
|
||||
'last_name' => $request->last_name,
|
||||
'email' => $request->email,
|
||||
'password' => Hash::make($request->password),
|
||||
]);
|
||||
|
||||
67
app/Http/Controllers/UserController.php
Normal file
67
app/Http/Controllers/UserController.php
Normal file
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Requests\StoreUserRequest;
|
||||
use App\Http\Requests\UpdateUserRequest;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class UserController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$users = User::paginate(10);
|
||||
|
||||
return view('users.index', compact('users'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
return view('users.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(StoreUserRequest $request)
|
||||
{
|
||||
User::create($request->validated());
|
||||
|
||||
return redirect()->route('users.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(User $user)
|
||||
{
|
||||
return view('users.edit', compact('user'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(UpdateUserRequest $request, User $user)
|
||||
{
|
||||
$user->update($request->validated());
|
||||
|
||||
return redirect()->route('users.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(User $user)
|
||||
{
|
||||
$user->delete();
|
||||
|
||||
return redirect()->route('users.index');
|
||||
}
|
||||
}
|
||||
32
app/Http/Requests/StoreUserRequest.php
Normal file
32
app/Http/Requests/StoreUserRequest.php
Normal file
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class StoreUserRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'first_name' => ['required'],
|
||||
'last_name' => ['required'],
|
||||
'email' => ['required', 'email', Rule::unique('users')],
|
||||
'password' => ['required'],
|
||||
];
|
||||
}
|
||||
}
|
||||
31
app/Http/Requests/UpdateUserRequest.php
Normal file
31
app/Http/Requests/UpdateUserRequest.php
Normal file
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class UpdateUserRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'first_name' => ['required'],
|
||||
'last_name' => ['required'],
|
||||
'email' => ['required', 'email', Rule::unique('users')->ignore($this->user)],
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -4,12 +4,13 @@
|
||||
|
||||
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
|
||||
class User extends Authenticatable
|
||||
{
|
||||
use HasFactory, Notifiable;
|
||||
use HasFactory, Notifiable, SoftDeletes;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
@ -17,7 +18,8 @@ class User extends Authenticatable
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'first_name',
|
||||
'last_name',
|
||||
'email',
|
||||
'password',
|
||||
];
|
||||
|
||||
@ -24,7 +24,8 @@ class UserFactory extends Factory
|
||||
public function definition(): array
|
||||
{
|
||||
return [
|
||||
'name' => fake()->name(),
|
||||
'first_name' => fake()->firstName(),
|
||||
'last_name' => fake()->lastName(),
|
||||
'email' => fake()->unique()->safeEmail(),
|
||||
'email_verified_at' => now(),
|
||||
'password' => static::$password ??= Hash::make('password'),
|
||||
|
||||
@ -13,12 +13,14 @@ public function up(): void
|
||||
{
|
||||
Schema::create('users', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->string('first_name');
|
||||
$table->string('last_name');
|
||||
$table->string('email')->unique();
|
||||
$table->timestamp('email_verified_at')->nullable();
|
||||
$table->string('password');
|
||||
$table->rememberToken();
|
||||
$table->timestamps();
|
||||
$table->softDeletes();
|
||||
});
|
||||
|
||||
Schema::create('password_reset_tokens', function (Blueprint $table) {
|
||||
|
||||
@ -13,11 +13,6 @@ class DatabaseSeeder extends Seeder
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
// User::factory(10)->create();
|
||||
|
||||
User::factory()->create([
|
||||
'name' => 'Test User',
|
||||
'email' => 'test@example.com',
|
||||
]);
|
||||
User::factory(10)->create();
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,11 +2,18 @@
|
||||
<form method="POST" action="{{ route('register') }}">
|
||||
@csrf
|
||||
|
||||
<!-- Name -->
|
||||
<!-- First Name -->
|
||||
<div>
|
||||
<x-input-label for="name" :value="__('Name')" />
|
||||
<x-text-input id="name" class="block mt-1 w-full" type="text" name="name" :value="old('name')" required autofocus autocomplete="name" />
|
||||
<x-input-error :messages="$errors->get('name')" class="mt-2" />
|
||||
<x-input-label for="first_name" :value="__('First Name')" />
|
||||
<x-text-input id="first_name" class="block mt-1 w-full" type="text" name="first_name" :value="old('first_name')" required autofocus autocomplete="first_name" />
|
||||
<x-input-error :messages="$errors->get('first_name')" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<!-- Last Name -->
|
||||
<div class="mt-4">
|
||||
<x-input-label for="last_name" :value="__('Last Name')" />
|
||||
<x-text-input id="last_name" class="block mt-1 w-full" type="text" name="last_name" :value="old('last_name')" required autocomplete="last_name" />
|
||||
<x-input-error :messages="$errors->get('last_name')" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<!-- Email Address -->
|
||||
|
||||
@ -15,6 +15,9 @@
|
||||
<x-nav-link :href="route('dashboard')" :active="request()->routeIs('dashboard')">
|
||||
{{ __('Dashboard') }}
|
||||
</x-nav-link>
|
||||
<x-nav-link :href="route('users.index')" :active="request()->routeIs('users.*')">
|
||||
{{ __('Users') }}
|
||||
</x-nav-link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -23,7 +26,7 @@
|
||||
<x-dropdown align="right" width="48">
|
||||
<x-slot name="trigger">
|
||||
<button class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-500 bg-white hover:text-gray-700 focus:outline-none transition ease-in-out duration-150">
|
||||
<div>{{ Auth::user()->name }}</div>
|
||||
<div>{{ Auth::user()->first_name }}</div>
|
||||
|
||||
<div class="ms-1">
|
||||
<svg class="fill-current h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
|
||||
@ -70,12 +73,15 @@
|
||||
<x-responsive-nav-link :href="route('dashboard')" :active="request()->routeIs('dashboard')">
|
||||
{{ __('Dashboard') }}
|
||||
</x-responsive-nav-link>
|
||||
<x-responsive-nav-link :href="route('users.index')" :active="request()->routeIs('users.*')">
|
||||
{{ __('Users') }}
|
||||
</x-responsive-nav-link>
|
||||
</div>
|
||||
|
||||
<!-- Responsive Settings Options -->
|
||||
<div class="pt-4 pb-1 border-t border-gray-200">
|
||||
<div class="px-4">
|
||||
<div class="font-medium text-base text-gray-800">{{ Auth::user()->name }}</div>
|
||||
<div class="font-medium text-base text-gray-800">{{ Auth::user()->first_name }}</div>
|
||||
<div class="font-medium text-sm text-gray-500">{{ Auth::user()->email }}</div>
|
||||
</div>
|
||||
|
||||
|
||||
69
resources/views/users/create.blade.php
Normal file
69
resources/views/users/create.blade.php
Normal file
@ -0,0 +1,69 @@
|
||||
<x-app-layout>
|
||||
<x-slot name="header">
|
||||
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
|
||||
{{ __('Create User') }}
|
||||
</h2>
|
||||
</x-slot>
|
||||
|
||||
<div class="py-12">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
|
||||
<div class="overflow-hidden overflow-x-auto p-6 bg-white border-b border-gray-200">
|
||||
|
||||
<form method="POST" action="{{ route('users.store') }}">
|
||||
@csrf
|
||||
|
||||
<!-- First Name -->
|
||||
<div>
|
||||
<x-input-label for="first_name" :value="__('First Name')" />
|
||||
<x-text-input id="first_name" class="block mt-1 w-full" type="text" name="first_name" :value="old('first_name')" required />
|
||||
<x-input-error :messages="$errors->get('first_name')" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<!-- Last Name -->
|
||||
<div class="mt-4">
|
||||
<x-input-label for="last_name" :value="__('Last Name')" />
|
||||
<x-text-input id="last_name" class="block mt-1 w-full" type="text" name="last_name" :value="old('last_name')" required />
|
||||
<x-input-error :messages="$errors->get('last_name')" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<!-- Email Address -->
|
||||
<div class="mt-4">
|
||||
<x-input-label for="email" :value="__('Email')" />
|
||||
<x-text-input id="email" class="block mt-1 w-full" type="email" name="email" :value="old('email')" required />
|
||||
<x-input-error :messages="$errors->get('email')" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<!-- Password -->
|
||||
<div class="mt-4">
|
||||
<x-input-label for="password" :value="__('Password')" />
|
||||
|
||||
<x-text-input id="password" class="block mt-1 w-full"
|
||||
type="password"
|
||||
name="password"
|
||||
required />
|
||||
|
||||
<x-input-error :messages="$errors->get('password')" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<!-- Confirm Password -->
|
||||
<div class="mt-4">
|
||||
<x-input-label for="password_confirmation" :value="__('Confirm Password')" />
|
||||
|
||||
<x-text-input id="password_confirmation" class="block mt-1 w-full"
|
||||
type="password"
|
||||
name="password_confirmation" required />
|
||||
|
||||
<x-input-error :messages="$errors->get('password_confirmation')" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<x-primary-button class="mt-4">
|
||||
{{ __('Save') }}
|
||||
</x-primary-button>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</x-app-layout>
|
||||
47
resources/views/users/edit.blade.php
Normal file
47
resources/views/users/edit.blade.php
Normal file
@ -0,0 +1,47 @@
|
||||
<x-app-layout>
|
||||
<x-slot name="header">
|
||||
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
|
||||
{{ __('Edit User') }}
|
||||
</h2>
|
||||
</x-slot>
|
||||
|
||||
<div class="py-12">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
|
||||
<div class="overflow-hidden overflow-x-auto p-6 bg-white border-b border-gray-200">
|
||||
|
||||
<form method="POST" action="{{ route('users.update', $user) }}">
|
||||
@method('PUT')
|
||||
@csrf
|
||||
|
||||
<!-- First Name -->
|
||||
<div>
|
||||
<x-input-label for="first_name" :value="__('First Name')" />
|
||||
<x-text-input id="first_name" class="block mt-1 w-full" type="text" name="first_name" :value="old('first_name', $user->first_name)" required />
|
||||
<x-input-error :messages="$errors->get('first_name')" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<!-- Last Name -->
|
||||
<div class="mt-4">
|
||||
<x-input-label for="last_name" :value="__('Last Name')" />
|
||||
<x-text-input id="last_name" class="block mt-1 w-full" type="text" name="last_name" :value="old('last_name', $user->last_name)" required />
|
||||
<x-input-error :messages="$errors->get('last_name')" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<!-- Email Address -->
|
||||
<div class="mt-4">
|
||||
<x-input-label for="email" :value="__('Email')" />
|
||||
<x-text-input id="email" class="block mt-1 w-full" type="email" name="email" :value="old('email', $user->email)" required />
|
||||
<x-input-error :messages="$errors->get('email')" class="mt-2" />
|
||||
</div>
|
||||
|
||||
<x-primary-button class="mt-4">
|
||||
{{ __('Save') }}
|
||||
</x-primary-button>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</x-app-layout>
|
||||
67
resources/views/users/index.blade.php
Normal file
67
resources/views/users/index.blade.php
Normal file
@ -0,0 +1,67 @@
|
||||
<x-app-layout>
|
||||
<x-slot name="header">
|
||||
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
|
||||
{{ __('Users') }}
|
||||
</h2>
|
||||
</x-slot>
|
||||
|
||||
<div class="py-12">
|
||||
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
|
||||
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
|
||||
<div class="p-6 text-gray-900">
|
||||
<a href="{{ route('users.create') }}" class="underline">Add new user</a>
|
||||
|
||||
<table class="min-w-full divide-y divide-gray-200 border mt-4">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="px-6 py-3 bg-gray-50 text-left">
|
||||
<span class="text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">First Name</span>
|
||||
</th>
|
||||
<th class="px-6 py-3 bg-gray-50 text-left">
|
||||
<span class="text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">Last Name</span>
|
||||
</th>
|
||||
<th class="px-6 py-3 bg-gray-50 text-left">
|
||||
<span class="text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">Email</span>
|
||||
</th>
|
||||
<th class="px-6 py-3 bg-gray-50 text-left">
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody class="bg-white divide-y divide-gray-200 divide-solid">
|
||||
@foreach($users as $user)
|
||||
<tr class="bg-white">
|
||||
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-900">
|
||||
{{ $user->first_name }}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-900">
|
||||
{{ $user->last_name }}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-900">
|
||||
{{ $user->email }}
|
||||
</td>
|
||||
<td class="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-900">
|
||||
<a href="{{ route('users.edit', $user) }}" class="underline">Edit</a>
|
||||
|
|
||||
<form method="POST"
|
||||
class="inline-block"
|
||||
action="{{ route('users.destroy', $user) }}"
|
||||
onsubmit="return confirm('Are you sure?')">
|
||||
@method('DELETE')
|
||||
@csrf
|
||||
<button type="submit" class="text-red-500 underline">Delete</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="mt-4">
|
||||
{{ $users->links() }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</x-app-layout>
|
||||
@ -1,6 +1,7 @@
|
||||
<?php
|
||||
|
||||
use App\Http\Controllers\ProfileController;
|
||||
use App\Http\Controllers\UserController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::get('/', function () {
|
||||
@ -12,6 +13,8 @@
|
||||
})->middleware(['auth', 'verified'])->name('dashboard');
|
||||
|
||||
Route::middleware('auth')->group(function () {
|
||||
Route::resource('users', UserController::class);
|
||||
|
||||
Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');
|
||||
Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update');
|
||||
Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy');
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user