Caching
Cache Panel terdiri dari satu file, bootstrap/cache/panels.php, yang menyimpan nama-nama class yang dimiliki setiap Panel. Ketika file ini tersedia, discovery tidak dijalankan: tidak ada filesystem scan, reflection, atau pekerjaan discovery per request.
Hanya daftar class tersebut yang di-cache. Semua jawaban yang bergantung pada user atau URL tetap dihitung ulang pada setiap request secara sengaja. Gunakan dokumentasi ini sebelum deployment, atau ketika class yang baru Anda tambahkan tiba-tiba tidak muncul di Panel.
Dua Command Utama
php artisan panel:cache
php artisan panel:clear2
INFO Panels cached: 2 panels, 1 resources, 9 pages, 5 widgets.
INFO Panel manifest cleared.2
Keduanya diregistrasikan sebagai hook optimize dengan key panels, sehingga deployment yang sudah menjalankan optimize otomatis menjalankan command tersebut:
php artisan optimize # includes panel:cache
php artisan optimize:clear # includes panel:clear2
| Command | Signature | Fungsi |
|---|---|---|
panel:cache | panel:cache | Menjalankan discovery Resource, Page, dan Widget lalu menyimpan manifest |
panel:clear | panel:clear | Menghapus cached Panel manifest |
panel:clear bersifat idempotent: manifest yang tidak ada tetap dianggap sukses, sehingga optimize:clear pada fresh checkout tidak akan gagal.
Bentuk File Cache
<?php
// Generated by "php artisan panel:cache". Do not edit.
return array (
'panels' =>
array (
'admin' =>
array (
'resources' =>
array (
0 => 'App\\Panels\\Admin\\Resources\\Users\\UserResource',
),
'pages' => array ( /* ... */ ),
'widgets' => array ( /* ... */ ),
),
'app' => array ( /* ... */ ),
),
'fingerprint' => '…',
);2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Framework menggunakan var_export, bukan serialization, sehingga file tersebut hanyalah return [...] PHP biasa yang dapat disimpan oleh opcache dan masih mudah dibaca manusia. Isinya hanya nama class — tidak ada closure, resolved metadata, ataupun data yang spesifik terhadap user. Test suite bahkan memastikan hasil file tidak mengandung Closure maupun function.
Daftar per Panel merupakan hasil gabungan:
explicit registration ∪ discoverykemudian di-deduplicate dan diurutkan. Karena itu dua run pada dua machine yang memiliki filesystem order berbeda tetap menghasilkan file yang identik byte-per-byte.
PanelManifest
PandaPanel\Cache\PanelManifest adalah container singleton sekaligus satu-satunya reader dan writer untuk file cache tersebut.
| Method | Signature | Catatan |
|---|---|---|
path | static path(): string | app()->bootstrapPath('cache/panels.php') |
exists | exists(): bool | |
for | for(Panel $panel): array{resources: list<string>, pages: list<string>, widgets: list<string>} | Menggunakan manifest jika tersedia, discovery jika tidak |
write | write(PanelRegistry $registry): array | Membangun manifest seluruh Panel terdaftar dan menulisnya secara atomic |
clear | clear(): bool | Menghapus file dan melupakan copy yang sudah dimuat ke memory |
warnIfStale | warnIfStale(PanelRegistry $registry): void | Hanya untuk development |
use PandaPanel\Cache\PanelManifest;
$manifest = app(PanelManifest::class);
$manifest->exists(); // bool
$manifest->for(panel('admin'))['resources'];// list<class-string>
PanelManifest::path(); // '/app/bootstrap/cache/panels.php'2
3
4
5
6
7
Path menggunakan bootstrapPath() alih-alih base_path('bootstrap/...') karena application boleh memindahkan directory bootstrap. Manifest yang ditulis ke lokasi yang tidak dikenali oleh optimize:clear akan menjadi stale cache yang sulit dibersihkan.
write() menulis terlebih dahulu ke panels.php.{pid}.tmp, lalu memindahkannya ke lokasi final. Dengan begitu file setengah tertulis tidak pernah dapat dimuat, dan dua process yang melakukan caching secara bersamaan tidak akan mencampur hasil tulisannya.
for() adalah jalur yang dilewati setiap Panel saat registration:
public function for(Panel $panel): array
{
$cached = $this->load()[$panel->getId()] ?? null;
if ($cached !== null) {
return $cached;
}
return [
'resources' => $this->discoverer->resources($panel),
'pages' => $this->discoverer->pages($panel),
'widgets' => $this->discoverer->widgets($panel),
];
}2
3
4
5
6
7
8
9
10
11
12
13
14
Panel yang sudah ada di manifest dilayani dari cache. Panel yang belum ada — misalnya Panel yang diregistrasikan oleh test atau ditambahkan setelah manifest dibuat — hanya melakukan fallback ke discovery untuk dirinya sendiri.
Menulis Manifest Secara Manual
use App\Panels\Admin\Resources\Users\UserResource;
use PandaPanel\Cache\PanelManifest;
use PandaPanel\Core\Panel;
use PandaPanel\Core\PanelRegistry;
$registry = new PanelRegistry;
$registry->register(
Panel::make('explicit')
->path('explicit')
->resources([UserResource::class]),
);
$manifest = app(PanelManifest::class)->write($registry);
$manifest['explicit']['resources']; // [UserResource::class]2
3
4
5
6
7
8
9
10
11
12
13
14
15
write() mengembalikan array yang sama dengan yang ditulis ke file, sehingga command atau test dapat melakukan assertion tanpa membaca ulang file dari disk.
Data yang Tidak Pernah Di-cache
| Di-cache | Tidak Di-cache |
|---|---|
| Nama class Resource per Panel | Hasil authorization |
| Nama class Page per Panel | Active state navigation |
| Nama class Widget per Panel | Nilai badge |
| Discovery fingerprint | Record data, table rows, widget data |
Data pada kolom kanan bergantung pada user atau URL saat ini. Menyimpannya dalam cache bersama manifest berisiko memberikan jawaban milik satu user kepada user lain — ini bukan sekadar stale UI, tetapi dapat menjadi masalah security.
Karena alasan yang sama:
SharePanelDatamembangun shared prop melalui closure;NavigationBuildermenghitung visibility dan active state ulang setiap request.
Warning untuk Manifest Stale
panel:cache menulis daftar nama class, lalu discovery tidak berjalan lagi. Itulah tujuan fitur cache, tetapi juga sumber jebakan utama: Resource yang ditambahkan setelah cache dibuat sama sekali tidak masuk ke Panel.
Tidak ada error, empty state, ataupun route. Sidebar terlihat persis seperti sebelum perubahan, sehingga penyebabnya sulit ditebak hanya dari gejala.
PandaPanel\Cache\DiscoveryFingerprint dibuat untuk mendeteksi kondisi tersebut.
use PandaPanel\Cache\DiscoveryFingerprint;
/** @param list<Panel> $panels */
public static function of(array $panels): string;
public static function isStale(array $panels, ?string $recorded): bool;2
3
4
5
Untuk setiap discovery path dari setiap Panel, fingerprint mencatat:
- jumlah file PHP di bawah path tersebut;
- modification time terbaru;
- lalu meng-hash ringkasan dengan
xxh128.
Path yang bukan directory diringkas sebagai missing. Kondisi ini juga dianggap perubahan yang penting, karena directory yang berganti nama dapat membuat sebuah Panel tiba-tiba tidak menemukan apa pun.
Path diurutkan terlebih dahulu, sehingga dua Panel yang mendeklarasikan path sama dalam urutan berbeda tidak dianggap berubah.
warnIfStale() dijalankan satu kali di akhir provider boot setelah semua Panel terdaftar. Method ini tidak melakukan apa pun kecuali:
- manifest tersedia; dan
- environment adalah
local,testing, atau debug mode aktif.
Jika fingerprint berbeda:
[panel] The cached panel manifest is out of date: the classes under the
discovery paths have changed since `php artisan panel:cache` last ran. Until
you run `php artisan panel:clear`, anything added since then is invisible — no
route, no navigation entry, and no error to say so.2
3
4
Framework tidak memberikan warning berdasarkan dugaan. isStale() mengembalikan false jika tidak ada manifest, tidak ada fingerprint yang tersimpan, atau path tidak dapat dibaca.
Deployment
composer install --no-dev --optimize-autoloader
php artisan optimize # config, routes, events, views — and panels
npm ci && npm run build2
3
Lakukan caching setelah composer install, bukan sebelumnya. Discovery me-resolve file melalui map PSR-4 milik Composer. Manifest yang dibuat menggunakan autoloader lama dapat menunjuk class ke lokasi yang sudah berubah.
Rollback juga mengikuti prinsip yang sama. optimize:clear menghapus manifest bersama cache lain. Deployment yang hanya mengganti source code tetapi mempertahankan bootstrap/cache/panels.php dari release sebelumnya adalah skenario stale cache yang tepat ingin dideteksi fingerprint.
Perlu diingat: production memang tidak menampilkan warning fingerprint.
Hal yang Perlu Diperhatikan
- Cached manifest pada development biasanya merupakan kesalahan. Semua class yang Anda tambahkan setelahnya tidak terlihat sampai cache dibersihkan. Jika pernah menjalankan
optimizesecara lokal, jalankanoptimize:clear. panel:cachetidak melakukan route cache. Route cache terpisah; gunakanroute:cachejuga. Semua route PandaBear aman di-cache karena menggunakan controller method, bukan closure.- Dua bentuk manifest tetap dapat dibaca. Manifest versi lama sebelum fingerprint diperkenalkan berupa flat map dari Panel id ke class dan tetap didukung agar upgrade tidak membutuhkan cache clear hanya untuk boot.
- Manifest menggunakan Panel id sebagai key. Mengganti id Panel membuat entry lama tidak terpakai dan Panel tersebut melakukan fallback ke discovery sampai cache dibangun ulang.
- File malformed dianggap kosong.
load()me-require file tersebut; jika hasilnya bukan array, framework memperlakukannya sebagai[]. Discovery kemudian berjalan kembali — lebih lambat tetapi tetap benar. clear()hanya melupakan in-memory copy pada instance tersebut. Di bawah Octane, worker yang sudah memuat manifest tetap dapat menggunakannya sampai worker di-recycle. Deployment seharusnya memang me-restart worker.- Fingerprint melakukan satu
statuntuk setiap file PHP di discovery path, dan hanya ketika development memiliki manifest. Karena manifest di development adalah kondisi yang tidak biasa, overhead ini normalnya tidak ada.