Mengubah Urutan Record
Reordering memungkinkan pengguna menyeret baris ke urutan tertentu lalu menulis urutan tersebut kembali ke sebuah kolom. Gunakan ketika urutan itu sendiri merupakan bagian dari data — misalnya item menu, langkah dalam checklist, atau prioritas dalam antrean — bukan sekadar cara pengguna memilih melihat data.
Contoh minimal
Tambahkan kolom integer ke tabel:
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
Schema::table('menu_items', function (Blueprint $table): void {
$table->unsignedInteger('position')->default(0);
});2
3
4
5
6
Kemudian tentukan nama kolom tersebut pada schema:
<?php
declare(strict_types=1);
namespace App\Panels\Admin\Resources\MenuItems\Tables;
use PandaPanel\Tables\Columns\TextColumn;
use PandaPanel\Tables\TableSchema;
final class MenuItemsTable
{
public static function configure(TableSchema $table): TableSchema
{
return $table
->columns([
TextColumn::make('label')->searchable(),
])
->reorderable('position');
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Setiap baris sekarang memiliki drag handle. Saat baris dilepas, client mengirim urutan baru ke server.
API
use PandaPanel\Tables\TableSchema;
TableSchema::reorderable(string $column): self
TableSchema::getReorderColumn(): ?string
TableSchema::isReorderable(): bool2
3
4
5
| Method | Return | Default |
|---|---|---|
reorderable('position') | self | nonaktif — tabel belum reorderable sampai fitur ini dideklarasikan |
getReorderColumn() | ?string | null |
isReorderable() | bool | false |
reorderable() juga menetapkan pengurutan: method ini memanggil defaultSort($column, SortDirection::Ascending) secara otomatis. Urutan yang diatur pengguna hanya bermakna ketika tabel memang menampilkan urutan tersebut, jadi pengaturan reorder dan default sort diperlakukan sebagai satu keputusan, bukan dua konfigurasi yang dapat saling bertentangan.
use PandaPanel\Tables\Columns\TextColumn;
use PandaPanel\Tables\Enums\SortDirection;
use PandaPanel\Tables\TableSchema;
$schema = TableSchema::make()
->columns([TextColumn::make('label')])
->reorderable('position');
$schema->getReorderColumn(); // 'position'
$schema->getDefaultSortColumn(); // 'position'
$schema->getDefaultSortDirection(); // SortDirection::Ascending2
3
4
5
6
7
8
9
10
11
Definisi yang diserialisasi membawa satu boolean, reorderable, yang membuat kolom handle ditampilkan:
$schema->toArray()['reorderable']; // trueData yang dikirim saat drag
Client menghitung urutan hasil akhirnya lalu mengirim urutan key record — posisi key di dalam array tersebut adalah urutannya. Client tidak pernah membuat sendiri nilai untuk kolom yang tidak diketahuinya.
POST {panel path}/actions/reorder route name: panel.{panelId}.actions.reorder{ "resource": "menu-items", "records": [7, 3, 12, 4] }Nested resource juga mengirim parent, yang di-resolve dan di-bind dengan cara yang sama seperti route middleware pada halaman resource tersebut.
Request memvalidasi records sebagai array berisi 1 sampai 500 item dan setiap item wajib tersedia. Setelah itu proses berjalan dalam urutan berikut:
- Resource slug harus dapat di-resolve di panel untuk request ini; jika tidak, 404.
TableSchema::getReorderColumn()harus tidaknull; jikanull, 400 — "This table is not reorderable."Resource::query()->findMany($keys)harus mengembalikan jumlah record yang sama dengan jumlah key; jika tidak, 404. Bagian ini sengaja menggunakan list query, bukan record lookup: trashed record tidak memiliki tempat dalam susunan aktif.Resource::canEdit($record)diperiksa untuk setiap record; jika salah satu ditolak, 403. Pemeriksaan dilakukan sebelum ada data yang ditulis.- Seluruh write dijalankan dalam satu
DB::transaction():$record->forceFill([$column => $position])->save()untuk setiap record. Daftar yang hanya setengah berhasil diurutkan lebih buruk daripada daftar yang sama sekali tidak berubah.
Response melakukan redirect kembali dengan flash success berisi "Order updated.".
Posisi adalah index dalam daftar yang dikirim
Controller membalik key yang dikirim menjadi posisi:
$positions = array_flip(array_map(strval(...), $keys));Artinya key pertama menjadi 0, key kedua menjadi 1, dan seterusnya. Ada dua konsekuensi penting:
- Client hanya mengirim baris yang tampil di layar. Reorder pada halaman dua akan kembali menulis
0…n-1untuk baris di halaman tersebut, sehingga dapat bertabrakan dengan nilai halaman satu. Berikan tabel reorderable nilaiperPageyang cukup besar untuk menampung seluruh daftar, atau terima bahwa urutan berlaku per halaman. - Urutan yang sedang ditampilkan adalah urutan yang akan ditulis. Jika pengguna mengurutkan berdasarkan
labellalu menyeret baris, posisi yang disimpan mengikuti urutan display tersebut. Menetapkan default sort ke kolom urutan membuat kasus umum tetap benar; menjadikan kolom pentingtoggleable(false)dan membiarkan kolom lain tidak sortable membantu menjaga perilaku tersebut tetap konsisten.
Otorisasi
Tidak ada policy per action pada fitur ini — reordering bukan Action dan tidak memiliki nama action untuk dicari. Otorisasi dilakukan dengan Resource::canEdit() pada setiap record dalam payload, sebelum satu record pun diubah. Jika policy resource menolak satu baris, seluruh perubahan urutan ditolak.
use App\Models\MenuItem;
use App\Policies\MenuItemPolicy;
use Illuminate\Support\Facades\Gate;
Gate::policy(MenuItem::class, MenuItemPolicy::class);2
3
4
5
Tanpa policy yang terdaftar, Gate menolak dan drag menghasilkan 403. Ini adalah default yang tepat: endpoint write tanpa proteksi jauh lebih berbahaya.
Catatan
- Reordering bukan action. Tidak ada confirmation dan tidak ada handler yang dicari; hanya ada urutan baru yang harus disimpan. Karena itu fitur ini memiliki endpoint sendiri dan tidak masuk ke confirmation flow.
reorderable()mengatur baris;reorderableColumns()mengatur kolom. Nama keduanya mirip, tetapi fiturnya tidak berhubungan: yang pertama menulis kolom database, sedangkan yang kedua hanya presentation dan tidak pernah dipersist ke database. Lihat Pengelola kolom.- Kolom harus dapat ditulis. Controller menggunakan
forceFill(), sehingga$guardedtidak memblokirnya. Namun, kolom yang tidak ada akan menjadi database error, bukan validation message. - Maksimal 500 record per request adalah batas keras dari validation rule endpoint.
- Tabel relation manager tidak mendukung reorder. Schema menerima
reorderable()dan handle dapat terlihat, tetapi frontend relation table tidak menghubungkan drag ke endpoint, sementara endpoint reorder menyelesaikan resource, bukan relation. Lakukan reorder record terkait dari resource list-nya sendiri. - Tabel reorderable tetap dapat menggunakan pagination, search, dan filter. Reordering tidak mengubah record mana yang dikembalikan query.