Resource
Um Resource é a única class PHP que liga um model Eloquent ao admin panel: routes, entrada na sidebar, páginas index/create/edit/show, fields, table, actions e autorização derivam todos dele. Se você for construir uma única coisa no Arqel, são os Resources.
Esta página mostra o uso do Arqel\Core\Resources\Resource no dia a dia. Para a lista completa de métodos, veja a referência do arqel-dev/core.
Criando um Resource
Gere um com o generator do Artisan:
php artisan arqel:resource Post --with-policyIsso produz app/Arqel/Resources/PostResource.php:
namespace App\Arqel\Resources;
use App\Models\Post;
use Arqel\Core\Resources\Resource;
use Arqel\Fields\FieldFactory as Field;
final class PostResource extends Resource
{
protected static string $model = Post::class;
protected static ?string $navigationIcon = 'document-text';
public function fields(): array
{
return [
Field::text('title')->required()->maxLength(200),
Field::slug('slug')->fromField('title')->required(),
Field::textarea('body')->rows(8),
];
}
}As únicas duas coisas de que um Resource estritamente precisa são protected static string $model e uma implementação de fields(): array. Todo o resto — routes, navegação, columns da table — é derivado automaticamente, a menos que você sobrescreva.
Registre a class em um Panel (veja o guia de Panels) e o Arqel cuida de:
- Slug e nomes de route (
PostResource→posts, routes sobarqel.resources.posts.*) - Entrada na sidebar, agrupada/ordenada por
$navigationGroup/$navigationSort - Página de index com columns auto-derivadas de
fields() - Forms de create/edit renderizando esses mesmos fields
- Autorização via
Gate::denies('create'|'update'|'delete'|'view'|'viewAny', ...)
Nomenclatura e metadados
Sobrescreva as propriedades estáticas para personalizar como um Resource se apresenta — o Arqel cai em defaults sensatos derivados do nome da class quando elas estão ausentes:
final class PostResource extends Resource
{
protected static string $model = Post::class;
protected static ?string $slug = 'articles';
protected static ?string $label = 'Article';
protected static ?string $pluralLabel = 'Articles';
protected static ?string $navigationIcon = 'document-text';
protected static ?string $navigationGroup = 'Content';
protected static ?int $navigationSort = 10;
}Declarando fields
fields(): array é o único método que você precisa implementar. É a fonte única de verdade que o Arqel usa para as regras de validação, o form auto-derivado e as columns auto-derivadas da table:
public function fields(): array
{
return [
Field::text('title')->required()->maxLength(200),
Field::slug('slug')->fromField('title')->required(),
Field::textarea('body')->rows(8),
];
}Veja o guia de Fields para o catálogo completo de tipos de input.
Personalizando table e form
table() e form() são ambos opcionais — quando você os omite, o Arqel deriva uma table de index razoável e um form de coluna única direto de fields(). Sobrescreva-os quando precisar de columns customizadas, filtros ou layout:
use Arqel\Table\Table;
use Arqel\Table\Columns\{TextColumn, BadgeColumn, DateColumn};
use Arqel\Actions\Actions;
public function table(): Table
{
return Table::make()
->columns([
TextColumn::make('title')->sortable()->searchable(),
BadgeColumn::make('status')->colors([
'draft' => 'gray',
'published' => 'green',
]),
DateColumn::make('created_at')->dateTime('d/m/Y H:i'),
])
->actions([
Actions::edit(),
Actions::delete()->visible(fn ($record) => $record->status !== 'published'),
]);
}Veja Table e Form para as APIs completas dos builders.
Lifecycle hooks
Sobrescreva estes hooks protected para rodar lógica em torno de save/delete — o Arqel os invoca automaticamente a partir de runCreate/runUpdate/runDelete:
final class PostResource extends Resource
{
protected static string $model = Post::class;
protected function beforeSave(Model $record, array $data): array
{
$record->user_id = auth()->id();
return $data;
}
protected function afterCreate(Model $record): void
{
Notification::send($record->user, new PostPublished($record));
}
}Hooks disponíveis:
beforeCreate(array $data): array/afterCreate(Model $record): voidbeforeUpdate(Model $record, array $data): array/afterUpdate(Model $record): voidbeforeSave(Model $record, array $data): array/afterSave(Model $record): void— disparam tanto no create quanto no updatebeforeDelete(Model $record): void/afterDelete(Model $record): void—afterDeletesó roda se odelete()retornou truthy
Identidade do record: recordTitle e recordSubtitle
Controle como um record é rotulado em breadcrumbs e modais de confirmação:
public function recordTitle(Model $record): string
{
return $record->title;
}
public function recordSubtitle(Model $record): ?string
{
return $record->author?->name;
}Sem um override, o Arqel usa $recordTitleAttribute (default title/name, o que existir no model).
Escopando o index: indexQuery
public function indexQuery(): Builder
{
return Post::query()->where('user_id', auth()->id())->latest();
}indexQuery() escopa apenas a listagem do index — edit/show/delete continuam sem escopo, então o controle de acesso de verdade continua pertencendo a uma Policy, não aqui.
Relation managers
Um Resource pode expor uma relation Eloquent do record pai (hasMany/morphMany/belongsToMany) como uma aba na sua página de edit:
public function relations(): array
{
return [CommentsRelationManager::class];
}Cada entrada estende Arqel\Core\Relations\RelationManager e declara sua própria table() (obrigatória) e, opcionalmente, fields()/form() para create/edit. Veja a referência do arqel-dev/core para o contrato completo.
Busca global
Habilite um Resource na busca global do command palette declarando quais colunas são pesquisáveis:
public static function globallySearchable(): array
{
return ['title', 'slug'];
}Resources que não sobrescrevem este método (default []) nunca aparecem nos resultados da busca.
Chamando os orchestrators diretamente
runCreate, runUpdate e runDelete são os métodos públicos que o ResourceController chama por baixo dos panos. Você raramente precisa deles diretamente, mas eles são úteis em testes de feature ou em controllers customizados que queiram reusar o pipeline de hooks:
$resource = new PostResource();
$post = $resource->runCreate(['title' => 'Hello', 'slug' => 'hello']);
$resource->runUpdate($post, ['title' => 'Hello world']);
$resource->runDelete($post);Cada orchestrator dispara a sequência completa de hooks (beforeSave → beforeCreate/beforeUpdate → fill+save → afterCreate/afterUpdate → afterSave).
Próximos passos
- Fields — o catálogo de inputs usado por
fields() - Table — personalizando a listagem do index
- Form — personalizando o layout de create/edit
- Actions — botões de linha, em lote, de toolbar e de header
- API completa: referência do
arqel-dev/core