Tutorial SAW Laravel 10 + MySQL + Bootstrap 5

Tutorial SAW Laravel

Tutorial SAW Laravel – Tutorial membuat aplikasi Sistem Pendukung Keputusan (SPK) metode Simple Additive Weighting (SAW) berbasis web dengan Laravel 10, MySQL, dan Bootstrap 5.

1. Membuat Project Laravel

Pastikan Anda sudah menginstall composer, kemudian jalankan perintah berikut di command prompt.

composer create-project laravel/laravel laravel-saw

2. Mengatur Database MySQL

Langkah kedua adalah membuat database dengan nama laravel_saw di http://localhost/phpmyadmin jika Anda menginstall XAMPP untuk server MySQL.

Sesuaikan pengaturan koneksi mysql di project laravel pada file .env

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel_saw
DB_USERNAME=root
DB_PASSWORD=

Sesuaikan DB_HOST, DB_PORT, DB_DATABASE, DB_USERNAME, dan DB_PASSWORD sesuai server MySQL.

3. Membuat Migration dan Seeder

Buat 3 buah migration untuk tabel Alternatif, Kriteria, dan Nilai.

php artisan make:migration create_tb_alternatif_table
php artisan make:migration create_tb_kriteria_table
php artisan make:migration create_tb_nilai_table

Atur field setiap table yang ada di database/migrations/[waktu]_create_tb_alternatif_table.php, create_tb_alternatif_table.php, dan create_tb_alternatif_table.php.

<?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('tb_alternatif', function (Blueprint $table) {
            $table->string('id_alternatif', 16)->primary();
            $table->string('nama_alternatif', 255);
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('tb_alternatif');
    }
};
<?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('tb_kriteria', function (Blueprint $table) {
            $table->string('id_kriteria', 16)->primary();
            $table->string('nama_kriteria', 255);
            $table->string('atribut', 16);
            $table->double('bobot');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('tb_kriteria');
    }
};
<?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('tb_nilai', function (Blueprint $table) {
            $table->id('id_nilai');
            $table->string('id_alternatif', 16);
            $table->string('id_kriteria', 16);
            $table->double('nilai', 16);
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('tb_nilai');
    }
};

Isikan data sampel menggunakan seeder di file database/seeders/DatabaseSeeder.php.

<?php

namespace Database\Seeders;

use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     */
    public function run(): void
    {
        DB::table('tb_alternatif')->insert([
            [
                'id_alternatif' => 'A01',
                'nama_alternatif' => 'Alternatif 1',
            ],
            [
                'id_alternatif' => 'A02',
                'nama_alternatif' => 'Alternatif 2',
            ],
            [
                'id_alternatif' => 'A03',
                'nama_alternatif' => 'Alternatif 3',
            ],
        ]);

        DB::table('tb_kriteria')->insert([
            [
                'id_kriteria' => 'C01',
                'nama_kriteria' => 'Kriteria 1',
                'atribut' => 'Benefit',
                'bobot' => 1,
            ],
            [
                'id_kriteria' => 'C02',
                'nama_kriteria' => 'Kriteria 2',
                'atribut' => 'Cost',
                'bobot' => 2,
            ],
            [
                'id_kriteria' => 'C03',
                'nama_kriteria' => 'Kriteria 3',
                'atribut' => 'Benefit',
                'bobot' => 3,
            ],
            [
                'id_kriteria' => 'C04',
                'nama_kriteria' => 'Kriteria 4',
                'atribut' => 'Cost',
                'bobot' => 4,
            ],
        ]);

        DB::statement("INSERT INTO tb_nilai (id_alternatif, id_kriteria, nilai) SELECT id_alternatif, id_kriteria, ROUND(RAND() * 5) FROM tb_alternatif, tb_kriteria");
    }
}

Perintah DB::statement digunakan untuk membuat nilai sejumlah alternatif x kriteria. Perintah ROUND(RAND() * 5) berfungsi untuk mengisi nilai otomatis secara acak antara 0-5.

Jalankan migration dan seeder sekaligus dengan perintah berikut.

php artisan migrate:fresh --seed

Jika berhasil, maka akan ada 3 buah tabel beserta data di server MySQL.

Tabel Alternatif
Tabel Kriteria
Tabel Nilai

4. Membuat Model

Buat model Alternatif, Kriteria, dan Nilai sesuai tabel yang ada di database menggunakan perintah berikut.

php artisan make:model Alternatif
php artisan make:model Kriteria
php artisan make:model Nilai

Model Alternatif

Atur nama tabel dan primary key pada model alternatif yang ada di file app/Models/Alternatif.php.

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Alternatif extends Model
{
    use HasFactory;

    protected $table = 'tb_alternatif';
    protected $primaryKey = 'id_alternatif';
    public $incrementing = false;
}

Model Kriteria

Isikan nama tabel dan primary key pada model kriteria yang ada di file app/Models/Kriteria.php.

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Kriteria extends Model
{
    use HasFactory;

    protected $table = 'tb_kriteria';
    protected $primaryKey = 'id_kriteria';
    public $incrementing = false;
}

Model Nilai

Sesuaikan nama tabel dan primary key pada model nilai yang ada di file app/Models/Nilai.php.

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Nilai extends Model
{
    use HasFactory;

    protected $table = 'tb_nilai';
    protected $primaryKey = 'id_nilai';
}

5. Membuat Controller

Gunakan perintah berikut untuk membuat 5 buah controller yaitu PageController.php, AlternatifController.php, KriteriaController.php, NilaiController.php, dan HitungController.php.

php artisan make:controller PageController
php artisan make:controller AlternatifController --resource --model=Alternatif
php artisan make:controller KriteriaController --resource --model=Kriteria
php artisan make:controller NilaiController --resource --model=Nilai
php artisan make:controller HitungController

Ketiga controller bertipe resource, walaupun di tutorial kali ini tidak dibahas semua, namun nanti bisa dikembangkan untuk membuat CRUD di semua data.

Untuk PageController sebagai halaman yang tidak berhubungan dengan database seperti home, about, bantuan, dll.

HitungContoller berfungsi untuk halaman perhitungan SAW.

Sesuaikan file app/http/controllers/PageController.php sebagai berikut.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class PageController extends Controller
{
    public function home()
    {
        $title = 'Home';
        return view('home', compact('title'));
    }
}

Sesuaikan function index di app/http/controllers/AlternatifController.php sebagai berikut.

<?php

namespace App\Http\Controllers;

use App\Models\Alternatif;
use Illuminate\Http\Request;

class AlternatifController extends Controller
{
    /**
     * Display a listing of the resource.
     */
    public function index()
    {
        $title = 'Data Alternatif';
        $alternatifs = Alternatif::all();
        return view('alternatif.index', compact('title', 'alternatifs'));
    }

    /**
     * Show the form for creating a new resource.
     */
    public function create()
    {
        //
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(Request $request)
    {
        //
    }

    /**
     * Display the specified resource.
     */
    public function show(Alternatif $alternatif)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     */
    public function edit(Alternatif $alternatif)
    {
        //
    }

    /**
     * Update the specified resource in storage.
     */
    public function update(Request $request, Alternatif $alternatif)
    {
        //
    }

    /**
     * Remove the specified resource from storage.
     */
    public function destroy(Alternatif $alternatif)
    {
        //
    }
}

Sesuaikan function index di app/http/controllers/KriteriaController.php sebagai berikut.

<?php

namespace App\Http\Controllers;

use App\Models\Kriteria;
use Illuminate\Http\Request;

class KriteriaController extends Controller
{
    /**
     * Display a listing of the resource.
     */
    public function index()
    {
        $title = 'Data Kriteria';
        $kriterias = Kriteria::all();
        return view('kriteria.index', compact('title', 'kriterias'));
    }

    /**
     * Show the form for creating a new resource.
     */
    public function create()
    {
        //
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(Request $request)
    {
        //
    }

    /**
     * Display the specified resource.
     */
    public function show(Kriteria $kriteria)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     */
    public function edit(Kriteria $kriteria)
    {
        //
    }

    /**
     * Update the specified resource in storage.
     */
    public function update(Request $request, Kriteria $kriteria)
    {
        //
    }

    /**
     * Remove the specified resource from storage.
     */
    public function destroy(Kriteria $kriteria)
    {
        //
    }
}

Sesuaikan function index di app/http/controllers/NilaiController.php sebagai berikut.

<?php

namespace App\Http\Controllers;

use App\Models\Alternatif;
use App\Models\Kriteria;
use App\Models\Nilai;
use Illuminate\Http\Request;

class NilaiController extends Controller
{
    /**
     * Display a listing of the resource.
     */
    public function index()
    {
        $title = 'Data Nilai';
        $kriterias = [];
        $alternatifs = [];
        $nilais = [];
        foreach (Kriteria::all() as $kriteria)
            $kriterias[$kriteria->id_kriteria] = $kriteria;
        foreach (Alternatif::all() as $alternatif)
            $alternatifs[$alternatif->id_alternatif] = $alternatif;
        foreach (Nilai::orderBy('id_alternatif')->orderBy('id_kriteria')->get() as $nilai)
            $nilais[$nilai->id_alternatif][$nilai->id_kriteria] = $nilai->nilai;

        return view('nilai.index', compact('title', 'kriterias', 'alternatifs', 'nilais'));
    }

    /**
     * Show the form for creating a new resource.
     */
    public function create()
    {
        //
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(Request $request)
    {
        //
    }

    /**
     * Display the specified resource.
     */
    public function show(Nilai $nilai)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     */
    public function edit(Nilai $nilai)
    {
        //
    }

    /**
     * Update the specified resource in storage.
     */
    public function update(Request $request, Nilai $nilai)
    {
        //
    }

    /**
     * Remove the specified resource from storage.
     */
    public function destroy(Nilai $nilai)
    {
        //
    }
}

Sesuaikan file app/http/controllers/HitungController.php sebagai berikut.

<?php

namespace App\Http\Controllers;

use App\Models\Alternatif;
use App\Models\Kriteria;
use App\Models\Nilai;
use Illuminate\Http\Request;

class HitungController extends Controller
{
    public function index()
    {
        $title = 'Perhitungan';
        $kriterias = [];
        $alternatifs = [];
        $nilais = [];
        foreach (Kriteria::all() as $kriteria)
            $kriterias[$kriteria->id_kriteria] = $kriteria;
        foreach (Alternatif::all() as $alternatif)
            $alternatifs[$alternatif->id_alternatif] = $alternatif;
        foreach (Nilai::orderBy('id_alternatif')->orderBy('id_kriteria')->get() as $nilai)
            $nilais[$nilai->id_alternatif][$nilai->id_kriteria] = $nilai->nilai;

        $minmax = [];
        $arr = [];
        foreach ($nilais as $key => $val) {
            foreach ($val as $k => $v) {
                $arr[$k][$key] = $v;
            }
        }
        foreach ($arr as $key => $val) {
            $minmax[$key]['min'] = min($val);
            $minmax[$key]['max'] = max($val);
        }
        $normal = [];
        foreach ($nilais as $key => $val) {
            foreach ($val as $k => $v) {
                $normal[$key][$k] = strtolower($kriterias[$k]->atribut) == 'benefit' ? $v / $minmax[$k]['max'] : $minmax[$k]['min'] / $v;
            }
        }
        $terbobot = [];
        foreach ($normal as $key => $val) {
            foreach ($val as $k => $v) {
                $terbobot[$key][$k] = $v * $kriterias[$k]->bobot;
            }
        }
        $total = [];
        foreach ($terbobot as $key => $val) {
            $total[$key] = array_sum($val);
        }
        arsort($total);
        $rank = [];
        $no = 1;
        foreach ($total as $key => $val) {
            $rank[$key] = $no++;
        }
        ksort($total);
        return view('hitung.index', compact('title', 'kriterias', 'alternatifs', 'nilais', 'minmax', 'normal', 'terbobot', 'total', 'rank'));
    }
}

6. Menambahkan Route

Tambahkan route untuk home, alternatif, kriteria, dan nilai di routes/web.php bertipe resource seperti berikut.

<?php

use App\Http\Controllers\AlternatifController;
use App\Http\Controllers\HitungController;
use App\Http\Controllers\KriteriaController;
use App\Http\Controllers\NilaiController;
use App\Http\Controllers\PageController;
use Illuminate\Support\Facades\Route;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider and all of them will
| be assigned to the "web" middleware group. Make something great!
|
*/

Route::get('/hitung', [HitungController::class, 'index'])->name('hitung.index');
Route::resource('/nilai', NilaiController::class)->parameters(['nilai' => 'nilai']);
Route::resource('/kriteria', KriteriaController::class)->parameters(['kriteria' => 'kriteria']);
Route::resource('/alternatif', AlternatifController::class)->parameters(['alternatif' => 'alternatif']);
Route::get('/',  [PageController::class, 'home'])->name('home');

7. Membuat View

Buat 6 buah view untuk halaman index, home, tampil alternatif, tampil kriteria, tampil nilai, dan perhitungan dengan perintah sebagai berikut.

php artisan make:view app
php artisan make:view home
php artisan make:view alternatif.index
php artisan make:view kriteria.index
php artisan make:view nilai.index
php artisan make:view hitung.index

app

resources/views/app.blade.php berfungsi sebagai parent view untuk menaruh css, javascript, dan menu utama project.

<!doctype html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>{{ $title }}</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
</head>

<body>
    <nav class="navbar navbar-expand-lg bg-body-tertiary">
        <div class="container">
            <a class="navbar-brand" href="#">SAW</a>
            <button class="navbar-toggler" type="button" data-bs-toggle="collapse"
                data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false"
                aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>
            <div class="collapse navbar-collapse" id="navbarSupportedContent">
                <ul class="navbar-nav me-auto mb-2 mb-lg-0">
                    <li class="nav-item">
                        <a class="nav-link" href="{{ route('home') }}">Home</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="{{ route('kriteria.index') }}">Kriteria</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="{{ route('alternatif.index') }}">Alternatif</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="{{ route('nilai.index') }}">Nilai</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link" href="{{ route('hitung.index') }}">Hitung</a>
                    </li>
                </ul>
            </div>
        </div>
    </nav>
    <div class="container">
        <h1 class="my-3">{{ $title }}</h1>
        @yield('content')
    </div>
</body>

</html>

home

resources/views/home.blade.php berfungsi sebagai child view untuk halaman awal ketika project dibuka.

@extends('app')
@section('content')
    <p>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Esse voluptatum totam, nobis similique ab corporis
        pariatur! Obcaecati quia ad incidunt nobis id sapiente reprehenderit saepe nemo harum quidem, architecto
        cum?</p>
@endsection

alternatif.index

resources/views/alternatif/index.blade.php berfungsi sebagai child view untuk menampilkan data alternatif.

@extends('app')
@section('content')
    <div class="card">
        <div class="table-responsive">
            <table class="table table-bordered table-hover table-striped m-0">
                <thead>
                    <tr>
                        <th>Id</th>
                        <th>Nama</th>
                    </tr>
                </thead>
                @foreach ($alternatifs as $alternatif)
                    <tr>
                        <td>{{ $alternatif->id_alternatif }}</td>
                        <td>{{ $alternatif->nama_alternatif }}</td>
                    </tr>
                @endforeach
            </table>
        </div>
    </div>
@endsection

kriteria.index

resources/views/kriteria/index.blade.php berfungsi sebagai child view untuk menampilkan data kriteria.

@extends('app')
@section('content')
    <div class="card">
        <div class="table-responsive">
            <table class="table table-bordered table-hover table-striped m-0">
                <thead>
                    <tr>
                        <th>Id</th>
                        <th>Nama</th>
                        <th>Atribut</th>
                        <th>Bobot</th>
                    </tr>
                </thead>
                @foreach ($kriterias as $kriteria)
                    <tr>
                        <td>{{ $kriteria->id_kriteria }}</td>
                        <td>{{ $kriteria->nama_kriteria }}</td>
                        <td>{{ $kriteria->atribut }}</td>
                        <td>{{ $kriteria->bobot }}</td>
                    </tr>
                @endforeach
            </table>
        </div>
    </div>
@endsection

nilai.index

resources/views/nilai/index.blade.php berfungsi sebagai child view untuk menampilkan data nilai.

@extends('app')
@section('content')
    <div class="card">
        <div class="table-responsive">
            <table class="table table-bordered table-hover table-striped m-0">
                <thead>
                    <tr>
                        <th>Id</th>
                        <th>Nama</th>
                        @foreach ($kriterias as $kriteria)
                            <th>{{ $kriteria->nama_kriteria }}</th>
                        @endforeach
                    </tr>
                </thead>
                @foreach ($nilais as $key => $val)
                    <tr>
                        <td>{{ $key }}</td>
                        <td>{{ $alternatifs[$key]->nama_alternatif }}</td>
                        @foreach ($val as $k => $v)
                            <td>{{ $v }}</td>
                        @endforeach
                    </tr>
                @endforeach
            </table>
        </div>
    </div>
@endsection

hitung.index

resources/views/hitung/index.blade.php berfungsi sebagai child view untuk menampilkan hasil perhitungan metode SAW.

@extends('app')
@section('content')
    <div class="card mb-3">
        <div class="card-header">
            Data Nilai
        </div>
        <div class="table-responsive">
            <table class="table table-bordered table-hover table-striped m-0">
                <thead>
                    <tr>
                        <th>Id</th>
                        <th>Nama</th>
                        @foreach ($kriterias as $kriteria)
                            <th>{{ $kriteria->nama_kriteria }}({{ $kriteria->atribut }}:
                                {{ $kriteria->bobot }})</th>
                        @endforeach
                    </tr>
                </thead>
                @foreach ($nilais as $key => $val)
                    <tr>
                        <td>{{ $key }}</td>
                        <td>{{ $alternatifs[$key]->nama_alternatif }}</td>
                        @foreach ($val as $k => $v)
                            <td>{{ $v }}</td>
                        @endforeach
                    </tr>
                @endforeach
                <tr>
                    <td colspan="2">Min</td>
                    @foreach ($minmax as $key => $val)
                        <td>{{ $val['min'] }}</td>
                    @endforeach
                </tr>
                <tr>
                    <td colspan="2">Max</td>
                    @foreach ($minmax as $key => $val)
                        <td>{{ $val['max'] }}</td>
                    @endforeach
                </tr>
            </table>
        </div>
    </div>

    <div class="card mb-3">
        <div class="card-header">
            Normalisasi
        </div>
        <div class="table-responsive">
            <table class="table table-bordered table-hover table-striped m-0">
                <thead>
                    <tr>
                        <th>Id</th>
                        @foreach ($kriterias as $kriteria)
                            <th>{{ $kriteria->id_kriteria }}</th>
                        @endforeach
                    </tr>
                </thead>
                @foreach ($normal as $key => $val)
                    <tr>
                        <td>{{ $key }}</td>
                        @foreach ($val as $k => $v)
                            <td>{{ round($v, 4) }}</td>
                        @endforeach
                    </tr>
                @endforeach
            </table>
        </div>
    </div>

    <div class="card mb-3">
        <div class="card-header">
            Terbobot
        </div>
        <div class="table-responsive">
            <table class="table table-bordered table-hover table-striped m-0">
                <thead>
                    <tr>
                        <th>Id</th>
                        @foreach ($kriterias as $kriteria)
                            <th>{{ $kriteria->id_kriteria }}</th>
                        @endforeach
                    </tr>
                </thead>
                @foreach ($terbobot as $key => $val)
                    <tr>
                        <td>{{ $key }}</td>
                        @foreach ($val as $k => $v)
                            <td>{{ round($v, 4) }}</td>
                        @endforeach
                    </tr>
                @endforeach
            </table>
        </div>
    </div>

    <div class="card mb-3">
        <div class="card-header">
            Perangkingan
        </div>
        <div class="table-responsive">
            <table class="table table-bordered table-hover table-striped m-0">
                <thead>
                    <tr>
                        <th>Rank</th>
                        <th>Id</th>
                        <th>Nama</th>
                        <th>Total</th>
                    </tr>
                </thead>
                @foreach ($rank as $key => $val)
                    <tr>
                        <td>{{ $val }}</td>
                        <td>{{ $key }}</td>
                        <td>{{ $alternatifs[$key]->nama_alternatif }}</td>
                        <td>{{ round($total[$key], 4) }}</td>
                    </tr>
                @endforeach
            </table>
        </div>
    </div>
@endsection

8. Menjalankan Project SAW Laravel

Langkah terakhir adalah menjalankan project. Silahkan gunakan perintah berikut untuk mengaktifkan server laravel.

php artisan serve

Ketikkan alamat sesuai server di browser (http://127.0.0.1:8000/). Hasilnya seperti berikut.

Home
Alternatif
Kriteria
Nilai
Perhitungan

Itulah tutorial membuat metode SAW dengan laravel. Jika ada yang ditanyakan, silahkan berkomentar.

Download Full Source Code

Jika Anda tertarik dengan source code tanpa repot mengetik ulang dan mengikuti tutorial ini, bisa bantu traktir Admin untuk ngopi ya di link teer.id/herdikayan. Setelah itu infokan emailnya ke wa 085 737 058 375.

Leave a Comment

Alamat email Anda tidak akan dipublikasikan. Ruas yang wajib ditandai *

Situs ini menggunakan Akismet untuk mengurangi spam. Pelajari bagaimana data komentar Anda diproses.

To top