Langsung ke konten utama

Langkah-langkah untuk Membuat Tabel Database dan CRUD Produk Menggunakan Laravel

Membuat 3 Tabel Database Menggunakan Laravel Migrations

1. Tabel Customers
  • jalankan perintah berikut
     php artisan make:migration create_customers_table
  • Buka file migration yang baru dibuat di database/migrations/.
  • Tambahkan kode berikut di dalam metode up():
public function up(): void
    {
        Schema::create('customers', function (Blueprint $table) {
            $table->id(); // BIGINT UNSIGNED AUTO_INCREMENT PRIMARY
            $table->string('name');
            $table->string('email')->unique();
            $table->text('address')->nullable();
            $table->timestamps(); // created_at & updated_at (nullable by default)
        });
    }

2. Tabel Orders
  • jalankan perintah berikut
php artisan make:migration create_orders_table
  • Buka file migration yang baru dibuat di database/migrations/.
  • Tambahkan kode berikut di dalam metode up():
public function up(): void
    {
        Schema::create('orders', function (Blueprint $table) {
            $table->id();
            $table->foreignId('customer_id')->constrained('customers');
            $table->date('order_date');
            $table->decimal('total_amount', 10, 2)->default(0.00);
            $table->enum('status',
            ['pending', 'processing', 'completed', 'cancelled'])->default('pending');
            $table->timestamps();
        });
    }

3. Tabel Order Details
  • jalankan perintah berikut
php artisan make:migration create_orders_details_table
  • Buka file migration yang baru dibuat di database/migrations/.
  • Tambahkan kode berikut di dalam metode up():
public function up(): void
    {
        Schema::create('order_details', function (Blueprint $table) {  
            $table->id();
            $table->foreignId('order_id')->constrained('orders');
            $table->foreignId('product_id')->constrained('products');
            $table->unsignedInteger('quantity')->default(1);
            $table->decimal('unit_price', 10, 2);
            $table->decimal('subtotal', 10, 2);
            $table->timestamps();
        });
    }

3. Jalankan Migration
  • Jalankan perintah berikut di Terminal untuk membuat Tabel :
php artisan migrate


CRUD Tabel Products Menggunakan FluxUi

  • Buka file routes/web.php
  • Tambahkan route untuk produk:
Route::group(['prefix' => 'dashboard', 'middleware' => ['auth', 'verified']], function() {
    Route::get('/', [DashboardController::class, 'index'])->name('dashboard');
    // Route untuk kategori
    Route::resource('categories', ProductCategoryController::class);
    Route::get('products',[DashboardController::class,'products'])->name('products');
    // Route resource untuk produk
    Route::resource('products', ProductController::class);
});
  • Jalankan perintah berikut di Terminal untuk membuat Model dan Controller:
php artisan:model Product
php artisan:controller ProductController --resource
  • Buka file app/Http/Controllers/ProductController.php
  • Tambahkan kode berikut:
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Product; // Gunakan Product, bukan Products
use App\Models\Categories;
use Illuminate\Support\Facades\Storage;

class ProductController extends Controller
{
    /**
     * GET: dashboard/products
     * Menampilkan daftar produk.
     */
    public function index(Request $request)
    {
    $q = $request->q;

        // Mengambil produk dan memuat relasi kategori
        $products = Product::with('category')
                        ->where('name', 'like', '%' . $q . '%')
                        ->orWhere('description', 'like', '%' . $q . '%')
                        ->paginate(10);

        return view('dashboard.products.index', compact('products', 'q'));
       
    }

    public function create()
    {
        $categories = Categories::all();

        return view('dashboard.products.create', compact('categories'));
    }
   

    public function show(string $id)
    {
        $products = Product::find($id);
    }

    public function edit($id)
    {
        $product = Product::findOrFail($id);
        $categories = Categories::all();

        return view('dashboard.products.edit', compact('product', 'categories'));
    }

    /**
     * POST: dashboard/products
     * Menyimpan produk baru.
     */
    public function store(Request $request)
    {
        // Validasi input
        $validated = $request->validate([
            'product_category_id' => 'nullable|exists:product_categories,id',
            'name' => 'required|string|max:255',
            'description' => 'nullable|string',
            'price' => 'required|numeric|min:0',
            'stock' => 'required|integer|min:0',
            'image' => 'nullable|image|mimes:jpg,jpeg,png|max:2048',
        ]);

        // Membuat produk baru
        $product = new Product; // Gunakan Product, bukan Products
        $product->product_category_id = $request->product_category_id;
        $product->name = $request->name;
        $product->description = $request->description;
        $product->price = $request->price;
        $product->stock = $request->stock;

        if ($request->hasFile('image')) {
            $image = $request->file('image');
            $imageName = time() . '_' . $image->getClientOriginalName();
            $imagePath = $image->storeAs('uploads/products', $imageName, 'public');
            $product->image = $imagePath;
        }

        $product->save();

        return redirect()->back()
            ->with('successMessage', 'Product Berhasil Disimpan');
    }

    /**
     * PUT/PATCH: dashboard/products/{product}
     * Memperbarui produk yang ada.
     */
    public function update(Request $request, string $id)
    {
        // Validasi input
        $validated = $request->validate([
            'product_category_id' => 'nullable|exists:product_categories,id',
            'name' => 'required|string|max:255',
            'description' => 'nullable|string',
            'price' => 'required|numeric|min:0',
            'stock' => 'required|integer|min:0',
            'image' => 'nullable|image|mimes:jpg,jpeg,png|max:2048',
        ]);

        $product = Product::find($id); // Gunakan Product, bukan Products
        $product->product_category_id = $request->product_category_id;
        $product->name = $request->name;
        $product->description = $request->description;
        $product->price = $request->price;
        $product->stock = $request->stock;

        if ($request->hasFile('image')) {
            $image = $request->file('image');
            $imageName = time() . '_' . $image->getClientOriginalName();
            $imagePath = $image->storeAs('uploads/products', $imageName, 'public');
            $product->image = $imagePath;
        }

        $product->save();

        return redirect()->back()
            ->with('successMessage', 'Product Berhasil Diperbarui');
    }

    /**
     * DELETE: dashboard/products/{product}
     * Menghapus produk.
     */
    public function destroy(string $id)
    {
        $product = Product::find($id); // Gunakan Product, bukan Products

        $product->delete();

        return redirect()->back()
            ->with('successMessage', 'Data Berhasil Dihapus');
    }
}
  • Buka file app/Models/Product.php
  • Tambahkan kode berikut:
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use App\Models\Categories;


class Product extends Model
{
    use HasFactory;

    protected $table = 'products';

        // Definisikan relasi belongsTo dengan Category
    public function category()
    {
        return $this->belongsTo(Categories::class, 'product_category_id');
    }

}
  • Buat View untuk Tabel Product
  • Buka file Components/Views/Dashboard/Products/index.blade.php 
  • Tambahkan kode berikut :
<x-layouts.app :title="__('Products')">
    <div class="relative mb-6 w-full">
        <flux:heading size="xl">Products</flux:heading>
        <flux:subheading size="lg" class="mb-6">Manage Product Data</flux:subheading>
        <flux:separator variant="subtle" />
    </div>

    <div class="flex justify-between items-center mb-4">
        <div>
            <form action="{{ route('products.index') }}" method="get">
                @csrf
                <flux:input icon="magnifying-glass" name="q" value="{{ $q ?? '' }}" placeholder="Search Product" />
            </form>
        </div>
        <div>
            <flux:button icon="plus">
                <flux:link href="{{ route('products.create') }}" variant="subtle">Add New Product</flux:link>
            </flux:button>
        </div>
    </div>

    @if(session()->has('successMessage'))
        <flux:badge color="lime" class="mb-3 w-full">{{ session()->get('successMessage') }}</flux:badge>
    @endif

    <div class="overflow-x-auto">
        <table class="min-w-full leading-normal table-auto">
            <thead>
                <tr>
                    <th class="px-5 py-3 border-b-2 border-gray-200 bg-gray-100 text-left text-xs font-semibold text-gray-600 uppercase tracking-wider">No</th>
                    <th class="px-5 py-3 border-b-2 border-gray-200 bg-gray-100 text-left text-xs font-semibold text-gray-600 uppercase tracking-wider">Image</th>
                    <th class="px-5 py-3 border-b-2 border-gray-200 bg-gray-100 text-left text-xs font-semibold text-gray-600 uppercase tracking-wider">Name</th>
                    <th class="px-5 py-3 border-b-2 border-gray-200 bg-gray-100 text-left text-xs font-semibold text-gray-600 uppercase tracking-wider">Category</th>
                    <th class="px-5 py-3 border-b-2 border-gray-200 bg-gray-100 text-left text-xs font-semibold text-gray-600 uppercase tracking-wider">Description</th>
                    <th class="px-5 py-3 border-b-2 border-gray-200 bg-gray-100 text-left text-xs font-semibold text-gray-600 uppercase tracking-wider">Price</th>
                    <th class="px-5 py-3 border-b-2 border-gray-200 bg-gray-100 text-left text-xs font-semibold text-gray-600 uppercase tracking-wider">Stock</th>
                    <th class="px-5 py-3 border-b-2 border-gray-200 bg-gray-100 text-left text-xs font-semibold text-gray-600 uppercase tracking-wider">Created At</th>
                    <th class="px-5 py-3 border-b-2 border-gray-200 bg-gray-100 text-left text-xs font-semibold text-gray-600 uppercase tracking-wider">Actions</th>
                </tr>
            </thead>

            <tbody>
                @foreach($products as $key => $product)
                    <tr class="bg-white hover:bg-gray-50 transition duration-150">
                        <td class="px-5 py-5 border-b border-gray-200 text-sm">{{ $key + 1 }}</td>
                        <td class="px-5 py-5 border-b border-gray-200 text-sm">
                            @if($product->image)
                                <img src="{{ Storage::url($product->image) }}" alt="{{ $product->name }}" class="h-10 w-10 object-cover rounded">
                            @else
                                <div class="h-10 w-10 bg-gray-200 flex items-center justify-center rounded">
                                    <span class="text-gray-500 text-sm">N/A</span>
                                </div>
                            @endif
                        </td>
                        <td class="px-5 py-5 border-b border-gray-200 text-sm">{{ $product->name }}</td>
                        <td class="px-5 py-5 border-b border-gray-200 text-sm">
                            {{ $product->category ? $product->category->name : 'No Category' }}
                        </td>
                        <td class="px-5 py-5 border-b border-gray-200 text-sm">{{ \Illuminate\Support\Str::limit($product->description, 50) }}</td>
                        <td class="px-5 py-5 border-b border-gray-200 text-sm">Rp {{ number_format($product->price, 0, ',', '.') }}</td>
                        <td class="px-5 py-5 border-b border-gray-200 text-sm">{{ $product->stock }}</td>
                        <td class="px-5 py-5 border-b border-gray-200 text-sm">{{ $product->created_at }}</td>
                        <td class="px-5 py-5 border-b border-gray-200 text-sm">
                            <flux:dropdown>
                                <flux:button icon:trailing="chevron-down">Actions</flux:button>
                                <flux:menu>
                                    <flux:menu.item icon="pencil" href="{{ route('products.edit', $product->id) }}">Edit</flux:menu.item>
                                    <flux:menu.item
                                        icon="trash"
                                        variant="danger"
                                        onclick="event.preventDefault(); if(confirm('Are you sure you want to delete this product?')) document.getElementById('delete-form-{{ $product->id }}').submit();">
                                        Delete
                                    </flux:menu.item>

                                    <form id="delete-form-{{ $product->id }}" action="{{ route('products.destroy', $product->id) }}" method="POST" style="display: none;">
                                        @csrf
                                        @method('DELETE')
                                    </form>
                                </flux:menu>
                            </flux:dropdown>
                        </td>
                    </tr>
                @endforeach
            </tbody>
        </table>

        <div class="mt-3">
            {{ $products->links() }}
        </div>
    </div>
</x-layouts.app>


  • Buka file Components/Views/Dashboard/Products/create.blade.php 
  • Tambahkan kode berikut :
<x-layouts.app :title="__('Tambah Products')">
    <div class="relative mb-6 w-full">
        <flux:heading size="xl">Add New Product</flux:heading>
        <flux:subheading size="lg" class="mb-6">Manage data Product</flux:subheading>
        <flux:separator variant="subtle" />
    </div>

    @if(session()->has('successMessage'))
        <flux:badge color="lime" class="mb-3 w-full">{{ session()->get('successMessage') }}</flux:badge>
    @elseif(session()->has('errorMessage'))
        <flux:badge color="red" class="mb-3 w-full">{{ session()->get('errorMessage') }}</flux:badge>
    @endif

    <form action="{{ route('products.store') }}" method="post" enctype="multipart/form-data">
        @csrf

        <flux:input label="Name" name="name" class="mb-3" />

        <!-- Pindahkan kategori ke bawah Name -->
        <div class="mb-3">
            <label for="product_category_id" class="block text-sm font-medium text-gray-700 mb-1">
                Category
            </label>
            <select
                name="product_category_id"
                id="product_category_id"
                class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring focus:ring-indigo-500 focus:border-indigo-500 text-sm">
                <option value="" disabled selected>Select Category</option>
                @foreach($categories as $category)
                    <option value="{{ $category->id }}">{{ $category->name }}</option>
                @endforeach
            </select>
        </div>

        <flux:textarea label="Description" name="description" class="mb-3" />

        <flux:input label="Price" name="price" class="mb-3" />

        <flux:input label="Stock" name="stock" class="mb-3" />

        <flux:input type="file" label="Image" name="image" class="mb-3" />

        <flux:separator />

        <div class="mt-4">
            <flux:button type="submit" variant="primary">Simpan</flux:button>
            <flux:link href="{{ route('products.index') }}" variant="ghost" class="ml-3">Kembali</flux:link>
        </div>
    </form>
</x-layouts.app>
  • Buka file Components/Views/Dashboard/Products/edit.blade.php 
  • Tambahkan kode berikut :
<x-layouts.app :title="__('Edit Product')">
    <div class="relative mb-6 w-full">
        <flux:heading size="xl">Edit Product</flux:heading>
        <flux:subheading size="lg" class="mb-6">Manage data Product</flux:subheading>
        <flux:separator variant="subtle" />
    </div>

    @if(session()->has('successMessage'))
        <flux:badge color="lime" class="mb-3 w-full">{{ session()->get('successMessage') }}</flux:badge>
    @elseif(session()->has('errorMessage'))
        <flux:badge color="red" class="mb-3 w-full">{{ session()->get('errorMessage') }}</flux:badge>
    @endif

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

        <!-- Product Name -->
        <flux:input label="Name" name="name" value="{{ old('name', $product->name) }}" class="mb-3" />

        <!-- Product Category (Moved below Name) -->
        <div class="mb-3">
            <label for="product_category_id" class="block text-sm font-medium text-gray-700 mb-1">Category</label>
            <select name="product_category_id" id="product_category_id" class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring focus:ring-indigo-500 focus:border-indigo-500 text-sm">
                <option value="" disabled>Select Category</option>
                @foreach($categories as $category)
                    <option value="{{ $category->id }}" {{ $category->id == $product->product_category_id ? 'selected' : '' }}>{{ $category->name }}</option>
                @endforeach
            </select>
        </div>

        <!-- Product Description -->
        <flux:textarea label="Description" name="description" class="mb-3">{{ old('description', $product->description) }}</flux:textarea>

        <!-- Product Price -->
        <flux:input label="Price" name="price" value="{{ old('price', $product->price) }}" class="mb-3" />

        <!-- Product Stock -->
        <flux:input label="Stock" name="stock" value="{{ old('stock', $product->stock) }}" class="mb-3" />

        <!-- Product Image -->
        @if($product->image)
            <div class="mb-3">
                <img src="{{ Storage::url($product->image) }}" alt="{{ $product->name }}" class="w-32 h-32 object-cover rounded">
            </div>
        @endif
        <flux:input type="file" label="Image" name="image" class="mb-3" />

        <flux:separator />

        <div class="mt-4">
            <flux:button type="submit" variant="primary">Update</flux:button>
            <flux:link href="{{ route('products.index') }}" variant="ghost" class="ml-3">Kembali</flux:link>
        </div>
    </form>
</x-layouts.app>

Selanjutnya jalankan project dengan perintah pada terminal :
composer run dev

buka pada browser http://127.0.0.1:8000/dashboard/products dan hasilnya seperti ini :





sekian terimakasih.....




M. Irsyad Fachryanto
23090111 (4D)

Komentar

Postingan populer dari blog ini

Sejarah Bahasa Pemrograman Java

Latar Belakang Sejarah Java Sebagai penggemar pemrograman, Anda mungkin bertanya-tanya, "Apa yang membuat Java menjadi bahasa pemrograman yang begitu istimewa?" Jawabannya terletak dalam sejarah unik dan latar belakang perkembangan bahasa ini. Untuk benar-benar memahami Java, mari kita kembali ke akar-akarnya yang menarik. Dalam awal 1990-an, dunia pemrograman mengalami gebrakan besar. Teknologi terus berkembang, dan perangkat keras semakin canggih. Namun, ada satu masalah yang belum terpecahkan, yaitu kompatibilitas lintas platform. Pada saat itu, bahasa pemrograman yang ada cenderung spesifik untuk sistem operasi dan arsitektur tertentu. Tim pengembang di Sun Microsystems, yang terdiri dari James Gosling, Mike Sheridan, dan Patrick Naughton, menyadari pentingnya mengatasi masalah kompatibilitas ini. Inilah yang memicu kelahiran Java. Mereka memulai proyek OAK, yang kemudian berkembang menjadi bahasa yang kita kenal sebagai Java. Proyek OAK dimulai dengan fokus pada perangka...

Strategi Pemilihan Metodologi

Strategi Pemilihan Metodologi menyoroti pentingnya strategi yang terencana dan terstruktur dalam memilih metodologi yang sesuai untuk proyek pengembangan perangkat lunak. Dalam konteks ini, "metodologi" mengacu pada seperangkat aturan, praktik, dan proses yang digunakan untuk mengelola siklus hidup pengembangan perangkat lunak dari konsepsi hingga pengiriman. Mengapa Ini Penting? Kompleksitas Pengembangan Solusi Lunak: Di era yang semakin kompleks ini, penentuan pendekatan yang sesuai bisa menjadi perbedaan antara sukses dan kegagalan proyek. Dampak pada Efisiensi dan Mutu: Pilihan pendekatan yang tepat dapat meningkatkan efisiensi pengembangan, menjamin penyelesaian proyek tepat waktu, dan meningkatkan mutu perangkat lunak. Kepuasan Pengguna: Dengan penetapan pendekatan yang cocok, tim pengembangan bisa memastikan bahwa kebutuhan dan harapan pengguna terpenuhi dengan baik, meningkatkan kepuasan akhir pengguna. Apa yang Dibahas dalam Artikel Ini? Faktor-Faktor yang Berpengaru...

Translate