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