Membuat fitur upload image adalah sesuatu yang sangat menarik dan menantang untuk dipelajari bagi Programmer pemula. Karena saat mempelajari upload image ada banyak hal yang sering kali perlu diperhatikan, misal: permission tempat penyimpanan image, limitasi upload dari web server, resize image dan sebagainya.
Nah, pada kesempatan ini kita akan membahas tentang Membuat Fitur Upload Image di Laravel 9 yang sekaligus digabung dengan Create-Read data dari sebuah tabel database.
Namun sebelum membahas lebih lanjut, saya asumsikan bahwa Anda telah menginstall project laravel dari awal dan juga telah melakukan konfigurasi database. Jika belum, Anda dapat mengikuti Tutorial Instalasi Laravel 9 yang telah diposting sebelumnya.
Step 1 - Membuat Model dan Migration
Buat Mode dan Migration dengan satu perintah seperti berikut:
php artisan make:model Product -m
Ubah file migration database/migrations/xxxxx_create_products_table.php
menjadi seperti berikut:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('sku')->index();;
$table->string('name');
$table->decimal('price', 15, 2)->nullable();
$table->integer('stock')->default(0);
$table->string('image')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('products');
}
};
Kita akan menyimpan informasi letak image disimpan pada field image
dalam tabel products
tersebut.
Ubah model Product
(app/Models/Product.php) menjadi seperti berikut:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
use HasFactory;
protected $fillable = [
'sku',
'name',
'price',
'stock',
'image',
];
}
Selanjutnya, jalankan migrasi database dengan perintah:
php artisan migrate
Step 2 - Membuat Controller
Buat ProductController
resource dengan perintah:
php artisan make:controller ProductController -r
Perintah di atas akan membuat file app/Http/Controllers/ProductController.php
yang di dalamnya terdapat method: index
, create
, store
, show
, edit
, update
, dan destroy
.
Step 3 - Membuat Route
Buat routing (routes/web.php
) yang akan mengarahkan ke method-method yang ada pada ProductController
:
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ProductController;
Route::get('products', [ProductController::class, 'index'])->name('products.index');
Route::get('products/create', [ProductController::class, 'create'])->name('products.create');
Route::post('products', [ProductController::class, 'store'])->name('products.store');
Step 4 - Membuat Validasi dengan Form Request
Kita akan membuat validasi dengan Form Request untuk StoreProductRequest
dengan perintah:
php artisan make:request StoreProductRequest
Update file app/Http/Requests/StoreProductRequest.php
menjadi seperti berikut:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreProductRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, mixed>
*/
public function rules()
{
return [
'sku' => ['required', 'unique:products', 'max:100'],
'name' => ['required', 'max:100'],
'price' => ['required', 'numeric', 'min:1'],
'stock' => ['required', 'numeric', 'min:0'],
'image' => 'required|image|mimes:jpeg,png,jpg|max:2048',
];
}
}
Pada rules validation di atas terdapat validasi untuk inputan image yang mana image yang di upload harus berekstensi jpeg
, png
, atau jpg
dengan ukuran maksimal 2MB.
Step 5 - Membuat Form Create Produk
Buat form sederhana untuk create produk dan simpan pada resources/views/products/create.blade.php
:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My App</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous">
</head>
<body>
<div id="app">
<div class="main-wrapper">
<div class="main-content">
<div class="container">
<form method="post" action="{{ route('products.store') }}" enctype="multipart/form-data">
@csrf
<div class="card mt-5">
<div class="card-header">
<h3>New Product</h3>
</div>
<div class="card-body">
@if ($errors->any())
<div class="alert alert-danger">
<div class="alert-title"><h4>Whoops!</h4></div>
There are some problems with your input.
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
@if (session('success'))
<div class="alert alert-success">{{ session('success') }}</div>
@endif
@if (session('error'))
<div class="alert alert-danger">{{ session('error') }}</div>
@endif
<div class="mb-3">
<label class="form-label">SKU</label>
<input type="text" class="form-control" name="sku" value="{{ old('sku') }}" placeholder="#SKU">
</div>
<div class="mb-3">
<label class="form-label">Name</label>
<input type="text" class="form-control" name="name" value="{{ old('name') }}" placeholder="Name">
</div>
<div class="mb-3">
<label class="form-label">Price</label>
<input type="text" class="form-control" name="price" value="{{ old('price') }}" placeholder="Price">
</div>
<div class="mb-3">
<label class="form-label">Stock</label>
<input type="text" class="form-control" name="stock" value="{{ old('stock') }}" placeholder="Stock">
</div>
<div class="mb-3">
<label for="formFile" class="form-label">Image</label>
<input class="form-control" type="file" name="image" id="formFile">
</div>
</div>
<div class="card-footer">
<button class="btn btn-primary" type="submit">Create</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</body>
</html>
Kemudian update method create
pada ProductController
menjadi seperti berikut:
public function create()
{
return view('products.create');
}
Tampilan form create produk:
Step 6 - Membuat Fungsi Store Produk dengan Upload Image
Ini adalah proses menyimpan input dari form produk ke dalam tabel products
di database. Proses ini akan dihandle oleh method store
yang ada di dalam ProductController
. Pertama, kita perlu melakukan validasi input dengan StoreProductRequest
yang telah kita buat di atas. Kemudian, jika inputan tersebut lolos validasi maka langkah selanjutnya adalah proses upload image ke directory yang ada di server/aplikasi kita dalam hal ini adalah public/images
. Kode program method store
akan menjadi seperti berikut:
public function store(StoreProductRequest $request)
{
$imageName = time().'.'.$request->image->extension();
$uploadedImage = $request->image->move(public_path('images'), $imageName);
$imagePath = 'images/' . $imageName;
$params = $request->validated();
if ($product = Product::create($params)) {
$product->image = $imagePath;
$product->save();
return redirect(route('products.index'))->with('success', 'Added!');
}
}
Kita ada beberapa pilihan untuk tujuan penyimpanan image/file di Laravel yaitu di public
folder, storage
folder dan s3
.
Upload ke Public Folder
Contoh di atas adalah kode program untuk upload ke public
folder dengan membuat sub folder bernama images
yaitu baris kode berikut:
$request->image->move(public_path('images'), $imageName);
// public/images/image_name.png
Upload ke Storage Folder
Kode program untuk upload image ke storage
folder adalah seperti berikut:
$request->image->storeAs('images', $imageName);
// storage/app/images/image_name.png
Namun ada catatan yaitu jika kita ingin menampilkan gambar yang disimpan pada storage
folder ini, kita perlu membuat symbolic link
dengan cara seperti berikut:
php artisan storage:link
Upload ke S3
Laravel juga memberikan kemudahan bagi kita untuk menyimpan image yang di upload ke layanan cloud storage yang mendukung protocol S3
. Kode programnya adalah seperti berikut:
$request->image->storeAs('images', $imageName, 's3');
Tentu dengan pengaturan credential yang dibutuhkan diantaranya AccessID
, AccessSecret
dan BucketName
.
Step 7 - Membuat Fungsi Read / List Produk
Untuk menampilkan data produk ini akan dihandle oleh method index
dalam ProductController
dengan kode program seperti berikut:
public function index()
{
$products = Product::all();
return view('products.index', ['products' => $products]);
}
Pertama, panggil Product::all()
untuk melakukan query mengambil semua data dalam tabel products
. Selanjutnya data tersebut akan di assign sebagai parameter pada saat render view resources/views/products/index.blade.php
.
Adapun kode program untuk index.blade.php
adalah seperti berikut:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My App</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous">
</head>
<body>
<div id="app">
<div class="main-wrapper">
<div class="main-content">
<div class="container">
<div class="card mt-5">
<div class="card-header">
<h3>List Product</h3>
</div>
<div class="card-body">
@if (session('success'))
<div class="alert alert-success">{{ session('success') }}</div>
@endif
@if (session('error'))
<div class="alert alert-danger">{{ session('error') }}</div>
@endif
<p>
<a class="btn btn-primary" href="{{ route('products.create') }}">New Product</a>
</p>
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>Image</th>
<th>ID</th>
<th>SKU</th>
<th>Name</th>
<th>Price</th>
<th>Stock</th>
</tr>
</thead>
<tbody>
@forelse ($products as $product)
<tr>
<td><img src="{{ asset($product->image) }}" class="img-thumbnail" style="width:200px" /></td>
<td>{{ $product->id }}</td>
<td>{{ $product->sku }}</td>
<td>{{ $product->name }}</td>
<td>{{ $product->price }}</td>
<td>{{ $product->stock }}</td>
</tr>
@empty
<tr>
<td colspan="6">
No record found!
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
Jika tidak ada permasalahan saat upload image, maka tampilan list produk harusnya menyertakan image seperti berikut:
Download Source Code
Source code lengkap dapat di download dari github: https://github.com/gieart87/tutorial-laravel9/tree/feature/laravel9-crud-with-upload-image
Anda tertantang untuk membuat fitur upload image? Selamat mencoba!
Tulis Komentar