In this tutorial, we will create crud operations in laravel 10 with Tailwind CSS. For tailwind css we will use laravel breeze. For laravel 10 you need php 8.1+ version.
Step 1: Install Laravel & Connect Database
Run below command to install laravel 10.
composer create-project laravel/laravel project-name
Now, you have to connect the laravel app to the database, hence open the .env configuration file and add the database credentials as suggested below.
.env
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=database_name
DB_USERNAME=database_user_name
DB_PASSWORD=database_password
Step 2: Install Breeze For Tailwind CSS
Install laravel breeze via composer
composer require laravel/breeze --dev
Next, run below command
php artisan breeze:install
Give 0 number to start with tailwind css blade file.
Which stack would you like to install?
blade .............................................. 0
react .............................................. 1
vue ................................................ 2
api ................................................ 3
❯ 0
You can also add dark mode support and pest.
Would you like to install dark mode support? (yes/no) [no]
❯ yes
Would you prefer Pest tests instead of PHPUnit? (yes/no) [no]
❯ yes
Step 3: Create Model Migration Resource Controller & route
Run below command to create post model migration controller
php artisan make:model Post -mcr
2023_02_21_144535_create_posts_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.
*/
public function up(): void
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->string('slug');
$table->text('content');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('posts');
}
};
And migrate database:
php artisan migrate
app/Models/Post.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
use HasFactory;
protected $fillable = [
'title',
'slug',
'content',
];
}
Before add CRUD Operation logic in PostController. you need import use Illuminate\View\View; and give index, create, show, edit to View type laravel 10 support type system so you need to create correct type otherwise you get error message.
app/Http/Controllers/PostController.php
<?php
namespace App\Http\Controllers;
use App\Models\Post;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\View\View;
class PostController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index(): View
{
$posts = Post::latest()->paginate(10);
return view('posts.index', compact('posts'));
}
/**
* Show the form for creating a new resource.
*/
public function create(): View
{
return view('posts.create');
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request): RedirectResponse
{
$request->validate([
'title' => 'required|string|max:255',
'slug' => 'required|string|max:255',
'content' => 'required'
]);
Post::create([
'title' => $request->title,
'slug' => \Str::slug($request->slug),
'content' => $request->content,
]);
return redirect()->route('posts.index')->with('status', 'Post Created Successfully');
}
/**
* Display the specified resource.
*/
public function show(Post $post): View
{
return view('posts.show', compact('post'));
}
/**
* Show the form for editing the specified resource.
*/
public function edit(Post $post): View
{
return view('posts.edit', compact('post'));
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, Post $post): RedirectResponse
{
$request->validate([
'title' => 'required|string|max:255',
'slug' => 'required|string|max:255',
'content' => 'required'
]);
$post->title = $request->title;
$post->slug = \Str::slug($request->slug);
$post->content = $request->content;
$post->save();
return redirect()->route('posts.index')->with('status', 'Post Updated Successfully');
}
/**
* Remove the specified resource from storage.
*/
public function destroy(Post $post): RedirectResponse
{
$post->delete();
return redirect()->route('posts.index')->with('status', 'Post Delete Successfully');
}
}
web.php
<?php
use App\Http\Controllers\ProfileController;
use App\Http\Controllers\PostController;
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| 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('/', function () {
return view('welcome');
});
Route::get('/dashboard', function () {
return view('dashboard');
})->middleware(['auth', 'verified'])->name('dashboard');
Route::middleware('auth')->group(function () {
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');
Route::resource('posts', PostController::class);
});
require __DIR__.'/auth.php';
Step 4: Create Blade view file for CRUD
resources/views/posts/create.blade.php
<x-app-layout>
<x-slot name="header">
<h2 class="text-xl font-semibold leading-tight text-gray-800">
{{ __('Post Create') }}
</h2>
</x-slot>
<div class="py-12">
<div class="mx-auto max-w-5xl sm:px-6 lg:px-8">
<div class="overflow-hidden bg-white shadow-sm sm:rounded-lg">
<div class="p-6 bg-white border-b border-gray-200">
<form method="POST" action="{{ route('posts.store') }}">
@csrf
<div class="mb-6">
<label class="block">
<span class="text-gray-700">Title</span>
<input type="text" name="title" class="block w-full mt-1 rounded-md" placeholder=""
value="{{ old('title') }}" />
</label>
@error('title')
<div class="text-sm text-red-600">{{ $message }}</div>
@enderror
</div>
<div class="mb-6">
<label class="block">
<span class="text-gray-700">Slug</span>
<input type="text" name="slug" class="block w-full mt-1 rounded-md" placeholder=""
value="{{ old('slug') }}" />
</label>
@error('slug')
<div class="text-sm text-red-600">{{ $message }}</div>
@enderror
</div>
<div class="mb-6">
<label class="block">
<span class="text-gray-700">Content</span>
<textarea id="editor" class="block w-full mt-1 rounded-md" name="content" rows="3">{{ old('content') }}</textarea>
</label>
@error('content')
<div class="text-sm text-red-600">{{ $message }}</div>
@enderror
</div>
<x-primary-button type="submit">
Submit
</x-primary-button>
</form>
</div>
</div>
</div>
</div>
</x-app-layout>
resources/views/posts/index.blade.php
<x-app-layout>
<x-slot name="header">
<h2 class="text-xl font-semibold leading-tight text-gray-800">
{{ __('Posts') }}
</h2>
</x-slot>
<div class="py-12">
<div class="mx-auto max-w-5xl sm:px-6 lg:px-8">
<div class="overflow-hidden bg-white shadow-sm sm:rounded-lg">
<div class="p-6 bg-white border-b border-gray-200">
@if (session()->has('status'))
<div class="flex justify-center items-center">
<p class="ml-3 text-sm font-bold text-green-600">{{ session()->get('status') }}</p>
</div>
@endif
<div class="mt-1 mb-4">
<x-primary-button>
<a href="{{ route('posts.create') }}">{{ __('Add Post') }}</a>
</x-primary-button>
</div>
<div class="relative overflow-x-auto shadow-md sm:rounded-lg">
<table class="w-full text-sm text-left text-gray-500 dark:text-gray-400">
<thead
class="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
<tr>
<th scope="col" class="px-6 py-3">
#
</th>
<th scope="col" class="px-6 py-3">
Title
</th>
<th scope="col" class="px-6 py-3">
Edit
</th>
<th scope="col" class="px-6 py-3">
Delete
</th>
</tr>
</thead>
<tbody>
@foreach ($posts as $post)
<tr class="bg-white border-b dark:bg-gray-800 dark:border-gray-700">
<th scope="row"
class="px-6 py-4 font-medium text-gray-900 dark:text-white whitespace-nowrap">
{{ $post->id }}
</th>
<td class="px-6 py-4">
{{ $post->title }}
</td>
<td class="px-6 py-4">
<a href="{{ route('posts.edit', $post->id) }}">Edit</a>
</td>
<td class="px-6 py-4">
<form action="{{ route('posts.destroy', $post->id) }}" method="POST"
onsubmit="return confirm('{{ trans('are You Sure ? ') }}');"
style="display: inline-block;">
<input type="hidden" name="_method" value="DELETE">
<input type="hidden" name="_token" value="{{ csrf_token() }}">
<input type="submit" class="px-4 py-2 text-white bg-red-700 rounded"
value="Delete">
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</x-app-layout>
resources/views/posts/edit.blade.php
<x-app-layout>
<x-slot name="header">
<h2 class="text-xl font-semibold leading-tight text-gray-800">
{{ __('Category Edit') }}
</h2>
</x-slot>
<div class="py-12">
<div class="mx-auto max-w-5xl sm:px-6 lg:px-8">
<div class="overflow-hidden bg-white shadow-sm sm:rounded-lg">
<div class="p-6 bg-white border-b border-gray-200">
<form method="POST" action="{{ route('posts.update',$post->id) }}">
@csrf
@method('put')
<div class="mb-6">
<label class="block">
<span class="text-gray-700">Title</span>
<input type="text" name="title"
class="block w-full mt-1 rounded-md"
placeholder="" value="{{old('title',$post->title)}}" />
</label>
@error('title')
<div class="text-sm text-red-600">{{ $message }}</div>
@enderror
</div>
<div class="mb-6">
<label class="block">
<span class="text-gray-700">Slug</span>
<input type="text" name="slug"
class="block w-full mt-1 rounded-md"
placeholder="" value="{{old('slug',$post->slug)}}" />
</label>
@error('slug')
<div class="text-sm text-red-600">{{ $message }}</div>
@enderror
</div>
<div class="mb-6">
<label class="block">
<span class="text-gray-700">Content</span>
<textarea id="editor" class="block w-full mt-1 rounded-md" name="content"
rows="3">{{ $post->content}}</textarea>
</label>
@error('content')
<div class="text-sm text-red-600">{{ $message }}</div>
@enderror
</div>
<x-primary-button type="submit">
Update
</x-primary-button>
</form>
</div>
</div>
</div>
</div>
</x-app-layout>
Step 5: Laravel Run Server with Vite
Run below command in terminal to serve laravel 10 app.
php artisan serve
Next, you need to open next terminal.
npm run dev
// or
npm run build