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
Posting Komentar