Skip to content

Tutorial Laravel 11 Dengan Breeze (PART 2)

Facebook
Twitter
LinkedIn

Kali ini kita akan bahas mekanisme register dari Breeze, Coba perhatikan folder routes pada project, Disana akan ada file baru bernama auth.php dan file ini memang di buat otomatis oleh Breeze untuk mengatur fitur-fitur route yang di butuhkan oleh Breeze itu sendiri. Sekarang mari buka file web.php, Kurang lebih isinya akan seperti ini :

<?php

use App\Http\Controllers\ChirpController;
use App\Http\Controllers\ProfileController;
use Illuminate\Support\Facades\Route;

Route::get('/', function () {
    return view('welcome');
});

Route::get('/dashboard', function () {
    return view('dashboard');
})->middleware(['auth', 'verified'])->name('dashboard');

Route::middleware('auth')->group(function () {
    Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');
    Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update');
    Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy');
});

Route::resource('chirps', ChirpController::class)
    ->only(['index', 'store', 'edit', 'update', 'destroy'])
    ->middleware(['auth', 'verified']);

require __DIR__.'/auth.php';

Perhatikan pada kode di nomor 7 – 9, Kode tersebut mendefinisikan rute untuk URL root / dari aplikasi dan rute tersebut menggunakan metode get, yang berarti akan merespons permintaan HTTP GET ke URL root.
Di rute tersebut terdapat sebuah fungsi anonim yang memanggil fungsi view untuk mengembalikan tampilan (view) yang bernama welcome.blade.php. Jadi secara default, Saat aplikasi di akses maka kode itu yang akan di jalankan dan menampilkan halaman welcome yang terdapat pada folder resources\views. Kurang lebih tampilannya seperti ini

Sekarang buka file welcome.blade.php dan cari kode ini di file tersebut

<header class="grid grid-cols-2 items-center gap-2 py-10 lg:grid-cols-3">
                        <div class="flex lg:justify-center lg:col-start-2">
                            <svg class="h-12 w-auto text-white lg:h-16 lg:text-[#FF2D20]" viewBox="0 0 62 65" fill="none" xmlns="" fill="currentColor"/></svg>
                        </div>
                        @if (Route::has('login'))
                            <nav class="-mx-3 flex flex-1 justify-end">
                                @auth
                                    <a
                                        href="{{ url('/dashboard') }}"
                                        class="rounded-md px-3 py-2 text-black ring-1 ring-transparent transition hover:text-black/70 focus:outline-none focus-visible:ring-[#FF2D20] dark:text-white dark:hover:text-white/80 dark:focus-visible:ring-white"
                                    >
                                        Dashboard
                                    </a>
                                @else
                                    <a
                                        href="{{ route('login') }}"
                                        class="rounded-md px-3 py-2 text-black ring-1 ring-transparent transition hover:text-black/70 focus:outline-none focus-visible:ring-[#FF2D20] dark:text-white dark:hover:text-white/80 dark:focus-visible:ring-white"
                                    >
                                        Log in
                                    </a>

                                    @if (Route::has('register'))
                                        <a
                                            href="{{ route('register') }}"
                                            class="rounded-md px-3 py-2 text-black ring-1 ring-transparent transition hover:text-black/70 focus:outline-none focus-visible:ring-[#FF2D20] dark:text-white dark:hover:text-white/80 dark:focus-visible:ring-white"
                                        >
                                            Register
                                        </a>
                                    @endif
                                @endauth
                            </nav>
                        @endif
                    </header>

Kode nomor 5 sampai 32 adalah kode yang bertugas untuk menampilkan link Login dan Register pada halaman welcome. Kira kira begini logika keseluruhan kode tersebut
1. @if (Route::has('login')) : code ini akan memeriksa apakah rute login ada. Jika ada maka blok kode di dalamnya akan di eksekusi dan jika tidak ada maka link login dan Register tidak akan muncul di halaman welcome.
2. @auth : Direktif ini akan memeriksa apakah pengguna saat ini sudah login. Jika sudah maka aplikasi akan menampilkan link Dashboard.
3. @if (Route::has('register')) : Kode ini akan melakukan pemeriksaan apakah rute register tersedia. Jika tidak maka link Register tidak akan di tampilkan.

Jadi ketika pengguna mengklik link register maka aplikasi laravel akan menangani proses tersebut di file web.php, Karena rute itu di buat dari Breeze secara otomatis di file terpisah yaitu auth.php maka di file web.php perlu meload file auth.php dengan menggunakan kode require __DIR__.'/auth.php';.

Perlu diketahui bahwa jika rute <a href="{{ route('register') }}"> tidak dideskripsikan secara eksplisit, maka secara default, rute ini akan mengarah ke metode GET. Ini adalah perilaku bawaan dari Laravel ketika menggunakan fungsi route() di dalam tautan (link). Jadi sekarang mari kita buka file auth.php dan mencari kode rute untuk register yang menggunakan metode GET.

<?php

use App\Http\Controllers\Auth\AuthenticatedSessionController;
use App\Http\Controllers\Auth\ConfirmablePasswordController;
use App\Http\Controllers\Auth\EmailVerificationNotificationController;
use App\Http\Controllers\Auth\EmailVerificationPromptController;
use App\Http\Controllers\Auth\NewPasswordController;
use App\Http\Controllers\Auth\PasswordController;
use App\Http\Controllers\Auth\PasswordResetLinkController;
use App\Http\Controllers\Auth\RegisteredUserController;
use App\Http\Controllers\Auth\VerifyEmailController;
use Illuminate\Support\Facades\Route;

Route::middleware('guest')->group(function () {
    Route::get('register', [RegisteredUserController::class, 'create'])
                ->name('register');

    Route::post('register', [RegisteredUserController::class, 'store']);

    Route::get('login', [AuthenticatedSessionController::class, 'create'])
                ->name('login');

    Route::post('login', [AuthenticatedSessionController::class, 'store']);

    Route::get('forgot-password', [PasswordResetLinkController::class, 'create'])
                ->name('password.request');

    Route::post('forgot-password', [PasswordResetLinkController::class, 'store'])
                ->name('password.email');

    Route::get('reset-password/{token}', [NewPasswordController::class, 'create'])
                ->name('password.reset');

    Route::post('reset-password', [NewPasswordController::class, 'store'])
                ->name('password.store');
});

Route::middleware('auth')->group(function () {
    Route::get('verify-email', EmailVerificationPromptController::class)
                ->name('verification.notice');

    Route::get('verify-email/{id}/{hash}', VerifyEmailController::class)
                ->middleware(['signed', 'throttle:6,1'])
                ->name('verification.verify');

    Route::post('email/verification-notification', [EmailVerificationNotificationController::class, 'store'])
                ->middleware('throttle:6,1')
                ->name('verification.send');

    Route::get('confirm-password', [ConfirmablePasswordController::class, 'show'])
                ->name('password.confirm');

    Route::post('confirm-password', [ConfirmablePasswordController::class, 'store']);

    Route::put('password', [PasswordController::class, 'update'])->name('password.update');

    Route::post('logout', [AuthenticatedSessionController::class, 'destroy'])
                ->name('logout');
});

Dari kode di atas, rute untuk menangani register dengan metode GET berada di baris 15 – 16 dan dari kode tersebut tampaknya kita di arahkan ke file RegisteredUserController yang berada di folder `

Dari kode di atas, rute untuk menangani register dengan metode GET berada di baris 15 – 16 dan dari kode tersebut tampaknya kita di arahkan ke file RegisteredUserController yang berada di folder App\Http\Controllers\Auth dan spesifik pada fungsi yang bernama create yang berada pada file tersebut. Jadi mari kita buka kode dari file tersebut.

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Auth\Events\Registered;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rules;
use Illuminate\View\View;

class RegisteredUserController extends Controller
{
    /**
     * Display the registration view.
     */
    public function create(): View
    {
        return view('auth.register');
    }

    /**
     * Handle an incoming registration request.
     *
     * @throws \Illuminate\Validation\ValidationException
     */
    public function store(Request $request): RedirectResponse
    {
        $request->validate([
            'name' => ['required', 'string', 'max:255'],
            'email' => ['required', 'string', 'lowercase', 'email', 'max:255', 'unique:'.User::class],
            'password' => ['required', 'confirmed', Rules\Password::defaults()],
        ]);

        $user = User::create([
            'name' => $request->name,
            'email' => $request->email,
            'password' => Hash::make($request->password),
        ]);

        event(new Registered($user));

        Auth::login($user);

        return redirect(route('dashboard', absolute: false));
    }
}

Mari kita pahami bagaimana kode itu bekerja,
Pertama adalah fungsi create di buat dengan deklarasi tipe pengembalian : View yang menjelaskan bahwa fungsi ini mengharapkan pengembalian dengan tipe View, Sementara kode return view('auth.register'); menjelaskan bahwa dia akan mengembalikan view yang berada di folder resources\views\auth\register.blade.php.
Jadi secara singkatnya ketika pengguna mengklik link Register maka laravel akan membuka file register.blade.php untuk menampilkan semua user interface ke pengguna.

Kedua adalah fungsi store yang di buat dengan tipe pengembalian RedirectResponse yang menjelaskan bahwa fungsi ini harus mengembalikan sebuah redirect route, Kemudian pada bagian $request->validate itu berfungsi untuk memvalidasi request jadi semisal fungsi ini di jalankan dan properti email tidak di sertakan maka fungsi ini akan memberi informasi bahwa email di perlukan untuk menjalankan fungsi ini. Lalu User::create berfungsi untuk membuat data yang telah di validasi dan data ini dibuat menggunakan Eloquent. Setelah itu ada kode event(new Registered($user)); kode ini bengfungsi untuk memicu event Registered yang dalam kasus ini dia akan mengirimkan email verifikasi ke pengguna.

Seperti yang saya katakan pada part 1 dari tutorial ini, bahwa Breeze juga membuat fitur verifikasi email yang bertujuan untuk memberi proteksi lebih terhadap aplikasi dengan cara mencegah user mengakses halaman tertentu yang menggunakan middleware verified, namun fitur itu tidak langsung berfungsi sebelum kita mengimplementasikan contract Illuminate\Contracts\Auth\MustVerifyEmail pada model App\Models\User.

<?php

namespace App\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable implements MustVerifyEmail
{
    use  Notifiable;

}

Ketika contract sudah di gunakan dan server mail sudah di atur, saat ada pengguna mendaftar akan secara otomatis di kirimi sebuah email yang berisi verifikasi link. Itu terjadi karena laravel sudah mendaftarkan listener Illuminate\Auth\Listeners\SendEmailVerificationNotification untuk event Illuminate\Auth\Events\Registered.

Jadi ketika kode event(new Registered($user)); di jalakan secara otomatis laravel akan mengirim email verifikasi ke properti email yang ada di dalam $user.

Sekarang kita kembali lagi ke fungsi store tadi, setelah kode untuk event di picu kode berikutnya adalah Auth::login($user); yang berfungsi untuk otomatis login setelah mendaftar kemudian kode return redirect(route('dashboard', absolute : false)); yang mengarahkan kita ke rute yang bernama dashboard, btw setelah kamu secara otomatis login ke aplikasi mungkin kamu berfikir sudah bisa mengakses halaman dashboard, Tapi dugaan kamu itu salah karena kamu akan di arahkan ke halaman verifikasi email, rute apa pun yang kamu akses saat kamu sudah login pasti kamu akan tetap di arahkan ke halaman verifikasi email.

Hal itu terjadi karena model User sudah mengimplementasikan interface MustVerifyEmail dan rute yang kamu akses tidak hanya dilindungi oleh middleware auth namun juga verified, kedua middleware itu memang sudah bawaan laravel. Jadi meskipun kamu sudah login namun tidak melakukan verifikasi email maka middleware verified akan mengarahkan kamu ke rute yang bernama verification.notice dan nama rute itu sudah paten karna sudah di tetapkan di middleware bawaan laravel jadi jangan rubah nama rute tersebut.

## ROUTE
Route::middleware('auth')->group(function () {
    Route::get('verify-email', EmailVerificationPromptController::class)
                ->name('verification.notice');
});

## CONTROLLER
class EmailVerificationPromptController extends Controller
{
    /**
     * Display the email verification prompt.
     */
    public function __invoke(Request $request): RedirectResponse|View
    {
        return $request->user()->hasVerifiedEmail()
                    ? redirect()->intended(route('dashboard', absolute: false))
                    : view('auth.verify-email');
    }
}

Coba sekarang kamu pahami sejenak potongan kode tersebut, kode itulah yang memaksa pengguna harus melakukan verifikasi sebelum menggunakan aplikasi. Jika kesulitan memahami cara kerja kode tersebut silahkan baca penjelasan ku :p.

Ingat bahwa rute untuk dashboard menggunakan middleware bawaan laravel yaitu verified, middleware itu akan selalu memeriksa apakah akun pengguna sudah terverifikasi?, Jika belum maka akan di arahkan ke rute yang bernama verification.notice dan kode tersebut ada di kode nomor 4 dan rute itu menggunakan EmailVerificationPromptController untuk menangani permintaan yang datang ke rute tersebut.

Alih-alih kontroller tersebut menggunakan nama fungsi sebagai pada umumnya, justru hanya ada satu fungsi dan itu adalah __invoke dan itu juga salah satu fitur dari laravel yaitu Single Action Controller yang intinya adalah ketika rute verification.notice di akses maka laravel akan otomatis menjalankan metode __invoke yang berada di kontroller EmailVerificationPromptController. Jika ingin tau lebih soal ini bisa baca di sini.

Nah sekarang kita bahas isi dari metode itu, pertama $request Variabel ini mewakili objek Illuminate\Http\Request yang mewakili permintaan HTTP yang masuk ke aplikasi Laravel, lalu objek user di ambil dari $request dengan cara $request->user() untuk di lakukan pengecekan apakah user tersebut telah melakukan verifikasi email dengan cara menambahkan hasVerifiedEmail() dan metode ini mengembalikan nilai TRUE atau FALSE. Jadi kode $request->user()->hasVerifiedEmail() adalah memeriksa mengambil objek user dari data request yang datang menggunakan metode hashVerifiedEmail.

Kemudian menggunakan ternary jika belum terverifikasi maka akan menjalankan kode view('auth.verify-email'); yang akan membuka halaman verifikasi email sementara jika sudah maka akan menjalankan kode redirect()->intended(route('dashboard', absolute: false)).
redirect() adalah fungsi global laravel yang mengembalikan instance dari RedirectResponse dan fungsi ini digunakan untuk mengarahkan pengguna ke URL berbeda. intended() adalah salah satu metode dari RedirectResponse yang akan mengarahkan pengguna ke URL yang sebelumnya di akses tapi belum login, jadi semisal kamu belum login dan memaksa mengakses halaman transaksi kamu akan terhalang middleware namun setelah login kamu akan di arahkan ke halaman transaksi namun jika kamu tidak mengakses halaman apapun sebelum login maka kamu akan di arahkan ke rute dashboard dengan menggunakan parameter absolute: false untuk memastikan bahwa URL yang dihasilkan adalah URL relatif, bukan absolut.

redirect()->intended(route(‘dashboard’, absolute: false));
// Menghasilkan redirect ke URL relatif: /dashboard

redirect()->intended(route(‘dashboard’));
// Menghasilkan redirect ke URL absolut: http://example.com/dashboard

Dalam kebanyakan kasus, menggunakan URL absolut lebih aman karena memastikan bahwa pengalihan akan bekerja dengan benar, terlepas dari konteks tempat pengalihan terjadi. Namun, dalam beberapa situasi khusus (misalnya, jika aplikasi Anda berjalan di beberapa subdomain atau direktori), Anda mungkin memerlukan URL relatif. Untuk lebih lanjut soal redirect dan intended bisa baca di sini.

Aku rasa kamu sudah paham bagaimana Laravel melindungi halaman dari pengguna yang belum memverifikasi email. Sekarang, kamu harus mengerti bagaimana cara Laravel melakukan verifikasi pengguna.

Kode di bawah ini adalah kode untuk menghandle proses verifikasi. Coba kamu pahami kode tersebut. Jika kamu merasa stuck, kamu bisa membaca informasi tambahan di sini. Bila masih stuck, simak penjelasan dariku nanti ;P

## Route
Route::middleware('auth')->group(function () {
    Route::get('verify-email/{id}/{hash}', VerifyEmailController::class)
                ->middleware(['signed', 'throttle:6,1'])
                ->name('verification.verify');
});

## CONTROLLER
class VerifyEmailController extends Controller
{
    /**
     * Mark the authenticated user's email address as verified.
     */
    public function __invoke(EmailVerificationRequest $request): RedirectResponse
    {
        if ($request->user()->hasVerifiedEmail()) {
            return redirect()->intended(route('dashboard', absolute: false).'?verified=1');
        }

        if ($request->user()->markEmailAsVerified()) {
            event(new Verified($request->user()));
        }

        return redirect()->intended(route('dashboard', absolute: false).'?verified=1');
    }
}

aku harap kamu benar – benar membaca dokumentasi yang tadi aku berikan, Karna jika iya mungkin kamu kebingungan mengapa kode dari Breeze bisa berbeda dari dokumentasi yang di berikan :D. Sebelum aku mencari tau kenapa hal itu bisa terjadi aku juga sempat bingung kenapa kode dan dokumentasi itu berbeda. Namun setelah aku pahami kembali sebenarnya kode dan dokumentasi itu sama hanya saja caranya yang berbeda, Breeze menggunakan Controller untuk menghandle logic sementara di dokementasi di jelaskan dengan cara menggunakan fungsi anonim di route.

Aku akan jelaskan cara dari kode di atas bekerja setelah itu aku akan jelaskan apa yang di maksud oleh dokumentasi. Di baris ke 3 dari kode itu menandakan bahwa rute tersebut membutuhkan 2 parameter yaitu id dan hash, bila kamu perhatikan lebih detail email yang di kirim oleh laravel maka kamu akan menyadari bahwa sebenarnya link tersebut berisi 4 hal yaitu id, hash, waktu link tersebut expired dan signature. Nah signature itu digunakan untuk melewati middleware signed sementara id dan hash akan di handle di VerifyEmailController. Jika kamu perhatikan di kontroller itu mungkin kamu sadar bahwa kontroller menggunakan EmailVerificationRequest padahal biasanya menggunakan Request, EmailVerificationRequest digunakan karena itu adalah form request bawaan laravel yang akan secara otomatis memvalidasi request yang datang harus menyertakan id dan hash.

Mungkin kamu bertanya – tanya bagaimana bisa EmailVerificationRequest bisa secara otomatis melakukan validasi terhadap parameter id dan hash seperti yang di katakan di dokumentasi, Jawabannya adalah baca lagi dokumentasinya. Di sana di jelaskan bahwa EmailVerificationRequest adalah sebuah Form Request lebih tepatnya Form Request Validation dan ketika aku klik link yang disediakan laravel aku di arahkan ke halaman dokumentasi Form Request Validation.

Di halaman tersebut aku menemukan informasi ketika membuat sebuah form request validasi maka laravel akan secara default membuat 2 metode pada form request yang kita buat yaitu authorize dan Rules, Kemudian di jelaskan juga ketika kita melakukan Type-Hint request yang kita buat ke sebuah kontroller maka laravel secara otomatis akan melakukan validasi terhadap request yang datang sebelum di proses oleh kontroller. Dengan kata lain metode authorize dan Rules akan di jalankan secara otomatis. Sekarang aku rasa kamu paham bagaiman sifat dan perilaku bawaan dari sebuah form request validation, Kita kembali ke EmailVerificationRequest.

Ingat bahwa EmailVerificationRequest itu adalah bawaan dari laravel jadi seharusnya di dalam sana ada metode Authorize dan Rules yang sudah otomatis di atur untuk memvalidasi id dan hash, Untuk membuktikan hal tersebut mari kita melihat lebih dalam ke dokumentasinya. Kamu bisa mengunjungi halaman API Documentation dari laravel dan biar lebih cepat kunjungi saja link ini.

Sekarang kamu harus kembali memeriksa kode di VerifyEmailController dan cari dari mana asal EmailVerificationRequest, Kamu seharusnya menemukan kode ini use Illuminate\Foundation\Auth\EmailVerificationRequest; dan memang dari situ form request tersebut berasal. Langkah berikutnya adalah kembali ke halaman API Documentation lalu bernavigasilah ke Illuminate >> Foundation >> Auth lalu pilih Class EmailVerificationRequest.

Di sana di jelaskan dengan detail tentang Class EmailVerificatonRequest, Dia extends dari apa, memiliki Traits apa saja, Properties apa saja dan Methods apa saja. Dan mari fokus ke bagian methods karena kita akan mencari method Authorize dan Rules. Di sana ada terlalu banyak methods namun kita akan fokus ke method dari class itu sendiri dan biasanya terletak di akhir list dan tidak ada tanda from.

Di sana sudah di jelaskan itu metode ngapain aja jadi aku rasa sedikit banyak kamu paham lah ya, Sekarang coba klik authorize() dan di pojok kanan ada link at line 16. Kalau kamu klik maka kamu akan di arahkan ke source code dari class EmailVerificationRequest dan di sana semua pertanyaan yang mungkin kamu tanyakan terkait bagaimana cara class tersebut otomatis memvalidasi id dan hash seharusnya terjawab.


Coba kamu buka database mu pada tabel users, maka kamu akan mendapati data yang tadi kamu input waktu melakukan register namun pada kolom email_verified_at berisi kosong yang menandakan bahwa user tersebut belum melakukan verifikasi email dan cara verifikasi email cukup dengan cari email yang masuk ke akun mu (cari di spam kalau tidak ketemu ya) lalu ikuti instruksi yang ada di email tersebut dan jika berhasil maka kolom email_verified_at akan berisi data dengan format time_stamp dan jika kamu coba login dengan akun tersebut maka sekarang kamu sudah

Leave a Reply

Your email address will not be published. Required fields are marked *