ID, Path, dan Domain Panel
Tiga nilai menentukan di mana sebuah panel berada dan bagaimana bagian lain mengalamatkannya: id adalah nama panel di dalam kode, path adalah prefix URL-nya, dan domain membatasi panel ke host tertentu. Route name, manifest, panel switcher, dan seluruh Resource::url() dibangun dari ketiganya, sehingga penting memahami default masing-masing secara tepat.
Mengatur ketiganya
use PandaPanel\Core\Panel;
use PandaPanel\Core\PanelProvider;
final class BackOfficePanelProvider extends PanelProvider
{
public function panel(Panel $panel): Panel
{
return $panel
->id('back-office') // usually unnecessary: derived from the class name
->path('back-office') // /back-office/...
->domain('admin.example.com') // this host only
->name('Back Office'); // the human label
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
ID
public function id(string $id): self
public function getId(): string // throws PanelRegistrationException when never set2
Id sudah diisi dari provider sebelum panel() dijalankan, sehingga jarang perlu diatur manual. PanelProvider::panelId() mengambil basename class, menghapus suffix PanelProvider, lalu mengubah sisanya menjadi kebab-case:
| Provider class | Id |
|---|---|
AdminPanelProvider | admin |
AppPanelProvider | app |
BackOfficePanelProvider | back-office |
Override derivasi tersebut pada provider jika nama class bukan id yang Anda inginkan:
final class AdminPanelProvider extends PanelProvider
{
public function panelId(): string
{
return 'backend';
}
public function panel(Panel $panel): Panel
{
return $panel->path('backend');
}
}2
3
4
5
6
7
8
9
10
11
12
Panel::make() tanpa argument membiarkan id belum terisi dan getId() kemudian melempar exception — panel tanpa id tidak dapat memberi nama pada route miliknya.
Panel::make('admin'); // id set
Panel::make(); // getId() throws PanelRegistrationException2
Id merupakan key di seluruh framework: panel('admin'), PanelManager::get('admin'), section manifest di bootstrap/cache/panels.php, route name prefix, dan panel.id di frontend. Mengubah id berarti mengubah seluruh referensi tersebut sekaligus.
Path
public function path(string $path): self // leading and trailing slashes are trimmed
public function getPath(): string // falls back to the id2
$panel->path('admin'); // /admin
$panel->path('/admin/'); // /admin — the same thing
Panel::make('reports')->getPath(); // 'reports' — the id, because no path was set2
3
Path menjadi prefix route group, sehingga seluruh page panel berada di bawahnya dan landing page panel adalah prefix tersebut sendiri:
route('panel.admin.dashboard', absolute: false); // '/admin'Path boleh nested (->path('admin/reports')). Resolver memilih path terpanjang terlebih dahulu, sehingga panel pada admin/reports menang atas panel pada admin untuk request /admin/reports/x.
Domain
public function domain(?string $domain): self
public function getDomain(): ?string // null by default2
Ketika domain diatur, route group panel membawa attribute domain milik Laravel dan panel hanya cocok dengan request ke host tersebut:
$panel->domain('admin.example.com')->path('/');Dua panel boleh berbagi path jika domain-nya berbeda. Keduanya tidak boleh berbagi path pada domain yang sama:
use PandaPanel\Core\PanelRegistry;
$registry = new PanelRegistry;
$registry->register(Panel::make('first')->path('admin')->domain('a.test'));
$registry->register(Panel::make('second')->path('admin')->domain('b.test')); // fine
$registry->register(Panel::make('third')->path('admin'));
$registry->register(Panel::make('fourth')->path('admin')); // throws2
3
4
5
6
7
8
String domain diteruskan ke router tanpa modifikasi, sehingga route parameter di dalamnya seperti {tenant}.example.com bekerja seperti pada Route::domain() biasa.
Nama panel
public function name(string $name): self
public function getName(): string // falls back to Str::headline($id)2
Nama adalah label yang ditampilkan shell dan panel switcher di dekat brand. Nilai ini tidak digunakan untuk routing.
Panel::make('back-office')->getName(); // 'Back Office'
Panel::make('back-office')->name('Back Office (EU)')->getName(); // 'Back Office (EU)'2
Route name
Setiap route yang didaftarkan panel memiliki prefix panel.{id}..
public function getRouteNamePrefix(): string // "panel.admin."
public function routeName(string $name): string2
panel('admin')->routeName('dashboard'); // 'panel.admin.dashboard'
route(panel('admin')->routeName('dashboard'), absolute: false); // '/admin'2
Daftar nama route yang didaftarkan panel, dengan prefix panel.{id}. dihilangkan:
| Nama | Path | Tujuan |
|---|---|---|
dashboard | / | Landing page panel. |
search | search | Endpoint JSON global search. |
options | options | Options untuk searchable select. |
uploads | uploads | Upload file sebelum form submit. |
form-state | form-state | Re-render live field. |
export-file | exports/{file} | Download hasil export. |
import-file | imports/{file} | Download import failure report. |
notifications.index, notifications.read, notifications.clear | notifications/* | Notification center. |
auth.two-factor.challenge, .send, .verify, .enable, .disable | two-factor/* | Second factor dengan emailed code. |
actions.record, .bulk, .reorder, .cell, .table, .infolist, .form, .submit | actions/* | Endpoint action. |
relations.form, .save, .action, .bulk | relations/* | Endpoint relation manager. |
pages.{page-slug} | routePath() milik page | Satu standalone page. |
resources.{slug}.index, .create, .store, .view, .edit, .update | di bawah resource slug | Resource page. |
auth.login, auth.register, auth.password.request, auth.password.reset, auth.verification.notice | login, register, … | Hanya untuk panel yang memanggil login() dan fitur auth terkait. |
Route name tidak pernah membawa cluster prefix; hanya path yang berubah. Karena itu mengadopsi cluster dapat memindahkan URL tanpa mematahkan Resource::url() yang sudah ditulis.
Cara request menemukan panel
Ada dua mekanisme yang menjawab pertanyaan berbeda.
Di dalam route group panel, id diteruskan ke middleware secara eksplisit (ResolvePanel:admin), sehingga resolution tidak bergantung pada pencocokan URL. Di luar route group — misalnya guest redirect dan home redirect — PanelManager::resolveFromRequest() melakukan matching berdasarkan host dan path prefix:
use Illuminate\Http\Request;
use PandaPanel\Core\PanelManager;
app(PanelManager::class)->resolveFromRequest(request()); // ?Panel2
3
4
Resolver mengurutkan kandidat berdasarkan panjang path secara descending, melewati panel yang domain-nya tidak cocok dengan request host, lalu memilih panel pertama yang path-nya sama dengan request path atau merupakan prefix-nya. Urutan inilah yang membuat /admin/reports/x jatuh ke panel admin/reports, bukan admin.
Catatan
getPath()yang fallback ke id bukan berarti path selalu alias dari id. Mengubah id setelah path sudah diatur tidak mengubah path.- Panel yang dipasang pada
/dashboardbertabrakan dengan route dashboard starter kit. Home redirect mengabaikan path yang memang merupakan mount point panel sehingga tidak terjadi loop — lihat Home Redirect. - Mengganti path mengubah semua URL yang dihasilkan panel tetapi tidak mengubah route name; bookmark dapat rusak, kode tidak. Mengganti id mengubah route name dan karena itu mematahkan kode yang merujuk route tersebut menggunakan string.
panel('unknown')melempar exception, bukan mengembalikan null. Id yang tidak dikenal adalah developer error, dan null hanya akan memindahkan failure ke titik yang lebih sulit dipahami seperti missing route.