Laravel 10 : Membuat CRUD Sederhana dan Upload Photo

Laravel 10 : Membuat CRUD Sederhana dan Upload Photo

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

Persiapan Database

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

Database Seeder

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=

 

Model

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';
}

 

Controller

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)
    {
        
    }


}

 

Route

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 ...

 

Blade View

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>

 

Read Data Customer

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>&nbsp;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>&nbsp;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

 

Create dan Update Data

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

 

Hapus Data

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