Membuat Controller, Route, dan Tampilan (Layout) Dasar

2 Maret 2025
  ·  

10 menit  ·  

Di Laravel, Controller, Route, dan Layout saling bekerja sama untuk menangani permintaan user, mengelola logika bisnis, dan menampilkan hasil proses.

Pada artikel ini, kita akan mulai mempersiapkan ketiganya sebagai fondasi fitur CRUD.

Membuat Controller

Kita akan membuat resource controller untuk model Article menggunakan perintah berikut:

# Cara Pertama
sail artisan make:controller ArticleController --model=Article

# Cara Kedua (versi yang lebih singkat)
sail artisan make:controller ArticleController -m Article
  • Perintah ini akan membuat file ArticleController.php pada direktori app/Http/Controllers.
  • Kita dapat menggunakan opsi --resource atau singkatnya -r untuk membuat Resource Controller, yaitu jenis Controller yang sudah dilengkapi dengan berbagai method bawaan untuk operasi dasar CRUD:
    MethodFungsi
    index()Menampilkan daftar artikel
    create()Menampilkan form pembuatan artikel baru
    store()Menyimpan artikel ke database
    edit()Menampilkan form edit artikel
    update()Menyimpan perubahan artikel
    destroy()Menghapus artikel
  • Pada perintah di atas, kita menggunakan opsi --model atau singkatnya -m sehingga Laravel menyisipkan parameter model secara otomatis pada method-method controller. Fitur ini memanfaatkan Route Model Binding. Selengkapnya dapat dipelajari pada dokumentasi Laravel: Specifying the Resource Model.

Seperti yang kita bahas pada artikel sebelumnya, kita bisa sekaligus membuat berbagai class lain saat membuat Model. Berikut adalah contoh perintahnya:

sail artisan make:model Article -mcr

Perintah ini akan menghasilkan:

  • -m → Migration
  • -c → Controller
  • -r → Resource Controller

Semuanya dibuat menggunakan satu perintah. Selengkapnya dapat dipelajari pada dokumentasi Laravel: Generating Model Classes.


Sampai di sini, Controller sudah berhasil kita buat!
Mari kita lanjutkan dengan menghubungkan Controller dengan Route.

Membuat Route

Route berfungsi untuk menentukan bagaimana Request HTTP akan ditangani oleh aplikasi.

Ketika Request masuk ke aplikasi, gerbang pertama yang akan menanganinya adalah Route. Route berisi pola endpoint yang diarahkan ke handler tertentu, baik berupa method Controller maupun closure.

Contoh sederhana Route adalah sebagai berikut:

Route::get('/greeting', function () {
    return 'Hello World';
});

Ketika user mengakses URL http://localhost/greeting (endpoint GET /greeting), user melakukan request dengan HTTP Method GET menuju path /greeting.

Dalam hal ini, Laravel akan menangani request dengan menjalankan closure tersebut dan mengembalikan response berupa teks “Hello World”.

Sekarang mari kita arahkan endpoint dengan HTTP Method yang diakses oleh user ke method pada Controller yang sesuai.

Untuk membuat Route, buka file routes/web.php. Lalu, ubah kode bawaan menjadi seperti berikut:

📄 routes/web.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<?php

use App\Http\Controllers\ArticleController;
use Illuminate\Support\Facades\Route;

Route::get('/articles', [ArticleController::class, 'index']);
Route::post('/articles', [ArticleController::class, 'store']);
Route::get('/articles/create', [ArticleController::class, 'create']);
Route::get('/articles/{article}', [ArticleController::class, 'show']);
Route::put('/articles/{article}', [ArticleController::class, 'update']);
Route::delete('/articles/{article}', [ArticleController::class, 'destroy']);
Route::get('/articles/{article}/edit', [ArticleController::class, 'edit']);

Penjelasan Route di atas adalah sebagai berikut:

Method HTTPEndpointDiarahkan ke Method pada Controller
GET/articlesindex()
POST/articlesstore()
GET/articles/createcreate()
GET/articles/{article}show()
PUT/articles/{article}update()
DELETE/articles/{article}destroy()
GET/articles/{article}/editedit()

Untuk melihat daftar Route yang terdaftar pada aplikasi, jalankan perintah berikut:

sail artisan route:list

Agar lebih ringkas, kita bisa mengganti semua Route di atas hanya dengan satu baris kode menggunakan Route Resource:

Route::resource('articles', ArticleController::class);

Dengan kode di atas, kita juga mengikuti konvensi penamaan Route seperti articles.index, articles.create, dan lainnya sehingga membantu kita saat membuat link atau redirect menggunakan fungsi route().

Fungsi route() merupakan helper bawaan Laravel yang digunakan untuk menghasilkan URL berdasarkan nama Route yang telah didefinisikan (kita akan menggunakannya nanti).

Kode Route kita saat ini adalah seperti berikut:

📄 routes/web.php

1
2
3
4
5
6
7
<?php

use App\Http\Controllers\ArticleController;
use Illuminate\Support\Facades\Route;

Route::resource('articles', ArticleController::class);

Kita bisa jalankan kembali perintah berikut untuk melihat daftar Route:

sail artisan route:list

Menariknya, meskipun hanya menggunakan satu baris kode, Laravel tetap akan mendaftarkan seluruh Route seperti sebelumnya.

Selamat! Route sudah berhasil kita buat!

Membuat Layout

Sebuah aplikasi web biasanya memiliki struktur tampilan (layout) yang sama di banyak halaman. Jika kita menduplikasi kode yang sama berulang kali di setiap View, kode menjadi sulit dikelola dalam jangka panjang!

Untuk menangani hal ini, kita akan menggunakan template layout.

Template layout merupakan kerangka utama yang akan digunakan ulang oleh halaman-halaman lain.

Pada folder resources/views, terdapat file welcome.blade.php. Ini adalah file View Laravel bawaan saat pertama kali kita membuat proyek. Karena kita akan membuat halaman sendiri, kita bisa menghapus file ini.

Pada folder resources/views, buat folder baru bernama layouts, lalu buat file app.blade.php di dalamnya.

📄 resources/views/layouts/app.blade.php

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>
            @hasSection('title') @yield('title') | @endif {{ config('app.name') }}
        </title>
        <style>
            body {
                display: flex;
                flex-direction: column;
                min-height: 100vh;
            }

            #content {
                margin: 80px auto 20px;
            }
        </style>

        @vite(['resources/css/app.css'])
        @stack('styles')
    </head>
    <body>
        <nav class="navbar navbar-expand-lg navbar-light bg-light fixed-top">
            <div class="container">
                <a class="navbar-brand" href="/">{{ config('app.name') }}</a>
                <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="collapse navbar-collapse" id="navbarNav">
                    <ul class="navbar-nav ms-auto">
                        <li class="nav-item">
                            <a class="nav-link {{ request()->routeIs('blog.list') ? 'active' : '' }}" href="/">Beranda</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link {{ request()->routeIs('articles*') ? 'active' : '' }}" href="/articles">Daftar Artikel</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>

        @yield('content')

        <footer class="footer mt-auto py-3 bg-light">
            <div class="container">
                <span class="text-muted">© 2025 {{ config('app.name') }}</span>
            </div>
        </footer>

        @vite(['resources/js/app.js'])
        @stack('scripts')
    </body>
</html>

Berikut penjelasan beberapa directive Blade yang digunakan dalam layout di atas:

  • @hasSection() — memeriksa apakah sebuah section tertentu didefinisikan di child view.
  • @yield() — placeholder untuk menampilkan konten dari section pada child view.
  • @vite() — menghubungkan file CSS/JS menggunakan Vite, baik saat development maupun production.
  • @stack() — menyediakan tempat untuk menumpuk konten (seperti style/script tambahan) dari child view.

Sampai di sini template layout kita sudah selesai!

Saat membuat View baru, kita cukup mewarisi (extend) template ini tanpa perlu menulis ulang seluruh struktur layout.

Oleh karena itu, kita menyebut View baru yang extend dari file app.blade.php tersebut sebagai child view dan View pada file app.blade.php sebagai parent view.

Child view bisa mengisi bagian-bagian tertentu pada layout (seperti title, styles, content, atau scripts) menggunakan directive seperti @section() atau @push() yang akan kita bahas setelah ini.

Sampai di sini, layout utama kita sudah berfungsi dengan baik. Selanjutnya, kita bisa membuatnya lebih terstruktur dan mudah dirawat dengan memecahnya ke dalam partial views.

Memisahkan Komponen Template ke Partial Views

Saat ini, seluruh struktur layout masih berada dalam satu file besar (app.blade.php). Untuk meningkatkan keterbacaan dan mempermudah pemeliharaan, kita akan memecahnya menjadi beberapa bagian kecil (partial views) dengan susunan sebagai berikut:

Partial view adalah file Blade yang berisi potongan HTML, seperti header, footer, atau bagian-bagian yang digunakan berulang di banyak halaman.

Partial-partial ini akan kita tempatkan dalam folder resources/views/partials.

Berikut ada daftar partial yang akan disisipkan ke layout utama:

FileFungsi
head.blade.phpMetadata HTML, title, dan link ke CSS
navbar.blade.phpNavigasi utama (header)
footer.blade.phpFooter halaman
scripts.blade.phpFile JavaScript dan stack untuk script lainnya
styles.blade.phpFile CSS dan stack untuk style lainnya

Yuk, kita pecahkan bersama!

Memindahkan Bagian <head> ke Partial View

  1. Di dalam folder resources/views, buat folder baru bernama partials. Buat sebuah file bernama head.blade.php di dalamnya:

  2. Pindahkan bagian <head> dari app.blade.php ke head.blade.php:

    📄 resources/views/partials/head.blade.php

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>
            @hasSection('title') @yield('title') | @endif {{ config('app.name') }}
        </title>
        <style>
            body {
                display: flex;
                flex-direction: column;
                min-height: 100vh;
            }
    
            #content {
                margin: 80px auto 20px;
            }
        </style>
    
        @vite(['resources/css/app.css'])
        @stack('styles')
    </head>
    
  3. Ubah bagian <head> pada app.blade.php menjadi seperti berikut:

    📄 resources/views/layouts/app.blade.php

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    
    <!DOCTYPE html>
    <html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
        @include('partials.head')
    
        <body>
            <nav class="navbar navbar-expand-lg navbar-light bg-light fixed-top">
                <div class="container">
                    <a class="navbar-brand" href="/">{{ config('app.name') }}</a>
                    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
                        <span class="navbar-toggler-icon"></span>
                    </button>
                    <div class="collapse navbar-collapse" id="navbarNav">
                        <ul class="navbar-nav ms-auto">
                            <li class="nav-item">
                                <a class="nav-link {{ request()->routeIs('blog.list') ? 'active' : '' }}" href="/">Beranda</a>
                            </li>
                            <li class="nav-item">
                                <a class="nav-link {{ request()->routeIs('articles*') ? 'active' : '' }}" href="/articles">Daftar Artikel</a>
                            </li>
                        </ul>
                    </div>
                </div>
            </nav>
    
            @yield('content')
    
            <footer class="footer mt-auto py-3 bg-light">
                <div class="container">
                    <span class="text-muted">© 2025 {{ config('app.name') }}</span>
                </div>
            </footer>
    
            @vite(['resources/js/app.js'])
            @stack('scripts')
        </body>
    
    </html>
    

    Directive @include() digunakan untuk menyisipkan subview ke dalam sebuah View. Dalam hal ini, isi dari head.blade.php akan dimasukkan ke app.blade.php tepat pada posisi directive dipanggil.

Memindahkan Bagian Navbar ke Partial View

  1. Buat sebuah file baru bernama navbar.blade.php di dalam resources/partials dan pindahkan bagian <nav> dari app.blade.php ke navbar.blade.php:

    📄 resources/views/partials/navbar.blade.php

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
    <nav class="navbar navbar-expand-lg navbar-light bg-light fixed-top">
        <div class="container">
            <a class="navbar-brand" href="/">{{ config('app.name') }}</a>
            <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>
            <div class="collapse navbar-collapse" id="navbarNav">
                <ul class="navbar-nav ms-auto">
                    <li class="nav-item">
                        <a class="nav-link {{ request()->routeIs('blog.list') ? 'active' : '' }}" href="/">Beranda</a>
                    </li>
                    <li class="nav-item">
                        <a class="nav-link {{ request()->routeIs('articles*') ? 'active' : '' }}" href="/articles">Daftar Artikel</a>
                    </li>
                </ul>
            </div>
        </div>
    </nav>
    
  2. Ubah bagian <nav> pada app.blade.php menjadi seperti berikut:

    📄 resources/views/layouts/app.blade.php

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    
    <!DOCTYPE html>
    <html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
        @include('partials.head')
    
        <body>
            @include('partials.navbar')
    
            @yield('content')
    
            <footer class="footer mt-auto py-3 bg-light">
                <div class="container">
                    <span class="text-muted">© 2025 {{ config('app.name') }}</span>
                </div>
            </footer>
    
            @vite(['resources/js/app.js'])
            @stack('scripts')
        </body>
    
    </html>
    
  1. Buat sebuah file baru bernama footer.blade.php dan pindahkan <footer> dari app.blade.php ke footer.blade.php:

    📄 resources/views/partials/footer.blade.php

    1
    2
    3
    4
    5
    
    <footer class="footer mt-auto py-3 bg-light">
        <div class="container">
            <span class="text-muted">© 2025 {{ config('app.name') }}</span>
        </div>
    </footer>
    
  2. Ubah bagian <footer> pada app.blade.php menjadi seperti berikut:

    📄 resources/views/layouts/app.blade.php

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    
    <!DOCTYPE html>
    <html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
        @include('partials.head')
    
        <body>
            @include('partials.navbar')
    
            @yield('content')
    
            @include('partials.footer')
    
            @vite(['resources/js/app.js'])
            @stack('scripts')
        </body>
    
    </html>
    

Memindahkan Bagian Scripts ke Partial View

  1. Buat sebuah file baru bernama scripts.blade.php dan pindahkan bagian scripts dari app.blade.php ke scripts.blade.php:

    📄 resources/views/partials/scripts.blade.php

    1
    2
    
    @vite(['resources/js/app.js'])
    @stack('scripts')
    
  2. Ubah bagian scripts pada app.blade.php menjadi seperti berikut:

    📄 resources/views/layouts/app.blade.php

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    
    <!DOCTYPE html>
    <html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
        @include('partials.head')
    
        <body>
            @include('partials.navbar')
    
            @yield('content')
    
            @include('partials.footer')
    
            @include('partials.scripts')
        </body>
    
    </html>
    
  3. Mari kita rapikan kode pada app.blade.php. Kita sesuaikan tabbing kode dan hapus spacing yang tidak diperlukan seperti berikut:

    📄 resources/views/layouts/app.blade.php

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    
    <!DOCTYPE html>
    <html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    @include('partials.head')
    
    <body>
        @include('partials.navbar')
        @yield('content')
        @include('partials.footer')
        @include('partials.scripts')
    </body>
    
    </html>
    

Memindahkan Bagian <style> ke Partial View

  1. Buat sebuah file baru bernama styles.blade.php dan pindahkan bagian <style> dari partials/head.blade.php ke partials/styles.blade.php:

    📄 resources/views/partials/styles.blade.php

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    
    <style>
        body {
            display: flex;
            flex-direction: column;
            min-height: 100vh;
        }
    
        #content {
            margin: 80px auto 20px;
        }
    </style>
    
    @vite(['resources/css/app.css'])
    @stack('styles')
    
  2. Ubah bagian <style> pada partials/head.blade.php menjadi seperti berikut:

    📄 resources/views/partials/head.blade.php

    1
    2
    3
    4
    5
    6
    7
    8
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>
            @hasSection('title') @yield('title') | @endif {{ config('app.name') }}
        </title>
        @include('partials.styles')
    </head>
    


Selesaiii… akhirnya kita berhasil merapikan template layout menjadi jauh lebih tertata!

Melihat setiap bagian layout tersusun rapi seperti ini, tidak cuma mempermudah pemeliharaan kode, tetapi juga bikin hati senang! ✨

Mulai sekarang, menambahkan atau mengubah bagian-bagian layout jadi jauh lebih mudah.

  • Ingin menambahkan script baru? Tinggal ubah scripts.blade.php.
  • Perlu menambahkan metadata? Edit saja head.blade.php.
  • Mau ubah styling? Tinggal sesuaikan styles.blade.php.

Semuanya jadi lebih praktis dan terstruktur!

Dengan struktur seperti ini, kita punya layout yang bersih, modular, dan mudah dipelihara. Cukup ubah satu partial sesuai kebutuhan—tanpa perlu menyentuh View lainnya.



Di bagian selanjutnya, kita akan mulai membangun halaman utama blog menggunakan layout ini. Kita juga akan mempelajari cara membuat child view yang mewarisi tampilan dari app.blade.php menggunakan directive @extends dan @section.

Sampai titik ini, kita sudah membangun fondasi utama aplikasi Laravel: Controller, Route, dan Layout.

Sudah siap untuk melangkah lebih jauh?
Yuk, lanjut ke tahap berikutnya! 😊🚀

Membuat Controller, Route, dan Tampilan (Layout) Dasar
Top