Setiap formulir yang dikirim browser membawa data yang perlu dibaca aplikasi sebelum diproses lebih lanjut. Topik ini membahas tiga mekanisme penanganan data pada siklus permintaan (request), yaitu pembacaan masukan melalui objek Request, pengisian ulang formulir dengan helper old(), dan pengiriman pesan flash antar permintaan. Seluruh contoh diuji pada aplikasi catatan sehingga alur data dari tombol kirim sampai kembali ke formulir dapat diamati pada keluaran nyata.
Objek Request dan metode pembacaan masukan#
Laravel membungkus setiap permintaan HTTP yang masuk ke dalam objek Illuminate\Http\Request. Objek ini dioperkan ke aksi controller melalui injeksi dependensi (dependency injection), sehingga data yang dikirim pengguna dapat dibaca langsung dari parameter aksi tersebut. Karena satu permintaan dapat membawa data dari beberapa sumber, objek Request menyediakan metode pembacaan yang dipilah menurut sumbernya.
Metode input() adalah metode yang paling sering digunakan. Metode ini mencari nilai pada data formulir dan query string sekaligus, sehingga sumber masukan tidak perlu ditentukan pada kasus umum. Apabila sumbernya ingin ditegaskan, metode query() hanya membaca query string, sedangkan all() mengembalikan seluruh data dalam satu array. Metode only() dan except() memilah bagian yang diambil, sedangkan filled() memeriksa apakah sebuah kolom terisi nilai.
| Metode | Data yang dibaca | Kegunaan |
|---|---|---|
input('judul') | formulir dan query string | Nilai satu kolom, lengkap dengan nilai bawaan bila kosong |
query('halaman') | query string | Parameter paginasi, pencarian, dan penyaringan |
all() | gabungan keduanya | Mengambil seluruh data dalam satu array |
only(['judul']) | bagian dari data | Memilih sejumlah kolom tertentu |
except(['isi']) | bagian dari data | Menyisihkan sejumlah kolom tertentu |
filled('judul') | pemeriksaan | Mengetahui kolom terisi atau tidak |
Perilaku metode-metode tersebut dapat dicoba tanpa server web. Objek Request dibuat langsung melalui Request::create(), lalu setiap metode pembacaannya dieksekusi melalui Tinker.
# membaca data permintaan melalui objek Request
cd ~/aplikasi-catatan
php artisan tinker --execute='
$request = Illuminate\Http\Request::create("/uji/catatan", "POST", [
"judul" => "Rapat pekanan",
"isi" => "Mencatat keputusan dan penanggung jawabnya.",
"category_id" => "2",
]);
echo "input(judul): " . $request->input("judul") . PHP_EOL;
echo "input(label, bawaan): " . $request->input("label", "tanpa-label") . PHP_EOL;
echo "only: " . json_encode($request->only(["judul", "category_id"])) . PHP_EOL;
echo "except: " . json_encode($request->except(["isi"])) . PHP_EOL;
echo "filled(judul): " . var_export($request->filled("judul"), true) . PHP_EOL;
$request = Illuminate\Http\Request::create("/uji/catatan?halaman=2", "GET");
echo "query(halaman): " . $request->query("halaman") . PHP_EOL;
'input(judul): Rapat pekanan
input(label, bawaan): tanpa-label
only: {"judul":"Rapat pekanan","category_id":"2"}
except: {"judul":"Rapat pekanan","category_id":"2"}
filled(judul): true
query(halaman): 2Keluaran di atas memperlihatkan beberapa perilaku yang patut dicatat. Nilai category_id tetap berupa string "2" meskipun terlihat seperti angka, karena data formulir memang selalu diterima sebagai teks. Metode input() dengan argumen kedua mengembalikan nilai bawaan tanpa-label bila kolomnya tidak dikirim. Metode only() dan except() mengembalikan array dengan kunci yang dipertahankan, sehingga hasilnya dapat langsung diteruskan ke pembuatan model.
Mengisi ulang formulir dengan old()#
HTTP tidak menyimpan keadaan antar permintaan. Setelah server menjawab dengan pengalihan (redirect), isi formulir yang dikirim pengguna tidak tersedia lagi pada permintaan berikutnya. Laravel menyelesaikan masalah itu dengan menyimpan masukan ke dalam session secara flash, yaitu data yang hanya tersedia untuk satu permintaan berikutnya. Metode withInput() melakukan penyimpanan tersebut pada respons pengalihan, sedangkan helper old() membacanya kembali dari sisi view. Kombinasi keduanya membuat isian pengguna tetap tampil pada formulir meskipun permintaannya dijawab dengan pengalihan.
Cara penggunaannya terlihat pada formulir berikut. Nilai atribut value dan isi textarea tidak ditulis apa adanya, melainkan dibaca dari old(), sehingga keduanya kosong pada kunjungan pertama dan terisi kembali apabila permintaan sebelumnya menyimpan masukan. Direktif @csrf menambahkan token tersembunyi yang wajib disertakan pada setiap formulir POST Laravel.
# menyiapkan view formulir contoh pada proyek aplikasi catatan
cd ~/aplikasi-catatan
mkdir -p resources/views/uji-masukan
cat > resources/views/uji-masukan/formulir.blade.php <<'BLADE'
<form method="POST" action="/uji/masukan">
@csrf
<label for="judul">Judul</label>
<input id="judul" name="judul" type="text" value="{{ old('judul') }}">
<label for="isi">Isi</label>
<textarea id="isi" name="isi" rows="3">{{ old('isi') }}</textarea>
<button type="submit">Simpan catatan</button>
</form>
@if (session('sukses'))
<p>{{ session('sukses') }}</p>
@endif
BLADEPerilaku lengkapnya diuji dengan skrip berikut. Skrip ini menjalankan aplikasi contoh tanpa server web, mendaftarkan rute demo, lalu mengirim empat permintaan berurutan: membuka formulir, mengirim data melalui POST, membuka kembali formulir dengan session yang sama, dan membukanya sekali lagi. Rute demo hanya memasang middleware session sehingga skrip dapat mengirim permintaan secara langsung.
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
$root = getcwd();
if (! is_file($root.'/bootstrap/app.php')) {
$root = getenv('HOME').'/aplikasi-catatan';
}
require $root.'/vendor/autoload.php';
$app = require $root.'/bootstrap/app.php';
$app->make(Illuminate\Contracts\Console\Kernel::class)->bootstrap();
Route::middleware([
Illuminate\Session\Middleware\StartSession::class,
])->group(function () {
Route::view('/uji/masukan/formulir', 'uji-masukan.formulir');
Route::post('/uji/masukan', function (Request $request) {
return redirect('/uji/masukan/formulir')
->withInput($request->only('judul', 'isi'))
->with('sukses', 'Catatan berhasil disimpan.');
});
});
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
function teruskanCookie($respons, Request $request): Request
{
foreach ($respons->headers->getCookies() as $cookie) {
$request->cookies->set($cookie->getName(), $cookie->getValue());
}
return $request;
}
// permintaan 1: formulir tanpa riwayat masukan
$resp1 = $kernel->handle(Request::create('http://localhost/uji/masukan/formulir', 'GET'));
preg_match('/name="judul" type="text" value="([^"]*)"/', $resp1->getContent(), $judul1);
echo '1. GET formulir: status '.$resp1->getStatusCode().', nilai judul: '.($judul1[1] === '' ? '(kosong)' : $judul1[1]).PHP_EOL;
// permintaan 2: kirim data lalu dialihkan kembali ke formulir
$resp2 = $kernel->handle(Request::create('http://localhost/uji/masukan', 'POST', [
'judul' => 'Rapat pekanan',
'isi' => 'Mencatat keputusan rapat.',
]));
echo '2. POST data: status '.$resp2->getStatusCode().', alihan ke '.$resp2->headers->get('Location').PHP_EOL;
// permintaan 3: buka formulir membawa session yang sama
$resp3 = $kernel->handle(teruskanCookie($resp2, Request::create('http://localhost/uji/masukan/formulir', 'GET')));
$html3 = $resp3->getContent();
preg_match('/name="judul" type="text" value="([^"]*)"/', $html3, $judul3);
echo '3. GET formulir berikutnya: status '.$resp3->getStatusCode().', nilai judul: '.$judul3[1];
echo ', isi: '.(str_contains($html3, 'Mencatat keputusan rapat.') ? 'terisi ulang' : 'kosong');
echo ', pesan flash: '.(str_contains($html3, 'Catatan berhasil disimpan.') ? 'terbaca' : 'tidak ada').PHP_EOL;
// permintaan 4: buka formulir sekali lagi
$resp4 = $kernel->handle(teruskanCookie($resp3, Request::create('http://localhost/uji/masukan/formulir', 'GET')));
$html4 = $resp4->getContent();
preg_match('/name="judul" type="text" value="([^"]*)"/', $html4, $judul4);
echo '4. GET formulir lagi: nilai judul: '.($judul4[1] === '' ? '(kosong)' : $judul4[1]);
echo ', pesan flash: '.(str_contains($html4, 'Catatan berhasil disimpan.') ? 'terbaca' : 'sudah habis').PHP_EOL;1. GET formulir: status 200, nilai judul: (kosong)
2. POST data: status 302, alihan ke http://localhost/uji/masukan/formulir
3. GET formulir berikutnya: status 200, nilai judul: Rapat pekanan, isi: terisi ulang, pesan flash: terbaca
4. GET formulir lagi: nilai judul: (kosong), pesan flash: sudah habisBaris pertama menunjukkan formulir yang belum pernah menerima masukan sehingga old('judul') bernilai kosong. Baris kedua menunjukkan respons pengalihan berstatus 302 yang disertai penyimpanan masukan dan pesan ke session. Baris ketiga adalah inti mekanismenya: isian judul dan isi kembali tampil pada formulir, dan pesan flash ikut terbaca pada kunjungan yang sama. Baris keempat memperlihatkan sifat sementara data flash, yaitu habis setelah dibaca sekali.
Pesan flash antar permintaan#
Pesan flash adalah data yang disimpan ke session hanya untuk permintaan berikutnya. Metode with() pada respons pengalihan menuliskannya, sedangkan helper session() membacanya pada view. Sifat sekali baca itu membuat flash cocok untuk pesan status seperti konfirmasi keberhasilan menyimpan data, yang memang hanya relevan tepat setelah aksi dilakukan.
Data flash dan data masukan lama disimpan pada session yang sama, tetapi pada kunci yang berbeda. Metode with('sukses', ...) menulis kunci sukses, sedangkan withInput() menulis kunci _old_input yang dibaca helper old(). Karena sama-sama disimpan secara flash, keduanya berakhir bersamaan, yaitu setelah permintaan berikutnya selesai dirender.
// tidak-dijalankan
// pada aksi controller: menulis pesan sebelum mengalihkan
return redirect('/uji/masukan/formulir')->with('sukses', 'Catatan berhasil disimpan.');
// pada view: membaca pesan, dan pesan itu habis setelah terbaca
@if (session('sukses'))
<p>{{ session('sukses') }}</p>
@endifPada keluaran skrip sebelumnya, pesan Catatan berhasil disimpan. hanya terbaca pada baris ketiga dan sudah habis pada baris keempat, sesuai sifat flash di atas. Apabila data perlu bertahan lebih lama, gunakan session()->put() untuk menyimpannya secara menetap dan baca dengan session('kunci') tanpa menghapusnya. Metode session()->pull() mengambil nilai sekali sekaligus menghapusnya, sehingga perilakunya mirip flash.
Kesalahan umum#
Kesalahan pertama adalah memanggil old() tanpa pernah menyimpan masukan. Helper ini hanya membaca data yang disimpan secara flash oleh withInput(), sehingga tanpa pemanggilan itu formulir selalu kosong setelah pengalihan. Ciri khasnya adalah isian yang menghilang pada setiap pengiriman, meskipun aksi controller memang mengalihkan pengguna ke halaman yang benar. Metode validate() yang gagal juga menyimpan masukan secara otomatis, tetapi pada pengalihan yang ditulis manual, withInput() perlu ditambahkan sendiri.
Kesalahan kedua adalah menganggap data flash masih ada dua permintaan kemudian. Data yang ditulis dengan with() atau flash() dihapus tepat setelah dibaca pada permintaan berikutnya, sehingga data penting yang disimpan dengan cara itu tidak tersedia lagi pada permintaan selanjutnya. Gunakan session()->put() untuk data yang harus bertahan, dan gunakan flash hanya untuk pesan status.
Kesalahan ketiga adalah menganggap old() membaca permintaan yang sedang berjalan. Helper ini membaca data flash dari session, sehingga nilainya kosong saat formulir dibuka tanpa riwayat, sekalipun URL formulirnya membawa query string. Untuk membaca query string tersebut, gunakan metode query() atau input() pada objek Request.
Ringkasan#
- Objek Request menyediakan
input(),query(),all(),only(),except(), danfilled()untuk membaca masukan menurut sumber dan kebutuhannya. - Metode
withInput()menyimpan masukan ke session secara flash, danold()membacanya kembali untuk mengisi ulang formulir. - Pesan flash ditulis dengan
with()dan dibaca dengansession(), lalu habis setelah satu kali terbaca. - Data yang perlu bertahan lebih lama disimpan dengan
session()->put(), sedangkan flash hanya tepat untuk pesan status.
Referensi#
- HTTP Requests — Laravel — Dokumentasi objek Request, metode pembacaan masukan, dan penyimpanan masukan lama.
- Session — Laravel — Dokumentasi session, penyimpanan flash, dan helper session().