Laravel 13.39.0 Rilis 27 Oktober 2026: Model Tanpa Primary Key, restoreOrCreate & Dampaknya untuk Source Code Kamu
Laravel 13.39.0 rilis 27 Oktober 2026 sebagai rilis mingguan tanpa breaking change: model tanpa primary key lewat #[Table(key: false)], restoreOrCreate() yang menghormati relasi Eloquent, dan session:garbage-collect terjadwal. Untuk source code toko online dan aplikasi kasir, update ini aman diambil lewat composer update, asal diuji di staging dulu.
Apa itu Laravel 13.39.0?
Laravel 13.39.0 adalah rilis minor mingguan lini Laravel 13, yang pertama rilis 17 Maret 2026 dan mensyaratkan PHP 8.3 minimum. Berbeda dengan rilis mayor, rilis mingguan seperti ini tidak mengubah perilaku lama secara diam-diam: semua fitur barunya bersifat opt-in.
Fakta kunci:
| Fakta Keterangan | |
| Versi | Laravel 13.39.0 |
| Tanggal rilis | 27 Oktober 2026 |
| Breaking change | Tidak ada |
| PHP yang didukung | 8.3–8.5 |
| Dukungan bug fix Laravel 13 | Sampai Q3 2027 |
| Dukungan keamanan Laravel 13 | Sampai 17 Maret 2028 |
| Cara update | composer update laravel/framework |
Seminggu sebelumnya, Laravel 13.38.0 rilis 20 Oktober 2026 membawa middleware anti stale read; 13.39 melanjutkan pola itu.
Apa yang baru di Laravel 13.39.0?
1. Model tanpa primary key: #[Table(key: false)]
Tidak semua tabel punya primary key: tabel log aktivitas yang hanya ditulis (append-only), tabel staging hasil impor, atau view database. Sebelum 13.39, Anda harus menulis protected $primaryKey = null; plus public $incrementing = false;, dan itupun masih bisa bermasalah. Sejak Laravel 13 model bisa memakai atribut #[Table], tetapi key: null ternyata berarti "pakai default" (id), bukan "tidak ada key". Di 13.39, key: false sungguh berarti tidak ada key, dan incrementing ikut dimatikan sehingga create() menyimpan baris tanpa error:
Untuk source code toko online, tabel activity_log atau import_staging kini cukup dimodelkan dengan satu baris atribut. Batasannya harus jujur: model tanpa key tidak bisa dipakai untuk find(), update pada instance yang sudah dimuat, delete pada instance, maupun route model binding — semua itu butuh key. Model keyless hanya untuk menulis baris dan menanyakannya lewat where().
2. Bagaimana cara kerja restoreOrCreate() yang kini menghormati relasi?
Ini perbaikan paling berdampak untuk aplikasi dengan soft delete — dan hampir semua toko online memakainya, misalnya alamat pelanggan yang dihapus lalu ditambahkan lagi.
Kasus nyatanya: pelanggan menghapus alamat berlabel "Rumah", lalu menambahkannya kembali. Anda memanggil $user->addresses()->restoreOrCreate(['label' => 'Rumah']) dan berharap baris lama pelanggan itu yang kembali. Sebelum 13.39, pemanggilan pada relasi melewati relasi sepenuhnya: Laravel mencari alamat "Rumah" mana pun, dan kalau harus membuat baru, user_id-nya tidak terisi. Pada belongsToMany, id pivot bahkan bisa menimpa kunci relasi sehingga baris milik orang lain yang ter-restore; pada relasi through, id tabel perantara dari join bisa membuat baris milik parent lain yang kembali.
Di 13.39, keduanya menjadi metode nyata pada HasOneOrMany, BelongsToMany, dan relasi through. Alurnya tetap di dalam relasi: query relasi ditambah withTrashed(), lalu memakai firstOrCreate() atau createOrFirst() milik relasi itu sendiri:
Baris soft-deleted milik user itu di-restore (deleted_at dikosongkan); kalau tidak ada, baris baru dibuat lewat relasi dengan user_id terisi benar. Pilih createOrRestore() bila kolomnya punya unique index dan Anda mengantisipasi race condition: metode ini mencoba insert dulu, lalu mencari dan me-restore saat terjadi pelanggaran unique constraint.
Pola alamat dan relasi seperti ini adalah fondasi keranjang belanja dan checkout Laravel yang anti double order. Kalau Anda menjual source code toko, perbaikan ini layak disebut di changelog produk Anda.
3. forceCreate() pada belongsToMany akhirnya me-attach model
Sebelumnya BelongsToMany tidak punya forceCreate(), sehingga panggilan itu jatuh ke Eloquent builder: model tersimpan tetapi tidak pernah di-attach, dan $team->users()->count() tetap 0. Di 13.39, $user->teams()->forceCreate() menyimpan model sekaligus me-attach-nya:
4. Aturan ukuran array kini fluent: Rule::array()->min()->max()
Sejak 13.36 hampir semua rule validasi punya builder fluent, tetapi ukuran array masih butuh string terpisah seperti Rule::array(), 'min:1'. Di 13.39, Rule::array() mendapat min(), max(), between(), dan exactly() (dikompilasi menjadi size):
Hasil kompilasinya tetap string rule biasa, sehingga pesan error ke form Vue/Inertia tidak berubah — murni soal keterbacaan.
5. Mengapa session:garbage-collect penting untuk shared hosting?
Dengan driver session file atau database, Laravel menghapus session kedaluwarsa lewat lotre: 2 dari setiap 100 request ('lottery' => [2, 100] di config/session.php). Request yang "kalah undian" menanggung biaya bersih-bersih, situs sepi nyaris tidak pernah bersih-bersih, situs ramai justru terlalu sering. Perintah baru menjalankan garbage collector driver sesuai session.lifetime kapan pun Anda mau:
Pasangkan dengan 'lottery' => [0, 100] agar request tidak lagi ikut bersih-bersih. Untuk Redis/Memcached, perintah ini no-op. Bagi pengguna shared hosting — lihat panduan setting cron job Laravel di shared hosting — satu baris scheduler ini menggantikan lotre acak.
6. Durasi job kini tercatat juga untuk job yang gagal
Sebelumnya hanya JobProcessed job sukses yang membawa $duration. JobAttempted — yang dipicu setiap percobaan, sukses maupun gagal — kini ikut membawa $duration (float, milidetik), termasuk untuk queue sync:
Perbaikan apa lagi yang dibawa 13.39.0?
Enam peningkatan testing yang menghilangkan flaky test atau email sungguhan dari CI:
#[WithoutMigrationEvents]— mengecualikan query migrasi dari hitunganexpectsDatabaseQueryCount().RefreshDatabasemengembalikan semua level transaksi — test yang meninggalkan transaksi terbuka tak lagi merusak test sesudahnya.Bus::fake()+withoutDispatchingAfterResponses()— sebagian job bisa di-fake sementara jobdispatchAfterResponse()asli tetap berjalan.Mail::html()danMail::plain()ikut di-fake — sebelumnya keduanya diteruskan ke mailer asli, sehingga email sungguhan terkirim sementaraassertNothingOutgoing()tetap lolos.- Shorthand
Process::fake()untukstart()danpool()— berlaku juga untuk proses asinkron. assertSeeText('0')tidak lagi lolos saat teks tidak ada — test yang mulai gagal kemungkinan memang salah sejak awal.
Dua perbaikan deploy yang diam tetapi nyata: config:cache, route:cache, dan event:cache kini ditulis atomik (file sementara lalu rename), sehingga request yang boot tepat saat deploy tidak lagi membaca file config kosong. Dan Filesystem::exists() serta isFile() kini memblokir skema phar:// karena path phar:// dapat memicu deserialisasi objek.
Bagaimana cara update ke Laravel 13.39.0 dengan aman?
Ikuti urutan ini, dan jangan lewati staging:
- Cek versi Anda sekarang dengan
composer show laravel/frameworkdan pastikan PHP 8.3+ (php -v). - Cadangkan dulu database dan file — lihat panduan backup otomatis website Laravel.
- Update di branch terpisah, bukan langsung di
main:
- Jalankan test suite, dengan perhatian khusus pada test
restoreOrCreate()pada relasi,Mail::fake(), atauexpectsDatabaseQueryCount()— ketiganya berubah perilaku. - Uji skenario soft delete secara manual: hapus alamat pelanggan, tambahkan lagi dengan label sama, dan pastikan baris yang kembali adalah milik pelanggan itu.
- Baru deploy, dan jalankan
php artisan optimizesetelah deploy — berkat penulisan cache atomik, langkah ini kini lebih aman.
Bila Anda masih di Laravel 12, jangan buru-buru: patch keamanan tersedia sampai 24 Februari 2027, tetapi bug fix sudah berhenti sejak 13 Agustus 2026. Panduan upgrade Laravel ke versi terbaru menjelaskan urutan aman dari versi 8/9/10/11.
Apakah Laravel 13.39.0 wajib segera diupdate?
Untuk sebagian besar aplikasi Laravel 13, jawabannya: ya, pada jadwal update rutin berikutnya — bukan tengah malam ini juga. Rilis ini tidak menambal celah keamanan kritis, jadi tidak ada urgensi darurat. Tetapi tiga kelompok sebaiknya memprioritaskannya: aplikasi yang memakai restoreOrCreate() pada relasi, aplikasi dengan session driver file/database di shared hosting, dan tim yang CI-nya memakai Mail::fake().
Sebaliknya, tunda dulu bila Anda masih mengandalkan perilaku lama restoreOrCreate(), atau bila test suite Anda belum pernah hijau. Perbaiki baseline dulu, baru update.
Kesimpulan
Laravel 13.39.0 adalah contoh rilis mingguan yang baik: tidak berisik, tidak merusak, tetapi menyelesaikan bug yang benar-benar ditemui di produksi — relasi soft delete yang salah restore, model tanpa key yang setengah jalan, session yang dibersihkan lewat lotre, dan cache deploy yang tidak atomik. Bagi penjual source code, nilainya ganda: perbaikan gratis lewat composer update, plus bahan changelog yang meyakinkan pembeli bahwa produk Anda dirawat mengikuti frameworknya.
FAQ
Apa itu Laravel 13.39.0?
Rilis minor mingguan lini Laravel 13 yang terbit 27 Oktober 2026, tanpa breaking change: model keyless, perbaikan restoreOrCreate() pada relasi, session:garbage-collect, durasi job gagal, dan perbaikan testing serta deploy.
Apakah update ke Laravel 13.39.0 aman?
Ya, untuk aplikasi Laravel 13 yang sehat: tanpa breaking change dan semua fitur baru opt-in. Tetap update di branch terpisah, jalankan test suite, dan uji di staging — terutama bila memakai restoreOrCreate() pada relasi atau Mail::fake().
Bagaimana cara update ke Laravel 13.39.0?
Jalankan composer update laravel/framework, lalu php artisan config:clear dan php artisan cache:clear. Pastikan PHP 8.3–8.5, karena Laravel 13 mensyaratkan PHP 8.3 minimum.
Apa fungsi #[Table(key: false)] di Laravel 13.39?
Atribut ini menyatakan model tidak punya primary key — cocok untuk tabel log append-only, tabel staging impor, atau view database. Berbeda dengan key: null, key: false benar-benar berarti "tidak ada key" dan mematikan incrementing sehingga create() berhasil.
Mengapa restoreOrCreate() pada relasi penting diperbaiki?
Sebelum 13.39, pemanggilan pada relasi mengabaikan relasi: baris baru bisa kehilangan foreign key, dan pada belongsToMany maupun relasi through, baris milik parent lain bisa ikut ter-restore. Setelah perbaikan, pencarian dan pembuatan tetap di dalam relasi.
Apakah session:garbage-collect menggantikan lotre session?
Ya, untuk driver file dan database: jadwalkan Schedule::command('session:garbage-collect')->hourly() dan set 'lottery' => [0, 100]. Untuk Redis/Memcached, perintah ini tidak berpengaruh karena session kedaluwarsa sendiri.
Sumber: dokumentasi resmi Laravel (laravel.com/docs/releases) dan changelog framework per 27 Oktober 2026.
Artikel Terkait
Cara Membuat Fitur Lupa Password di Laravel: Reset Password via Email yang Aman (Panduan 2026)
28 Oct 2026
WordPress 7.2 Beta 2 Dijadwalkan 27 Oktober 2026: Uji Ulang, Bukan Update Massal
28 Oct 2026
Cara Membuat Dashboard Statistik Penjualan di Laravel dengan Chart.js (Panduan Lengkap 2026)
28 Oct 2026
PHP 8.6.0 RC4 Rilis 21 Oktober 2026: 50 Perbaikan Sejak RC3 & Checklist Uji Source Code Sebelum 19 November
28 Oct 2026