Bagian 5 dari seri

Perhitungan Nilai Akhir dan Ranking AHP Laravel

Diterbitkan 18 September 2026

Tutorial AHP Laravel Hasil

Rumus Nilai Akhir

Nilai akhir setiap alternatif dihitung dari:

Nilai Akhir =
Σ (Bobot Kriteria × Bobot Alternatif pada Kriteria)

Halaman hasil menggunakan GET untuk menampilkan data. Proses perhitungan menggunakan POST karena mengubah nilai_akhir dan ranking di database.

Buat Controller

php artisan make:controller HasilController

app/Http/Controllers/HasilController.php:

<?php

namespace App\Http\Controllers;

use App\Models\Alternatif;
use App\Models\Kriteria;
use App\Models\PerbandinganAlternatif;
use App\Models\PerbandinganKriteria;
use App\Services\AhpService;
use Illuminate\Support\Facades\DB;

class HasilController extends Controller
{
    public function index()
    {
        $ranking = Alternatif::orderByRaw(
            'ranking IS NULL, ranking ASC'
        )
            ->orderBy('kode')
            ->get();

        return view('hasil.index', compact('ranking'));
    }

    public function calculate(AhpService $ahp)
    {
        $kriteria = Kriteria::orderBy('kode')->get();
        $alternatif = Alternatif::orderBy('kode')->get();

        if ($kriteria->count() < 2 || $alternatif->count() < 2) {
            return redirect()
                ->route('hasil.index')
                ->withErrors(
                    'Minimal diperlukan dua kriteria dan dua alternatif.'
                );
        }

        $kriteriaIds = $kriteria->pluck('id')->all();
        $alternatifIds = $alternatif->pluck('id')->all();

        $expectedKriteria =
            $kriteria->count() * ($kriteria->count() - 1) / 2;

        if (PerbandinganKriteria::count() !== $expectedKriteria) {
            return redirect()
                ->route('hasil.index')
                ->withErrors(
                    'Perbandingan kriteria belum lengkap.'
                );
        }

        $recordsKriteria = PerbandinganKriteria::all();

        $matrixKriteria = $ahp->matrix(
            $kriteriaIds,
            $recordsKriteria,
            'kriteria_1_id',
            'kriteria_2_id'
        );

        $hasilKriteria = $ahp->priority(
            $matrixKriteria,
            $kriteriaIds
        );

        $konsistensiKriteria = $ahp->consistency(
            $matrixKriteria,
            $hasilKriteria['weights'],
            $kriteriaIds
        );

        if ($konsistensiKriteria['cr'] > 0.1) {
            return redirect()
                ->route('hasil.index')
                ->withErrors(
                    'Perbandingan kriteria belum konsisten.'
                );
        }

        $expectedAlternatif =
            $alternatif->count() * ($alternatif->count() - 1) / 2;

        $bobotAlternatif = [];

        foreach ($kriteria as $itemKriteria) {
            $records = PerbandinganAlternatif::where(
                'kriteria_id',
                $itemKriteria->id
            )->get();

            if ($records->count() !== $expectedAlternatif) {
                return redirect()
                    ->route('hasil.index')
                    ->withErrors(
                        "Perbandingan alternatif pada {$itemKriteria->kode} belum lengkap."
                    );
            }

            $matrix = $ahp->matrix(
                $alternatifIds,
                $records,
                'alternatif_1_id',
                'alternatif_2_id'
            );

            $hasil = $ahp->priority(
                $matrix,
                $alternatifIds
            );

            $konsistensi = $ahp->consistency(
                $matrix,
                $hasil['weights'],
                $alternatifIds
            );

            if ($konsistensi['cr'] > 0.1) {
                return redirect()
                    ->route('hasil.index')
                    ->withErrors(
                        "Perbandingan alternatif pada {$itemKriteria->kode} belum konsisten."
                    );
            }

            $bobotAlternatif[$itemKriteria->id] =
                $hasil['weights'];
        }

        $nilaiAkhir = [];

        foreach ($alternatifIds as $alternatifId) {
            $nilaiAkhir[$alternatifId] = 0;

            foreach ($kriteriaIds as $kriteriaId) {
                $nilaiAkhir[$alternatifId] +=
                    $hasilKriteria['weights'][$kriteriaId]
                    * $bobotAlternatif[$kriteriaId][$alternatifId];
            }
        }

        arsort($nilaiAkhir);

        DB::transaction(function () use ($nilaiAkhir) {
            $posisi = 0;
            $ranking = 0;
            $nilaiSebelumnya = null;
            $epsilon = 0.00000001;

            foreach ($nilaiAkhir as $alternatifId => $nilai) {
                $posisi++;

                if (
                    $nilaiSebelumnya === null
                    || abs($nilai - $nilaiSebelumnya) > $epsilon
                ) {
                    $ranking = $posisi;
                }

                Alternatif::whereKey($alternatifId)->update([
                    'nilai_akhir' => $nilai,
                    'ranking' => $ranking,
                ]);

                $nilaiSebelumnya = $nilai;
            }
        });

        return redirect()
            ->route('hasil.index')
            ->with(
                'success',
                'Perhitungan AHP dan ranking berhasil dilakukan.'
            );
    }
}

Jika dua alternatif memiliki nilai akhir yang sama, keduanya memperoleh ranking yang sama.

Contoh:

A1 = 0.40000000 → Ranking 1
A2 = 0.40000000 → Ranking 1
A3 = 0.20000000 → Ranking 3

Route

Tambahkan pada grup auth:

use App\Http\Controllers\HasilController;

Route::get(
    '/hasil',
    [HasilController::class, 'index']
)->name('hasil.index');

Route::post(
    '/hasil/hitung',
    [HasilController::class, 'calculate']
)->name('hasil.calculate');

View Ranking

Buat resources/views/hasil/index.blade.php:

@extends('layouts.app')

@section('title', 'Hasil AHP')

@section('content')
<div class="d-flex justify-content-between align-items-center mb-3">
    <h1 class="h4 mb-0">
        Hasil Ranking AHP
    </h1>

    <form
        method="POST"
        action="{{ route('hasil.calculate') }}">

        @csrf

        <button class="btn btn-primary">
            Hitung Ranking
        </button>
    </form>
</div>

<div class="card border-0 shadow-sm">
    <div class="card-body">
        <div class="table-responsive">
            <table class="table table-bordered table-striped align-middle">
                <thead>
                    <tr>
                        <th width="100">Ranking</th>
                        <th>Kode</th>
                        <th>Alternatif</th>
                        <th>Nilai Akhir</th>
                    </tr>
                </thead>

                <tbody>
                    @forelse($ranking as $item)
                        <tr>
                            <td>
                                @if($item->ranking)
                                    <span class="badge text-bg-primary">
                                        {{ $item->ranking }}
                                    </span>
                                @else
                                    -
                                @endif
                            </td>

                            <td>{{ $item->kode }}</td>
                            <td>{{ $item->nama }}</td>

                            <td>
                                @if($item->nilai_akhir !== null)
                                    {{ number_format(
                                        $item->nilai_akhir,
                                        8
                                    ) }}
                                @else
                                    Belum dihitung
                                @endif
                            </td>
                        </tr>
                    @empty
                        <tr>
                            <td colspan="4" class="text-center">
                                Belum ada alternatif.
                            </td>
                        </tr>
                    @endforelse
                </tbody>
            </table>
        </div>
    </div>
</div>
@endsection

Tambahkan Menu Hasil

Pada navbar:

<a class="nav-link text-white" href="{{ route('hasil.index') }}">
    Hasil Ranking
</a>

Cara Kerja

Saat halaman hasil dibuka:

GET /hasil

aplikasi hanya menampilkan data.

Saat tombol Hitung Ranking ditekan:

POST /hasil/hitung

aplikasi akan:

  1. memastikan jumlah kriteria dan alternatif cukup;
  2. memastikan seluruh pasangan perbandingan lengkap;
  3. menghitung bobot kriteria;
  4. memeriksa CR kriteria;
  5. menghitung bobot alternatif pada setiap kriteria;
  6. memeriksa CR setiap matriks alternatif;
  7. menghitung nilai akhir;
  8. menentukan ranking;
  9. menyimpan nilai_akhir dan ranking.
Tutorial AHP Laravel Hasil

Pengujian Akhir

Pastikan:

  • Login dan logout berjalan.
  • CRUD kriteria berjalan.
  • CRUD alternatif berjalan.
  • Pasangan baru otomatis dibuat dengan nilai 1.
  • CR kriteria ≤ 0,1.
  • CR alternatif pada setiap kriteria ≤ 0,1.
  • Membuka halaman hasil tidak langsung mengubah database.
  • Perhitungan dilakukan setelah tombol Hitung Ranking ditekan.
  • Nilai akhir tersimpan.
  • Ranking diurutkan dari nilai terbesar.
  • Nilai akhir yang sama menghasilkan ranking yang sama.

Selesai

Aplikasi AHP Laravel sudah memiliki alur lengkap mulai dari data master, matriks perbandingan, pengujian konsistensi, sampai ranking akhir.

Kembali ke Tutorial AHP Laravel

Komentar

Belum ada komentar.

Tulis Komentar

Komentar pengunjung diperiksa sebelum ditampilkan.