Konvensi Directory Resource
PandaBear menemukan Resource dengan memindai directory, sehingga lokasi sebuah class menentukan Panel mana yang memilikinya. Halaman ini menjelaskan struktur yang dibuat generator dan yang diharapkan discovery. Dokumentasi ini sebaiknya dibaca sekali sebelum membuat Resource pertama, lalu dibaca kembali ketika sebuah Resource mulai memiliki exporter, importer, atau relation manager.
Bentuk directory
php artisan make:panel Admin
php artisan make:panel-resource Post --panel=Admin2
Dua command tersebut menghasilkan struktur:
app/Panels/Admin/
├── AdminPanelProvider.php
├── Pages/
│ └── .gitkeep
├── Resources/
│ └── Posts/
│ ├── PostResource.php
│ ├── Forms/
│ │ └── PostForm.php
│ ├── Pages/
│ │ ├── CreatePost.php
│ │ ├── EditPost.php
│ │ ├── ListPosts.php
│ │ └── ViewPost.php
│ └── Tables/
│ └── PostsTable.php
└── Widgets/
└── .gitkeep2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
File .gitkeep ada karena discovery memindai directory tersebut sedangkan Git tidak menyimpan directory kosong. Tanpa file ini, fresh clone dapat membuat provider menunjuk ke path yang sebenarnya tidak lagi ada.
Aturan yang diikuti directory
| Level | Konvensi | Sumber konvensi |
|---|---|---|
app/Panels/{Panel} | Nama Panel dalam StudlyCase | make:panel, PanelGeneratorCommand::panelName() |
Resources/{Plural} | Bentuk plural StudlyCase dari nama Resource | make:panel-resource |
{Class}Resource.php | Bentuk singular StudlyCase + Resource | make:panel-resource |
Pages/, Tables/, Forms/ | Masing-masing berisi class yang didelegasikan dari Resource | make:panel-resource |
RelationManagers/ | Ditambahkan ketika relation manager dibuat | make:panel-relation-manager |
make:panel-resource User --panel=Admin dan make:panel-resource Users --panel=Admin menghasilkan file yang sama. Nama diubah menjadi singular untuk class dan plural untuk directory, sehingga kedua bentuk penulisan berakhir di lokasi yang sama.
Directory yang ditambahkan generator kemudian
php artisan make:panel-relation-manager comments --panel=Admin --resource=Post
php artisan make:panel-relation-manager comments --panel=Admin --resource=Post --page2
Command pertama membuat app/Panels/Admin/Resources/Posts/RelationManagers/CommentsRelationManager.php. Dengan --page, generator juga membuat app/Panels/Admin/Resources/Posts/Pages/ManagePostsComments.php, yaitu page ManageRelatedRecords yang berada di samping empat page standar.
Menulis file ke directory tersebut tidak otomatis mendaftarkannya. Command juga mengingatkan hal ini setelah selesai: relation manager baru dapat diakses setelah class-nya disebut dalam PostResource::relationManagers(), dan page baru dapat diakses setelah disebut dalam PostResource::pages().
Kebutuhan lain milik Resource — seperti exporter, importer, atau class infolist — hanyalah PHP biasa dan tidak memiliki konvensi directory yang diwajibkan framework. Example application menggunakan struktur:
app/Panels/Admin/Resources/Users/
├── UserResource.php
├── Exports/UserExporter.php
├── Forms/UserForm.php
├── Imports/UserImporter.php
├── Infolists/UserInfolist.php
├── Pages/
└── Tables/2
3
4
5
6
7
8
UserResource::infolist() memanggil UserInfolist::configure(), sama seperti table() memanggil UsersTable::configure(). Helper class tersebut ditemukan oleh autoloader, bukan oleh discovery.
Cara discovery membaca directory tree
$panel
->discoverResources(app_path('Panels/Admin/Resources'))
->discoverPages(app_path('Panels/Admin/Pages'))
->discoverWidgets(app_path('Panels/Admin/Widgets'));2
3
4
Setiap method menerima satu atau beberapa path dan menggabungkannya dengan deklarasi yang sudah ada. Proses scan kemudian:
- Mengubah setiap file path menjadi nama class melalui PSR-4 prefix yang terdaftar pada Composer menggunakan
PandaPanel\Discovery\ClassResolver::forPath(), bukan dengan parsing atau mengeksekusi file. Path yang berada di luar seluruh PSR-4 root di-resolve menjadinulllalu dilewati karena class tersebut memang tidak dapat di-autoload. - Hanya mempertahankan concrete class yang mengimplementasikan contract yang diharapkan.
PostResourcedipertahankan;PostForm,PostsTable, dan class page yang berada pada tree yang sama dilewati karena bukan Resource. Abstract class juga dilewati, sehinggaPandaPanel\Resources\Resourcesendiri tidak pernah ditemukan discovery. - Melakukan scan secara recursive, sehingga
Resources/Posts/PostResource.phpditemukan ketika directoryResourcesdipindai. - Mengurutkan hasil agar dua mesin menghasilkan manifest yang sama.
- Mengembalikan
[]jika suatu path tidak ada, bukan melempar error.
Explicit registration tetap dapat digunakan dan digabungkan tanpa menghasilkan duplikasi:
$panel
->resources([PostResource::class])
->discoverResources(app_path('Panels/Admin/Resources'));2
3
Class yang diregistrasikan manual lalu juga ditemukan discovery tetap hanya memiliki satu registration.
Menempatkan Resource di luar konvensi
Konvensi ini adalah opini generator, bukan batasan framework. Resource dapat berada di module package, domain directory, atau lokasi lain selama salah satu dari dua pendekatan berikut digunakan:
// Point discovery at it,
$panel->discoverResources(base_path('modules/Blog/Panel/Resources'));
// or name the class.
$panel->resources([\Modules\Blog\Panel\PostResource::class]);2
3
4
5
Keduanya tetap mensyaratkan path berada di bawah PSR-4 root yang terdaftar. Discovery tidak memiliki cara lain untuk menentukan nama class dari sebuah file.
Path frontend
Resource page merender component framework — panel/resources/Index, Create, View, Edit, ManageRelated — yang dipublish ke aplikasi, bukan di-import langsung dari package. Alasannya, seluruh component registry pada frontend menggunakan import.meta.glob terhadap tree milik aplikasi.
| Path | Default | Config key |
|---|---|---|
| Component Panel | resources/js/panel | panda-panel.frontend.panel_path |
| Component page dan widget hasil generator | resources/js/pages/Panels | panda-panel.frontend.pages_path |
'frontend' => [
'panel_path' => 'js/panel',
'pages_path' => 'js/pages/Panels',
],2
3
4
Keduanya relatif terhadap resources/ dan dibaca melalui PandaPanel\Support\FrontendPaths, sehingga publisher, generator, dan icon command tidak dapat menggunakan penulisan path yang berbeda. Jika pages_path dipindahkan, glob pada frontend juga harus disesuaikan.
Mengustomisasi output generator
php artisan vendor:publish --tag=panda-panel-stubsCommand tersebut menyalin stub package ke stubs/panel/ pada aplikasi. Published stub selalu memiliki prioritas dibanding stub bawaan package. Artinya, mengedit stubs/panel/resource.stub akan mengubah seluruh Resource yang dibuat generator setelah perubahan tersebut.
| Stub | Dibuat oleh |
|---|---|
resource.stub | make:panel-resource |
resource-page.stub | make:panel-resource, satu kali per page |
resource-table.stub | make:panel-resource |
resource-form.stub | make:panel-resource |
relation-manager.stub | make:panel-relation-manager |
relation-page.stub | make:panel-relation-manager --page |
panel-provider.stub | make:panel |
page.stub, page-component.stub | make:panel-page |
widget-stats.stub, widget-table.stub, widget-chart.stub, widget-custom.stub, widget-component.stub | make:panel-widget |
Catatan penting
- Lokasi directory menentukan keanggotaan Panel hanya melalui discovery. Resource di
Panels/Admin/Resourcesberada pada Admin Panel karena Panel tersebut memindai path itu, bukan karena namespace-nya. Dua Panel boleh saja sengaja memindai path yang sama. - File di dalam tree yang bukan Resource bukanlah error. Scanner memfilter berdasarkan contract. Inilah alasan table, form, dan page yang berada di samping Resource diabaikan, bukan ditolak.
- Generator tidak menimpa file secara default. File yang sudah ada dilewati disertai warning yang menyebut nama file. Gunakan
--forceuntuk menimpanya. Jika seluruh file dilewati, command keluar dengan failure status agar automated regeneration tidak terlihat berhasil padahal tidak menulis apa pun. php artisan panel:cachemembekukan daftar class hasil discovery. Setelah menambahkan Resource di production, build ulang manifest; jika tidak, discovery tidak akan berjalan untuk menemukan Resource baru tersebut.