Referensi API Resource
Seluruh public dan protected member pada class Resource, menggunakan signature aslinya. Gunakan halaman ini sebagai referensi cepat untuk mencari API; halaman yang ditautkan dari setiap bagian menjelaskan kapan dan mengapa API tersebut digunakan.
Namespaces
| Class | Fungsi |
|---|---|
PandaPanel\Resources\Resource | Base class yang di-extend sebuah Resource |
PandaPanel\Contracts\ResourceContract | Contract yang digunakan registry dan navigation builder sebagai type-hint |
PandaPanel\Resources\ResourceConfiguration | Satu Resource class yang dikonfigurasi khusus untuk satu Panel |
PandaPanel\Resources\Pages\ResourcePage | Base class seluruh Resource page |
PandaPanel\Resources\Pages\ListRecords | Index page |
PandaPanel\Resources\Pages\CreateRecord | Create page |
PandaPanel\Resources\Pages\ViewRecord | Read-only detail page |
PandaPanel\Resources\Pages\EditRecord | Edit page |
PandaPanel\Resources\Pages\ManageRelatedRecords | Page khusus untuk satu relation milik record |
PandaPanel\Resources\Concerns\HasLifecycleHooks | Lifecycle hook yang dapat di-override page |
PandaPanel\Resources\Concerns\InteractsWithRecord | Record resolution untuk custom page |
PandaPanel\Search\GlobalSearch | Service di balik command palette |
PandaPanel\Support\ParentRecord | Parent record yang sedang di-bind untuk nested Resource |
PandaPanel\Resources\RelationManager, RelationTable, dan RelationForm berada pada namespace yang sama dan didokumentasikan pada Relation managers.
Bentuk Resource paling minimal
use App\Models\Post;
use PandaPanel\Forms\FormSchema;
use PandaPanel\Resources\Resource;
use PandaPanel\Tables\TableSchema;
final class PostResource extends Resource
{
protected static string $model = Post::class;
public static function table(TableSchema $table): TableSchema
{
return $table->columns([TextColumn::make('title')]);
}
public static function form(FormSchema $schema): FormSchema
{
return $schema->schema([TextInput::make('title')->required()]);
}
/**
* @return array<string, class-string>
*/
public static function pages(): array
{
return ['index' => ListPosts::class];
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
Resource — properties
Semuanya merupakan protected static.
| Property | Type | Default | Dokumentasi |
|---|---|---|---|
$model | class-string<Model> | wajib | Creating resources |
$slug | ?string | null | URLs and routes |
$label | ?string | null | Labels |
$pluralLabel | ?string | null | Labels |
$recordTitleAttribute | ?string | null, berarti 'name' | Model binding |
$navigationLabel | ?string | null | Navigation |
$navigationIcon | ?string | null | Navigation |
$activeNavigationIcon | ?string | null | Navigation |
$navigationGroup | string|BackedEnum|null | null | Navigation |
$navigationSort | int | 0 | Navigation |
$shouldRegisterNavigation | bool | true | Navigation |
$cluster | ?class-string<Cluster> | null | Clusters |
$subNavigationPosition | ?SubNavigationPosition | null | Sub-navigation |
$with | list<string> | [] | Queries |
$softDeletes | bool | false | Soft deletes |
$singular | bool | false | Singular resources |
$parentResource | ?class-string<Resource> | null | Nested resources |
$parentRelationship | ?string | null | Nested resources |
$tenantRelationship | ?string | null | Queries |
$globalSearchAttributes | list<string> | [] | Global search |
$globalSearchLimit | int | 5 | Global search |
$globalSearchSort | int | 0 | Global search |
Resource — schema
abstract public static function table(TableSchema $table): TableSchema;
abstract public static function form(FormSchema $schema): FormSchema;
abstract public static function pages(): array; // array<string, class-string>
public static function infolist(InfolistSchema $schema): InfolistSchema; // returns it untouched
public static function relationManagers(): array; // list<class-string<RelationManager>>, empty
public static function relationManager(string $key): ?string; // class-string<RelationManager>|null
public static function integrations(Integrations $integrations): Integrations;
public static function integrationSettings(): Integrations; // resolved once per class per request
public static function getWidgets(): array; // list<class-string<Widget>>, empty
public static function getHeaderWidgets(string $page): array; // index gets getWidgets()
public static function getFooterWidgets(string $page): array; // empty2
3
4
5
6
7
8
9
10
11
12
relationManager() melempar PanelRegistrationException ketika dua manager menggunakan key yang sama. Tanpa exception tersebut, jawaban endpoint akan bergantung pada declaration order.
Resource — model dan query
public static function getModel(): string; // class-string<Model>; throws when $model is unset
public static function query(): Builder; // the single entry point for every read
public static function globalSearchQuery(): Builder; // returns query()
protected static function recordQuery(): Builder; // query(), soft-delete scope lifted where declared
protected static function applyTenantScope(Builder $q): Builder;
public static function tenantRelationship(): ?string;
public static function usesSoftDeletes(): bool; // declared and corroborated by the model2
3
4
5
6
7
Resource — records
public static function resolveRecord(int|string $key): Model; // findOrFail
public static function findRecord(int|string $key): ?Model;
public static function findRecords(array $keys): Collection; // Collection<int, Model>
public static function resolveSingularRecord(): Model; // query()->firstOrFail()
public static function recordTitle(Model $record): string;
public static function isSingular(): bool;2
3
4
5
6
Resource — nesting
public static function isNested(): bool;
public static function parentResource(): ?string; // class-string<Resource>|null
public static function parentRelationship(): string; // camel case of the default slug when undeclared
protected static function parentRelation(): Relation;2
3
4
Resource — identity dan URLs
public static function defaultSlug(): string;
public static function defaultLabel(): string;
public static function defaultPluralLabel(): string;
public static function slug(): string; // as the current panel configured it
public static function slugIn(?Panel $panel): string;
public static function label(): string;
public static function pluralLabel(): string;
public static function configurationIn(?Panel $panel): ?ResourceConfiguration;
public static function routeName(string $page = 'index', Panel|string|null $panel = null): string;
public static function url(
string $page = 'index',
Model|int|string|null $record = null,
Panel|string|null $panel = null,
Model|int|string|null $parent = null,
): string;
protected static function resolvePanel(Panel|string|null $panel): Panel;
protected static function assertRegisteredIn(Panel $panel): void;2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Route name menggunakan pola panel.{panelId}.resources.{slug}.{page}.
Resource — navigation
public static function navigationItem(PanelContract $panel): ?NavigationItem;
public static function navigationIcon(): ?string;
public static function activeNavigationIcon(): ?string; // falls back to navigationIcon()
public static function cluster(): ?string; // class-string<Cluster>|null
public static function subNavigationPosition(): ?SubNavigationPosition;2
3
4
5
Resource — authorization
public static function canViewAny(): bool; // viewAny
public static function canView(Model $record): bool; // view
public static function canCreate(): bool; // create
public static function canEdit(Model $record): bool; // update
public static function canDelete(Model $record): bool; // delete
public static function canDeleteAny(): bool; // deleteAny
public static function canRestore(Model $record): bool; // restore
public static function canRestoreAny(): bool; // restoreAny
public static function canForceDelete(Model $record): bool; // forceDelete
public static function canForceDeleteAny(): bool; // forceDeleteAny
protected static function authorize(string $ability, Model|string $argument): bool;2
3
4
5
6
7
8
9
10
11
12
Resource — global search
public static function globalSearchAttributes(): array; // list<string>
public static function isGloballySearchable(): bool;
public static function globalSearchLimit(): int;
public static function globalSearchSort(): int;
public static function globalSearchResultTitle(Model $record): string;
public static function globalSearchResultDetails(Model $record): array; // array<string, string>
public static function globalSearchResultUrl(Model $record): string;2
3
4
5
6
7
ResourceContract
Member yang dibutuhkan registry dan navigation builder. Semuanya sudah diimplementasikan Resource. Module yang menyediakan implementation sendiri membutuhkan tepat member berikut.
public static function slug(): string;
public static function query(): Builder;
public static function pages(): array;
public static function canViewAny(): bool;
public static function navigationItem(PanelContract $panel): ?NavigationItem;
public static function cluster(): ?string;2
3
4
5
6
ResourceConfiguration
public readonly string $resource;
public static function for(string $resource): self;
public function slug(string $slug): self;
public function label(string $label): self;
public function pluralLabel(string $pluralLabel): self;
public function navigationLabel(string $navigationLabel): self;
public function navigationGroup(?string $navigationGroup): self;
public function navigationIcon(?string $navigationIcon): self;
public function navigationSort(int $navigationSort): self;
public function registerNavigation(bool $register = true): self;
public function modifyQueryUsing(Closure $callback): self; // Closure(Builder): Builder
public function getSlug(): string;
public function getLabel(): string;
public function getPluralLabel(): string;
public function getNavigationLabel(): ?string;
public function getNavigationGroup(): ?string;
public function getNavigationIcon(): ?string;
public function getNavigationSort(): ?int;
public function shouldRegisterNavigation(): ?bool;
public function applyQuery(Builder $query): Builder;2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Lihat Per-panel configuration.
ResourcePage
Digunakan bersama oleh seluruh Resource page.
protected static string $resource; // class-string<Resource>, required
protected static ?bool $hasDatabaseTransactions = null; // null inherits the panel
protected static ?string $routePath = null;
protected static ?string $title = null;
protected static ?string $heading = null;
protected static ?string $subheading = null;
public function getTitle(?Model $record = null): string;
public function getHeading(?Model $record = null): string;
public function getSubheading(?Model $record = null): ?string;
protected function defaultTitle(?Model $record): string;
protected function defaultHeading(?Model $record): string;
protected function defaultSubheading(?Model $record): ?string;
protected function headingMetadata(?Model $record = null): array;
public static function routePath(string $key): string; // defaults to the page key
public static function hasDatabaseTransactions(): ?bool;
public static function renderHookScope(): string; // 'resource:{slug}'
public static function resource(): string; // class-string<Resource>
public function headerWidgets(): array; // list<class-string<Widget>>
public function footerWidgets(): array;
protected function widgetProps(?PageContext $context = null): array;
protected function widgetPageKey(): string;
protected function widgetFilterSessionKey(?PageContext $context = null): string;
protected function fillForm(FormSchema $schema, ?Model $record = null): array;
protected function validateStepFor(Request $r, FormSchema $s, ?Model $record = null): JsonResponse;
protected function panel(): Panel;
protected function dashboardUrl(): string;
protected function resourceMetadata(): array;
protected function actionEndpoints(): array; // array<string, string>
protected function recordTitle(Model $record): string;
protected function relationTables(Request $request, Model $record): array;
protected function clusterNavigation(): ?array;
protected function subNavigationPosition(): SubNavigationPosition;
protected function subNavigation(?Model $record, string $currentPage): array;
protected function baseBreadcrumbs(): array; // list<Breadcrumb>
protected function parentBreadcrumbs(): array;
protected function recordCrumb(Model $record, string $title): Breadcrumb;
protected function serializeBreadcrumbs(array $crumbs): array;2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
ListRecords
protected static string $component = 'panel/resources/Index';
public function render(Request $request): Response;
public function tabs(): array; // array<string, Tab>, empty
protected function headerActions(): array;
protected function rows(TableSchema $schema, LengthAwarePaginator $records, ?Group $group = null): array;
protected function pagination(LengthAwarePaginator $records): array;
protected function pageMetadata(): array;2
3
4
5
6
7
8
CreateRecord
protected static string $component = 'panel/resources/Create';
protected static string $page = 'create';
protected static bool $canCreateAnother = true;
protected static bool $preservesDataOnCreateAnother = false;
public function render(Request $request): Response;
public function handle(Request $request): RedirectResponse;
public function validateStep(Request $request): JsonResponse;
protected function handleRecordCreation(array $attributes): Model;
protected function getRedirectUrl(Model $record): string;
protected function createdNotification(Model $record): ?array; // ['type' => ..., 'message' => ...]
protected function schema(): FormSchema;
protected function pageMetadata(): array;2
3
4
5
6
7
8
9
10
11
12
13
14
ViewRecord
protected static string $component = 'panel/resources/View';
protected static string $page = 'view';
public function render(Request $request, ?string $record = null): Response;
protected function entries(Model $record): array; // the form-derived fallback
protected function displayValue(Field $field, Model $record): ?string;
protected function headerActions(Model $record): array;
protected function pageMetadata(Model $record): array;2
3
4
5
6
7
8
9
Menggunakan InteractsWithRecord; authorization menggunakan canView().
EditRecord
protected static string $component = 'panel/resources/Edit';
protected static string $page = 'edit';
public function render(Request $request, ?string $record = null): Response;
public function handle(Request $request, ?string $record = null): RedirectResponse;
public function validateStep(Request $request, ?string $record = null): JsonResponse;
protected function authorizeRecord(Model $record): bool; // canEdit()
protected function handleRecordUpdate(Model $record, array $attributes): Model;
protected function getRedirectUrl(Model $record): string;
protected function savedNotification(Model $record): ?array;
protected function schema(): FormSchema;
protected function pageMetadata(Model $record): array;2
3
4
5
6
7
8
9
10
11
12
13
ManageRelatedRecords
protected static string $component = 'panel/resources/ManageRelated';
protected static string $relationManager; // class-string<RelationManager>, required
protected static string $page = 'relation';
public function render(Request $request, ?string $record = null): Response;
public static function relationManager(): string;
public static function relationPageKey(): string; // the manager's key
public static function routePath(string $key): string; // '{record}/'.$key by default
protected function pageMetadata(Model $owner): array;2
3
4
5
6
7
8
9
Page menghasilkan 404 ketika Resource tidak mendeklarasikan manager yang disebutnya, dan 403 ketika manager menolak owner. Lihat Relation pages.
HasLifecycleHooks
protected function halt(): never;
protected function beforeFill(): void;
protected function mutateFormDataBeforeFill(array $data): array;
protected function afterFill(array $data): void;
protected function beforeValidate(array $input): array;
protected function afterValidate(array $data): array;
protected function beforeCreate(): void;
protected function mutateFormDataBeforeCreate(array $data): array;
protected function mutateFormDataBeforeSave(array $data, ?Model $record): array;
protected function beforeSave(?Model $record): void;
protected function afterCreate(Model $record): void;
protected function afterSave(Model $record): void;2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Urutan dan semantics: Lifecycle hooks.
InteractsWithRecord
protected function resolveRecord(int|string|null $key = null): Model; // resolves, authorizes, memoizes
protected function getRecord(): Model; // LogicException before resolution
protected function hasRecord(): bool;
protected function authorizeRecord(Model $record): bool; // canView() by default2
3
4
GlobalSearch dan GlobalSearchResult
final class GlobalSearch
{
public function __construct(private readonly PanelManager $manager) {}
public function for(Panel $panel, string $term): array;
}
final readonly class GlobalSearchResult
{
public function __construct(
public string $title,
public string $url,
public array $details = [],
) {}
public function toArray(): array;
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
for() mengembalikan list<array{resource: string, label: string, icon: string|null, results: list<array<string, mixed>>}>. Lihat Global search.
ParentRecord
public static function bind(Model $record): void;
public static function current(): ?Model;
public static function require(string $resource): Model; // throws when none is bound
public static function routeParameter(): string; // 'parentRecord'
public static function resolve(string $parentResource, int|string $key): ?Model; // scoped and authorized
public static function assertRegistered(string $resource, string $parent): void;2
3
4
5
6
Route names
| Page key | Route name | Verb dan path |
|---|---|---|
index | panel.{id}.resources.{slug}.index | GET / |
create | ...create | GET create |
create | ...store | POST create |
create | ...validateCreateStep | POST create/step |
view | ...view | GET {record} |
edit | ...edit | GET {record}/edit |
edit | ...update | PUT {record}/edit |
edit | ...validateEditStep | POST {record}/edit/step |
| custom | ...{key} | GET pada $routePath, default ke page key |
Singular resource menghapus {record} dari seluruh path. Nested resource memberi prefix pada seluruh route group menggunakan {parentSlug}/{parentRecord}/.
Exceptions
| Exception | Dilempar ketika |
|---|---|
PandaPanel\Exceptions\PanelSchemaException | $model tidak pernah dideklarasikan atau schema memiliki duplicate name |
PandaPanel\Exceptions\PanelRegistrationException | Dua class memakai slug sama; URL diminta pada Panel yang tidak meregistrasikan Resource; tidak ada current Panel; parent Resource tidak diregistrasikan; tidak ada parent record ter-bind; $tenantRelationship tidak dikenal atau bukan relation; dua manager memakai key sama; dua Resource mengklaim path yang sama |
PandaPanel\Exceptions\PanelAuthorizationException | Pada strictAuthorization(), policy tidak ada atau policy method yang dibutuhkan tidak ada |
PandaPanel\Exceptions\Halt | $this->halt() — ditangkap oleh page dan tidak pernah ditampilkan sebagai error |
Illuminate\Database\Eloquent\ModelNotFoundException | resolveRecord() tidak menemukan record; menjadi 404 |