Bagian 2 dari seri

CRUD Kriteria dan Alternatif AHP Laravel

Diterbitkan 18 September 2026

Buat Controller

php artisan make:controller KriteriaController --resource
php artisan make:controller AlternatifController --resource

Route

Tambahkan ke grup middleware auth pada routes/web.php:

use App\Http\Controllers\KriteriaController;
use App\Http\Controllers\AlternatifController;

Route::resource('kriteria', KriteriaController::class)->except('show');
Route::resource('alternatif', AlternatifController::class)->except('show');

KriteriaController

app/Http/Controllers/KriteriaController.php:

<?php

namespace App\Http\Controllers;

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

class KriteriaController extends Controller
{
    public function index()
    {
        $items = Kriteria::orderBy('kode')->get();
        return view('kriteria.index', compact('items'));
    }

    public function create()
    {
        return view('kriteria.form', [
            'item' => new Kriteria(),
        ]);
    }

    public function store(Request $request)
    {
        $data = $request->validate([
            'kode' => ['required', 'max:10', 'unique:kriteria,kode'],
            'nama' => ['required', 'max:255'],
        ]);

        Kriteria::create($data);

        return redirect()
            ->route('kriteria.index')
            ->with('success', 'Kriteria berhasil ditambahkan.');
    }

    public function edit(Kriteria $kriterium)
    {
        return view('kriteria.form', [
            'item' => $kriterium,
        ]);
    }

    public function update(Request $request, Kriteria $kriterium)
    {
        $data = $request->validate([
            'kode' => [
                'required',
                'max:10',
                Rule::unique('kriteria', 'kode')->ignore($kriterium->id),
            ],
            'nama' => ['required', 'max:255'],
        ]);

        $kriterium->update($data);

        return redirect()
            ->route('kriteria.index')
            ->with('success', 'Kriteria berhasil diperbarui.');
    }

    public function destroy(Kriteria $kriterium)
    {
        $kriterium->delete();

        return redirect()
            ->route('kriteria.index')
            ->with('success', 'Kriteria berhasil dihapus.');
    }
}

View Kriteria

resources/views/kriteria/index.blade.php:

@extends('layouts.app')

@section('title', 'Kriteria')

@section('content')
<div class="d-flex justify-content-between align-items-center mb-3">
    <h1 class="h4 mb-0">Kriteria</h1>
    <a href="{{ route('kriteria.create') }}" class="btn btn-primary">
        Tambah Kriteria
    </a>
</div>

<div class="card border-0 shadow-sm">
    <div class="card-body">
        <div class="table-responsive">
            <table class="table table-bordered align-middle mb-0">
                <thead>
                    <tr>
                        <th width="100">Kode</th>
                        <th>Nama</th>
                        <th width="160">Aksi</th>
                    </tr>
                </thead>
                <tbody>
                    @forelse($items as $item)
                        <tr>
                            <td>{{ $item->kode }}</td>
                            <td>{{ $item->nama }}</td>
                            <td>
                                <a href="{{ route('kriteria.edit', $item) }}"
                                   class="btn btn-warning btn-sm">Edit</a>

                                <form method="POST"
                                      action="{{ route('kriteria.destroy', $item) }}"
                                      class="d-inline"
                                      onsubmit="return confirm('Hapus data?')">
                                    @csrf
                                    @method('DELETE')
                                    <button class="btn btn-danger btn-sm">Hapus</button>
                                </form>
                            </td>
                        </tr>
                    @empty
                        <tr>
                            <td colspan="3" class="text-center">
                                Belum ada data.
                            </td>
                        </tr>
                    @endforelse
                </tbody>
            </table>
        </div>
    </div>
</div>
@endsection

resources/views/kriteria/form.blade.php:

@extends('layouts.app')

@section('title', $item->exists ? 'Edit Kriteria' : 'Tambah Kriteria')

@section('content')
<div class="card border-0 shadow-sm">
    <div class="card-body">
        <h1 class="h4 mb-4">
            {{ $item->exists ? 'Edit Kriteria' : 'Tambah Kriteria' }}
        </h1>

        <form method="POST"
              action="{{ $item->exists
                    ? route('kriteria.update', $item)
                    : route('kriteria.store') }}">
            @csrf
            @if($item->exists)
                @method('PUT')
            @endif

            <div class="mb-3">
                <label class="form-label">Kode</label>
                <input type="text" name="kode"
                       value="{{ old('kode', $item->kode) }}"
                       class="form-control" required>
            </div>

            <div class="mb-3">
                <label class="form-label">Nama Kriteria</label>
                <input type="text" name="nama"
                       value="{{ old('nama', $item->nama) }}"
                       class="form-control" required>
            </div>

            <button class="btn btn-primary">Simpan</button>
            <a href="{{ route('kriteria.index') }}"
               class="btn btn-secondary">Kembali</a>
        </form>
    </div>
</div>
@endsection

AlternatifController

app/Http/Controllers/AlternatifController.php:

<?php

namespace App\Http\Controllers;

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

class AlternatifController extends Controller
{
    public function index()
    {
        $items = Alternatif::orderBy('kode')->get();
        return view('alternatif.index', compact('items'));
    }

    public function create()
    {
        return view('alternatif.form', [
            'item' => new Alternatif(),
        ]);
    }

    public function store(Request $request)
    {
        $data = $request->validate([
            'kode' => ['required', 'max:10', 'unique:alternatif,kode'],
            'nama' => ['required', 'max:255'],
        ]);

        Alternatif::create($data);

        return redirect()
            ->route('alternatif.index')
            ->with('success', 'Alternatif berhasil ditambahkan.');
    }

    public function edit(Alternatif $alternatif)
    {
        return view('alternatif.form', [
            'item' => $alternatif,
        ]);
    }

    public function update(Request $request, Alternatif $alternatif)
    {
        $data = $request->validate([
            'kode' => [
                'required',
                'max:10',
                Rule::unique('alternatif', 'kode')->ignore($alternatif->id),
            ],
            'nama' => ['required', 'max:255'],
        ]);

        $alternatif->update($data);

        return redirect()
            ->route('alternatif.index')
            ->with('success', 'Alternatif berhasil diperbarui.');
    }

    public function destroy(Alternatif $alternatif)
    {
        $alternatif->delete();

        return redirect()
            ->route('alternatif.index')
            ->with('success', 'Alternatif berhasil dihapus.');
    }
}

View alternatif dapat memakai pola yang sama dengan kriteria.

resources/views/alternatif/index.blade.php:

@extends('layouts.app')

@section('title', 'Alternatif')

@section('content')
<div class="d-flex justify-content-between align-items-center mb-3">
    <h1 class="h4 mb-0">Alternatif</h1>
    <a href="{{ route('alternatif.create') }}" class="btn btn-primary">
        Tambah Alternatif
    </a>
</div>

<div class="card border-0 shadow-sm">
    <div class="card-body">
        <table class="table table-bordered align-middle mb-0">
            <thead>
                <tr>
                    <th>Kode</th>
                    <th>Nama</th>
                    <th width="160">Aksi</th>
                </tr>
            </thead>
            <tbody>
                @forelse($items as $item)
                    <tr>
                        <td>{{ $item->kode }}</td>
                        <td>{{ $item->nama }}</td>
                        <td>
                            <a href="{{ route('alternatif.edit', $item) }}"
                               class="btn btn-warning btn-sm">Edit</a>

                            <form method="POST"
                                  action="{{ route('alternatif.destroy', $item) }}"
                                  class="d-inline"
                                  onsubmit="return confirm('Hapus data?')">
                                @csrf
                                @method('DELETE')
                                <button class="btn btn-danger btn-sm">Hapus</button>
                            </form>
                        </td>
                    </tr>
                @empty
                    <tr>
                        <td colspan="3" class="text-center">
                            Belum ada data.
                        </td>
                    </tr>
                @endforelse
            </tbody>
        </table>
    </div>
</div>
@endsection

resources/views/alternatif/form.blade.php:

@extends('layouts.app')

@section('title', $item->exists ? 'Edit Alternatif' : 'Tambah Alternatif')

@section('content')
<div class="card border-0 shadow-sm">
    <div class="card-body">
        <h1 class="h4 mb-4">
            {{ $item->exists ? 'Edit Alternatif' : 'Tambah Alternatif' }}
        </h1>

        <form method="POST"
              action="{{ $item->exists
                    ? route('alternatif.update', $item)
                    : route('alternatif.store') }}">
            @csrf
            @if($item->exists)
                @method('PUT')
            @endif

            <div class="mb-3">
                <label class="form-label">Kode</label>
                <input type="text" name="kode"
                       value="{{ old('kode', $item->kode) }}"
                       class="form-control" required>
            </div>

            <div class="mb-3">
                <label class="form-label">Nama Alternatif</label>
                <input type="text" name="nama"
                       value="{{ old('nama', $item->nama) }}"
                       class="form-control" required>
            </div>

            <button class="btn btn-primary">Simpan</button>
            <a href="{{ route('alternatif.index') }}"
               class="btn btn-secondary">Kembali</a>
        </form>
    </div>
</div>
@endsection

Tambahkan Menu

Pada navbar layouts/app.blade.php, tambahkan:

<a class="nav-link text-white" href="{{ route('kriteria.index') }}">Kriteria</a>
<a class="nav-link text-white" href="{{ route('alternatif.index') }}">Alternatif</a>

Data Awal

Data awal sudah dibuat melalui AhpSeeder pada bagian sebelumnya.

Kriteria:

C1 - Harga
C2 - Kualitas
C3 - Pelayanan

Alternatif:

A1 - Supplier A
A2 - Supplier B
A3 - Supplier C

Seeder juga sudah membuat seluruh pasangan perbandingan kriteria dan alternatif dengan nilai awal 1.

CRUD pada bagian ini digunakan untuk menambah, mengubah, atau menghapus data kriteria dan alternatif.

Jika jumlah kriteria atau alternatif diubah melalui CRUD, pasangan perbandingan untuk data baru akan diisi pada halaman perbandingan pada langkah berikutnya.

Tutorial AHP Laravel Kriteria
Tutorial AHP Laravel Alternatif

Checkpoint

Pastikan tambah, edit, dan hapus kriteria serta alternatif berjalan normal.

Lanjut: Perbandingan Kriteria dan Perhitungan Bobot AHP