Actions
Resource actions are backend-defined operations that can run for one model from the detail page or for selected models from the index table.
Use actions for workflows such as approving, sending, exporting, archiving or impersonating. Keep direct create/edit/delete behaviour in the resource pages unless the workflow needs its own form or confirmation.
Create An Action
namespace App\Actions;
use App\Models\Product;
use Illuminate\Database\Eloquent\Model;
use Qore\Next\System\Action\ResourceAction;
use Qore\Next\System\Field\Field;
use Qore\Next\System\Fields\TextAreaField;
class ArchiveProductAction extends ResourceAction
{
public function label(): string
{
return __('common.archive');
}
public function icon(): string
{
return 'archive';
}
/**
* @return list<Field>
*/
protected function fields(): array
{
return [
TextAreaField::make('reason', __('common.reason'))
->setRules(fn () => ['required', 'string', 'max:1000']),
];
}
/**
* @param Product $model
* @param array<string, mixed> $validated
*/
public function handle(Model $model, array $validated): void
{
$model->forceFill([
'archived_at' => now(),
'archive_reason' => $validated['reason'],
])->save();
}
}
The action form is rendered as a FormNode. The validated payload is passed to handle() for each authorized selected model.
Register Actions On The Resource
use App\Actions\ArchiveProductAction;
use Qore\Next\System\Action\ResourceAction;
/**
* @return ResourceAction[]
*/
public function actions(): array
{
return [
new ArchiveProductAction,
];
}
QoreResource::getActions() sets the resource on each action and keys actions by their generated name.
Visibility
Actions use the same conditional visibility traits as fields:
new ArchiveProductAction()
->setIsShownOnIndex(fn () => true)
->setIsShownOnDetail(fn (Product $product) => ! $product->archived_at);
Index actions appear as table bulk actions. Detail actions appear in the actions dropdown for a single model.
Authorization
By default, an action authorizes each model with:
user()->can('update', $model);
Override authorizeForModel() when the action has a more specific rule:
public function authorizeForModel(Model $model): bool
{
return user()->can('archive', $model);
}
The action skips unauthorized models when running a bulk action.
Action Forms
An action with fields renders a modal form. An action without fields still renders a submit form, which makes destructive or auditable actions explicit.
Useful methods:
description(): ?stringadds explanatory text above the form.isDanger(): boolmarks the dropdown item and submit button as dangerous.getShouldReloadParentOnFormSuccess(): boolcontrols whether the parent node reloads after submit.getShouldReloadGlobalsOnFormSuccess(): boolrequests a globals refresh.getNavigateUrlOnFormSuccess(): ?stringnavigates after success.
Logging
After handle() runs, Qore logs the action name and validated payload for each handled model:
qore()->logger()
->setEntity($model)
->setDescription($this->getName())
->setPayload($validated)
->save();
That log appears in the resource logbook for the model.