sobatcoding.com - Tutorial membuat CRUD sederhana menggunakan Laravel 10
Setelah sebelumnya kita belajar cara install Laravel 10 menggunakan composer, kali ini kita akan mencoba membuat CRUD sederhana menggunakan DataTable untuk tampilan list datanya dan Jquery FormValidate untuk validasi form.
Langsung saja kita coba langkah langkah berikut
Pertama kita buat dahulu database bernama laravel10 atau kalian bisa buat dengan nama yang lain. Kemudian kita buat table bernama customers menggunakan migration milik Laravel dengan perintah php artisan make:migration
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('customers', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('address');
$table->string('avatar')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('customers');
}
};
Setelah selesai kalian bisa migrasi menggunakan perintah php artisan migrate
Selanjutnya kita akan mencoba insert data dummy ke dalam table tersebut menggunakan database seeder. Database seeder ini sangat berguna untuk test aplikasi menggunakan data dummy. Pertama kalian jalankan perintah
php artisan make:seeder CustomerSeeder
Buka file CustomerSeeder.php yang ada di folder app\database\seeders. Kemudian tambahkan kode seperti berikut.
<?php
namespace Database\Seeders;
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use App\Models\Customer;
class CustomerSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
Customer::factory()->count(50)->create();
}
}
Kode di atas artinya kita aakan membuat 50 data dummy insert ke dalam tabel Customer.
Selanjutnya buka file DatabaseSeeder.php, dan tambahkan kode berikut
<?php
namespace Database\Seeders;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*/
public function run(): void
{
$this->call([
CustomerSeeder::class,
]);
}
}
Selanjutnya kalian jalankan database seeder menggunakan perintah
php artisan db:seed
Jangan lupa untuk setting koneksi database di file .env
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel10
DB_USERNAME=root
DB_PASSWORD=
Kita buat model bernama Customer menggunakan perintah php artisan make:model Customer
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Customer extends Model
{
use HasFactory;
protected $table = 'customers';
}
Selanjutnya buat controller bernama CustomerController.php menggunakan perintah php artisan make:controller CustomerController
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use App\Models\Customer;
class CustomerController extends Controller
{
public function index(Request $request)
{
}
public function show($customer)
{
}
public function create(Request $request)
{
}
public function edit($customer, Request $request)
{
}
public function store(Request $request)
{
}
public function update($customer, Request $request)
{
}
public function destroy($customer, Request $request)
{
}
}
Selanjutnya kita buat route untuk customer. Silahkan kalian buka file routes.php, kemudian tambahkan kode berikut ke dalam file tersebut
use App\Http\Controllers\CustomerController;
Route::resource('customers', CustomerController::class);
Route::post('customers/{customer}', [CustomerController::class, 'update']);
Kita tambahkan juga untuk route POST fungsinya nanti untuk proses update. Kenapa tidak memakai bawaan Laravel method PATCH karena method ini agak susah admin untuk implementasi menggunakan AJAX. He he he ...
Selanjutnya kita buat blade view bernama layout.blade.php di folder views/customer. Blade ini digunakan sebagai layout app nantinya
<!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', 'Laravel 10')</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<link href="https://cdn.datatables.net/1.13.4/css/jquery.dataTables.min.css" rel="stylesheet" >
</head>
<body>
<nav class="navbar navbar-light bg-light">
<div class="container-fluid">
<a class="navbar-brand" href="#">
<img src="https://laravel.com/img/logomark.min.svg" alt="" width="30" height="24" class="d-inline-block align-text-top">Laravel 10</a>
</div>
</nav>
<div class="container-fluid">
@yield('content')
</div>
<script src="https://code.jquery.com/jquery-3.6.4.min.js" integrity="sha256-oP6HI9z1XaZNBrJURtCoUT5SUnxFr8s3BzRl+cbzUq8=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.5/jquery.validate.min.js" integrity="sha512-rstIgDs0xPgmG6RX1Aba4KV5cWJbAMcvRCVmglpam9SoHZiUCyQVDdH2LPlxoHtrv17XWblE/V/PP+Tr04hbtA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
<script src="https://cdn.datatables.net/1.13.4/js/jquery.dataTables.min.js" ></script>
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
@yield('js')
</body>
</html>
Kali ini kita buat tampilan list data berbentuk datatable. Kita buat dahulu method index di CustomerController
public function index(Request $request)
{
//request ajax di akses oleh datatable
if($request->ajax()){
$table = Customer::get();
return response()->json(['data' => $table]);
}
return view('customer.index');
}
Buatlah blade untuk view menampilkan data ke dalam datatable
@extends('customer.layout')
@section('content')
<div class="card">
<div class="card-header">Data Pelanggan</div>
<div class="card-body">
<a href="{{ route('customers.create') }}" class="btn btn-primary mb-2">Tambah Data</a>
<table id="table" class="table table-striped" style="width:100%">
<thead class="table-active">
<tr>
<th>NO</th>
<th>AVATAR</th>
<th>NAMA</th>
<th>ALAMAT</th>
<th>ACTION</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
</div>
@endsection
@section('js')
<script>
$(document).ready(function(e) {
initDataTable();
async function initDataTable()
{
$('#table').DataTable({
processing: true,
serverSide: false,
ajax: "{{ route('customers.index') }}",
destroy: true,
language: {
searchPlaceholder: "Masukkan keywords disni ...",
emptyTable: "Data kosong"
},
columns: [
{data: 'id', name: 'id', render : function ( data, type, row, meta ) {
return meta.row+1;
}},
{data: 'avatar', name: 'avatar', render : function ( data, type, row, meta ) {
return '<img src="'+ ( data != null ? '{{ url('/') }}/' + data : 'https://placehold.co/64x64?text=AVATAR' ) +'" class="rounded-circle" alt="'+ row.name +'" width="64"/>';
}},
{data: 'name', name: 'name'},
{data: 'address', name: 'address'},
{data: 'id', name: 'action', orderable: false, render: function( data, type, row, meta) {
let btnAction = '<a class="btn btn-default edit" href="{{ url('customers') }}/'+ data +'/edit"><svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-edit" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M7 7h-1a2 2 0 0 0 -2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2 -2v-1"></path><path d="M20.385 6.585a2.1 2.1 0 0 0 -2.97 -2.97l-8.415 8.385v3h3l8.385 -8.415z"></path><path d="M16 5l3 3"></path></svg> Edit</a>';
btnAction += '<button class="btn btn-danger delete" data-url="{{ url('customers') }}/'+ data +'"><svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-trash-x" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M4 7h16"></path><path d="M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2 -2l1 -12"></path><path d="M9 7v-3a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v3"></path><path d="M10 12l4 4m0 -4l-4 4"></path></svg> Hapus</button>';
return '<div class="btn-group" >'+ btnAction +'</div>';
}},
],
columnDefs: [
{ "width": "5%", "targets": 0 },
{ "width": "10%", "targets": 1 },
{ "width": "15%", "targets": 2 },
{ "width": "12%", "targets": 4 },
],
});
}
})
</script>
@endsection
Tambahkan method untuk create dan edit data
public function create(Request $request)
{
return view('customer.form');
}
public function edit($customer, Request $request)
{
$data = Customer::findOrFail($customer);
return view('customer.form', compact('data'));
}
public function store(Request $request)
{
$validator = Validator::make($request->all(), [
'name' => 'required',
'address' => 'required',
],
[
'required' => ':attribute harus diisi',
]);
if ($validator->fails()) {
return response()->json(['success' => false, 'message' => $validator->errors()->first(), 422]);
}
$update = new Customer;
$update->name = $request->get('name');
$update->address = $request->get('address');
$update->save();
return response()->json(['success' => true, 'message' => 'Data pelanggan berhasil ditambahkan']);
}
public function update($customer, Request $request)
{
$validator = Validator::make($request->all(), [
'name' => 'required',
'address' => 'required',
],
[
'required' => ':attribute harus diisi',
]);
if ($validator->fails()) {
return response()->json(['success' => false, 'message' => $validator->errors()->first(), 422]);
}
$update = Customer::findOrFail($customer);
$update->name = $request->get('name');
$update->address = $request->get('address');
$update->save();
}
Untuk upload photo menggunakan Laravel tambahkan kode berikut
if($request->file('photo')){
$file= $request->file('photo');
if( in_array($file->getMimeType(), ['image/jpeg', 'image/png', 'image/gif']) ) //validate image
{
$filename= date('YmdHis')."_". Str::slug($update->name) . "." . $file->getClientOriginalExtension();
$file->move(public_path('avatars'), $filename);
Customer::where('id', $update->id)->update([ 'avatar' => "avatars/". $filename ]);
}
}
Selanjutnya buatlah blade view form seperti berikut
@extends('customer.layout')
@section('content')
<style>
.img-wrapper {
width: 140px;
height:140px;
background: url('https://placehold.co/140x140?text=AVATAR');
background-repeat:no-repeat;
background-size: cover;
background-position: center;
}
</style>
<div class="card">
<div class="card-header">{{ isset($data) ? 'Edit' : 'Tambah' }} Pelanggan</div>
<div class="card-body">
<form id="formCustomer" method="POST" action="{{ isset($data) ? route('customers.update', ['customer' => $data->id]) : route('customers.store') }}">
@csrf
<div class="row">
<div class="col-auto">
<div id="image-avatar" class="img-wrapper"></div>
<input type="file" id="pickPhoto" name="photo" accept="image/jpeg,image/png,image/gif"/>
</div>
<div class="col">
<div class="mb-2">
<label for="inputNama" class="form-label">Nama</label>
<input type="text" class="form-control" id="inputName" name="name" autocomplete="off" value="{{ $data->name ?? '' }}" required >
</div>
<div class="mb-2">
<label for="inputAddress" class="form-label">Alamat</label>
<input type="text" class="form-control" id="inputAddress" name="address" autocomplete="off" value="{{ $data->address ?? '' }}" required >
</div>
<div class="mb-2">
<button type="submit" class="btn btn-primary">SIMPAN</button>
</div>
</div>
</div>
</form>
</div>
</div>
@endsection
Untuk validasi form menggunakan Jquery Validation, tambahkan kode berikut
@section('js')
<script>
$(document).ready(function(e) {
//display image before upload
$(document).on('change', '#pickPhoto', function(e) {
var file = $(this)[0].files[0];
var exts = ["image/png", "image/jpg", "image/jpeg"];
var max = 1024 * 1024;
//validasi image
if( !exts.includes(file.type) )
{
alert("File must be an image. JPG OR PNG");
return false;
}
//validasi image size
if( file.size > max)
{
alert("File not large than 1 MB");
return false;
}
if (file) {
var reader = new FileReader();
reader.onload = function(e) {
var image = new Image();
image.src = e.target.result;
image.onload = function() {
$("#image-avatar").css("background-image", "url(" + this.src + ")");
$("#image-avatar").css("background-position", "center");
$("#image-avatar").css("background-size", "cover");
$("#image-avatar").css("background-repeat", "no-repeat");
};
}
reader.readAsDataURL(file);
} else {
alert('select a file to see preview');
$('#pickPhoto').val('');
$("#image-avatar").css("background", "url('https://placehold.co/140x140?text=AVATAR')");
}
});
//validasi form
$("#formCustomer").validate({
rules : {
name : "required",
address: "required",
},
messages : {
name : {
required : 'Nama harus diisi'
},
address : {
required : 'Alamat harus diisi'
}
},
errorPlacement: function(label, element) {
label.addClass('mt-2 invalid-feedback');
label.insertAfter(element);
$(element).removeClass('is-invalid')
},
highlight: function(element, errorClass) {
$(element).addClass('is-invalid')
},
unhighlight: function (element, errorClass, validClass) {
$(element).removeClass('is-invalid');
$(element).addClass('is-valid');
},
submitHandler: function(form) {
let formData = new FormData();
formData.append('_token', '{{ csrf_token() }}');
formData.append('name', $('#inputName').val());
formData.append('address', $('#inputAddress').val());
// Attach file
formData.append('photo', $('input[type=file]')[0].files[0]);
$.ajax({
url : $(form).attr('action'),
method: 'POST',
data: formData,
processData: false,
contentType: false,
beforeSend: function () {
//function here ...
$('button').prop('disabled', true);
},
success: function(response) {
$('button').prop('disabled', false);
console.log(response);
if( response.success == true )
{
Swal.fire({
icon: 'success',
title: 'Berhasil',
text: response.message
}).then((result) => {
if (result.isConfirmed) {
window.location.href = '{{ route('customers.index') }}';
}
})
}
},
error: function (jqXHR, textStatus, errorThrown) {
$('button').prop('disabled', false);
console.log('Message: ' + textStatus + ' , HTTP: ' + errorThrown );
},
})
return false;
}
});
})
</script>
@endsection
Untuk hapus data tambahkan method destroy ke dalam controller CustomerController
public function destroy($customer, Request $request)
{
Customer::where('id', $customer)->delete();
return response()->json(['success' => true, 'message' => 'Data pelanggan berhasil dihapus']);
}
Karena kita menggunakan Ajax, tambahkan javascript di file index.blade.php
$(document).on('click', '.delete', function(e) {
let deleteUrl = $(this).attr('data-url');
Swal.fire({
icon: 'info',
title: 'Anda yakin?',
text: 'Tindakan ini bisa mengakibatkan data hilang secara permanen',
showCancelButton: true,
confirmButtonColor: '#3085d6',
cancelButtonColor: '#d33',
confirmButtonText: 'Ya, hapus sekarang',
cancelButtonText: 'Batal'
}).then((result) => {
if (result.isConfirmed) {
let formData = new FormData();
formData.append('_token', '{{ csrf_token() }}');
formData.append('_method', 'DELETE');
$.ajax({
url : deleteUrl,
method: 'POST',
data: formData,
processData: false,
contentType: false,
beforeSend: function () {
//function here ...
$('button').prop('disabled', true);
},
success: function(response) {
$('button').prop('disabled', false);
console.log(response);
if( response.success == true )
{
Swal.fire({
icon: 'success',
title: 'Berhasil',
text: response.message
}).then((result) => {
if (result.isConfirmed) {
initDataTable();
}
})
}
},
error: function (jqXHR, textStatus, errorThrown) {
$('button').prop('disabled', false);
console.log('Message: ' + textStatus + ' , HTTP: ' + errorThrown );
},
})
}
})
return false;
})
Untuk hasil kurang lebih seperti berikut
Untuk source code bisa kalian unduh di akun github sobatcoding : https://github.com/sobatcoding21/Laravel10
Demikian tutorial kali ini. Semoga bermanfaat
Komentar 0