Untuk membuat CRUD Laravel dalam hal ini CRUD Posts, kita akan mulai langkah tersebut sebagai berikut:

1. Persiapan Proyek Laravel

Mulai dengan proyek Laravel baru dengan membukan console dan ketik berikut:
 

composer create-project --prefer-dist laravel/laravel blog
cd blog
php artisan serve

2. Buat Model dan Migration

Buat model Post dengan migration-nya dengan ketik di terminal berikut:

php artisan make:model Post -m

-m akan membuat migration di folder app\database\migrations. lalu Edit file migration di database/migrations/xxxx_create_posts_table.php menjadi sebagai berikut:
 

public function up()
{
    Schema::create('posts', function (Blueprint $table) {
        $table->id();
        $table->string('title');
        $table->text('body');
        $table->string('image')->nullable(); // Kolom untuk gambar
        $table->timestamps();
    });
}

Setelah itu edit file .env untuk konfigurasi database sebagai berikut:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=tutorials
DB_USERNAME=root
DB_PASSWORD=

Untuk nama database, username dan password silahkan sesuaikan dengan database masing-masing. Dalam tutorial ini, database kita buat degan nama tutorials, kemudian user root dan password kosong.  

Kemudian jalankan perintah migrate untuk membuat tabel posts di database dengan ketik perintah berikut:

php artisan migrate

Setelah migrate berhasil, maka akan terbentuk tabel di database dengan nama tutorials dan otomatis akan dibuat table dengan nama posts. 

Kemudian edit Model Post.php menjadi sebagai berikut:
 

<?php

namespace App\Models;

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

class Post extends Model
{
    use HasFactory;
    protected $fillable = ['title', 'body', 'image'];
}

3. Buat Resource Controller

Buat controller untuk Post dengan melakukan perintah berikut:

php artisan make:controller PostController --resource

Lalu bukan file controller yang sudah kita create tadi di folder app\controllers dan edit menjadi berikut:

<?php

namespace App\Http\Controllers;

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

class PostController extends Controller
{
    /**
     * Display a listing of the posts.
     */
    public function index()
    {
        $posts = Post::all();
        return view('posts.index', compact('posts'));
    }

    /**
     * Show the form for creating a new post.
     */
    public function create()
    {
        return view('posts.create');
    }

    /**
     * Store a newly created post in storage.
     */
    public function store(Request $request)
    {
        $request->validate([
            'title' => 'required|string|max:255',
            'body' => 'required',
            'image' => 'nullable|image|mimes:jpeg,png,jpg,gif|max:2048',
        ]);

        $imageName = null;
        if ($request->file('image')) {
            $imageName = time() . '.' . $request->image->extension();
            $request->image->move(public_path('images'), $imageName);
        }

        Post::create([
            'title' => $request->title,
            'body' => $request->body,
            'image' => $imageName,
        ]);

        return redirect()->route('posts.index')->with('success', 'Post created successfully.');
    }

    /**
     * Display the specified post.
     */
    public function show($id)
    {
        $post = Post::findOrFail($id);
        return view('posts.show', compact('post'));
    }

    /**
     * Show the form for editing the specified post.
     */
    public function edit($id)
    {
        $post = Post::findOrFail($id);
        return view('posts.edit', compact('post'));
    }

    /**
     * Update the specified post in storage.
     */
    public function update(Request $request, $id)
    {
        $post = Post::findOrFail($id);

        $request->validate([
            'title' => 'required|string|max:255',
            'body' => 'required',
            'image' => 'nullable|image|mimes:jpeg,png,jpg,gif|max:2048',
        ]);

        $imageName = $post->image;
        if ($request->file('image')) {
            if ($imageName) {
                unlink(public_path('images/') . $imageName); // Hapus gambar lama jika ada
            }
            $imageName = time() . '.' . $request->image->extension();
            $request->image->move(public_path('images'), $imageName);
        }

        $post->update([
            'title' => $request->title,
            'body' => $request->body,
            'image' => $imageName,
        ]);

        return redirect()->route('posts.index')->with('success', 'Post updated successfully.');
    }

    /**
     * Remove the specified post from storage.
     */
    public function destroy($id)
    {
        $post = Post::findOrFail($id);

        if ($post->image) {
            unlink(public_path('images/') . $post->image); // Hapus gambar jika ada
        }

        $post->delete();

        return redirect()->route('posts.index')->with('success', 'Post deleted successfully.');
    }
}

4. Views

Buat view untuk menampilkan form dan data post. Buat folder  posts di resources/views/posts dan buat file berikut:

index.blade.php (List Posts)

@extends('layout')

@section('title', 'Manage Posts')

@section('content')
<div class="container mt-5">
    <h2 class="mb-4">Manage Posts</h2>

    @if (session('success'))
        <div class="alert alert-success">
            {{ session('success') }}
        </div>
    @endif

    <!-- Tombol untuk menambahkan post baru -->
    <div class="d-flex justify-content-between mb-3">
        <a href="{{ route('posts.create') }}" class="btn btn-primary">Create New Post</a>
        <form action="{{ route('posts.index') }}" method="GET" class="d-flex">
            <input type="text" name="search" class="form-control me-2" placeholder="Search posts" value="{{ request()->query('search') }}">
            <button type="submit" class="btn btn-secondary">Search</button>
        </form>
    </div>

    <!-- Tabel daftar posts -->
    <table class="table table-bordered table-striped">
        <thead class="table-dark">
            <tr>
                <th>#</th>
                <th>Title</th>
                <th>Image</th>
                <th>Created At</th>
                <th>Actions</th>
            </tr>
        </thead>
        <tbody>
            @forelse ($posts as $post)
                <tr>
                    <td>{{ $loop->iteration }}</td>
                    <td>{{ $post->title }}</td>
                    <td>
                        @if ($post->image)
                            <img src="{{ asset('images/' . $post->image) }}" alt="{{ $post->title }}" class="img-thumbnail" style="width: 100px;">
                        @else
                            <span class="text-muted">No Image</span>
                        @endif
                    </td>
                    <td>{{ $post->created_at->format('d M Y') }}</td>
                    <td>
                        <a href="{{ route('posts.edit', $post->id) }}" class="btn btn-sm btn-warning">Edit</a>
                        <form action="{{ route('posts.destroy', $post->id) }}" method="POST" class="d-inline">
                            @csrf
                            @method('DELETE')
                            <button type="submit" class="btn btn-sm btn-danger" onclick="return confirm('Are you sure you want to delete this post?')">Delete</button>
                        </form>
                    </td>
                </tr>
            @empty
                <tr>
                    <td colspan="6" class="text-center">No posts found.</td>
                </tr>
            @endforelse
        </tbody>
    </table>

    <!-- Pagination -->
    <div class="d-flex justify-content-end">
       
    </div>
</div>
@endsection

Kemudian di folder yang sama, create file create.blade.php di folder yang sama dan isikan code berikut:

@extends('layout')

@section('title', 'Create New Post')

@section('content')
<div class="container mt-5">
    <h2 class="mb-4">Create New Post</h2>

    @if ($errors->any())
        <div class="alert alert-danger">
            <ul>
                @foreach ($errors->all() as $error)
                    <li>{{ $error }}</li>
                @endforeach
            </ul>
        </div>
    @endif

    <form action="{{ route('posts.store') }}" method="POST" enctype="multipart/form-data">
        @csrf
        <div class="mb-3">
            <label for="title" class="form-label">Post Title</label>
            <input type="text" class="form-control" id="title" name="title" value="{{ old('title') }}" placeholder="Enter post title">
        </div>

        <div class="mb-3">
            <label for="content" class="form-label">Content</label>
            <textarea class="form-control" id="content" name="body" rows="5" placeholder="Enter post content">{{ old('content') }}</textarea>
        </div>

        <div class="mb-3">
            <label for="image" class="form-label">Post Image</label>
            <input type="file" class="form-control" id="image" name="image">
        </div>

        <button type="submit" class="btn btn-primary">Create Post</button>
    </form>
</div>
@endsection

dan create file edit.blade.php di folder views dan isi code menjadi berikut:

@extends('layout')

@section('title', 'Edit Post')

@section('content')
<div class="container mt-5">
    <h2 class="mb-4">Edit Post</h2>

    @if ($errors->any())
        <div class="alert alert-danger">
            <ul>
                @foreach ($errors->all() as $error)
                    <li>{{ $error }}</li>
                @endforeach
            </ul>
        </div>
    @endif

    <form action="{{ route('posts.update', $post->id) }}" method="POST" enctype="multipart/form-data">
        @csrf
        @method('PUT')

        <div class="mb-3">
            <label for="title" class="form-label">Post Title</label>
            <input type="text" class="form-control" id="title" name="title" value="{{ old('title', $post->title) }}" placeholder="Enter post title">
        </div>

        <div class="mb-3">
            <label for="content" class="form-label">Content</label>
            <textarea class="form-control" id="content" name="body" rows="5">{{ old('content', $post->body) }}</textarea>
        </div>

        <div class="mb-3">
            <label for="image" class="form-label">Post Image</label>
            <input type="file" class="form-control" id="image" name="image">
            @if ($post->image)
                <div class="mt-3">
                    <img src="{{ asset('images/' . $post->image) }}" alt="Post Image" class="img-thumbnail" style="width: 150px;">
                </div>
            @endif
        </div>
        <button type="submit" class="btn btn-primary">Update Post</button>
    </form>
</div>
@endsection

Karena di file create dan edit tadi kita extends layout, maka di folder resource/views, buat file php dengan nama layout.blade.php sebagai template dan isikan code berikut:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@yield('title', 'CRUD Posts')</title>

    <!-- Tambahkan Bootstrap CSS atau styling lainnya -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
</head>
<body>

    <!-- Navbar -->
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
        <a class="navbar-brand" href="{{ route('posts.index') }}">My Blog</a>
        <div class="collapse navbar-collapse">
            <ul class="navbar-nav mr-auto">
                <li class="nav-item">
                    <a class="nav-link" href="{{ route('posts.index') }}">Posts</a>
                </li>
                <li class="nav-item">
                    <a class="nav-link" href="{{ route('posts.create') }}">Create New Post</a>
                </li>
            </ul>
        </div>
    </nav>

    <!-- Main Content -->
    <div class="container mt-5">
        @if (session('success'))
            <div class="alert alert-success">
                {{ session('success') }}
            </div>
        @endif

        @yield('content')
    </div>

    <!-- Tambahkan Bootstrap JS atau script lainnya -->
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>
</body>
</html>

5. Routing

Tambahkan route di routes/web.php:
 

use App\Http\Controllers\PostController;

Route::resource('posts', PostController::class);

Setelah itu, silahkan akses https://localhost/posts dan hasilnya sebagai berikut: