Dgitalin

Belajar CRUD lengkap dengan fitur upload gambar di Laravel 10

Samsul Arifin
September 23, 2024
Belajar CRUD lengkap dengan fitur upload gambar di Laravel 10

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:

Bagikan Artikel: