Add Nightwatch configuration guidance and MCP development skill docs across agent integrations, and refresh existing Laravel skill references.
7.1 KiB
Controller Entrypoint (asController)
Scope
Use this reference when exposing an action through HTTP routes.
Recap
- Documents controller lifecycle around
asController(...)and response adapters. - Covers routing patterns, middleware, and optional in-action
routes()registration. - Summarizes validation/authorization hooks used by
ActionRequest. - Provides extension points for JSON/HTML responses and failure customization.
Recommended pattern
- Route directly to action class when appropriate.
- Keep HTTP adaptation in controller methods (
asController,jsonResponse,htmlResponse). - Keep domain logic in
handle(...).
Methods provided (AsController trait)
__invoke
Required so Laravel can register the action class as an invokable controller.
$action($someArguments);
// Equivalent to:
$action->handle($someArguments);
If the method does not exist, Laravel route registration fails for invokable controllers.
// Illuminate\Routing\RouteAction
protected static function makeInvokable($action)
{
if (! method_exists($action, '__invoke')) {
throw new UnexpectedValueException("Invalid route action: [{$action}].");
}
return $action.'@__invoke';
}
If you need your own __invoke, alias the trait implementation:
class MyAction
{
use AsAction {
__invoke as protected invokeFromLaravelActions;
}
public function __invoke()
{
// Custom behavior...
}
}
Methods used (ControllerDecorator + ActionRequest)
asController
Called when used as invokable controller. If missing, it falls back to handle(...).
public function asController(User $user, Request $request): Response
{
$article = $this->handle(
$user,
$request->get('title'),
$request->get('body')
);
return redirect()->route('articles.show', [$article]);
}
jsonResponse
Called after asController when request expects JSON.
public function jsonResponse(Article $article, Request $request): ArticleResource
{
return new ArticleResource($article);
}
htmlResponse
Called after asController when request expects HTML.
public function htmlResponse(Article $article, Request $request): Response
{
return redirect()->route('articles.show', [$article]);
}
getControllerMiddleware
Adds middleware directly on the action controller.
public function getControllerMiddleware(): array
{
return ['auth', MyCustomMiddleware::class];
}
routes
Defines routes directly in the action.
public static function routes(Router $router)
{
$router->get('author/{author}/articles', static::class);
}
To enable this, register routes from actions in a service provider:
use Lorisleiva\Actions\Facades\Actions;
Actions::registerRoutes();
Actions::registerRoutes('app/MyCustomActionsFolder');
Actions::registerRoutes([
'app/Authentication',
'app/Billing',
'app/TeamManagement',
]);
prepareForValidation
Called before authorization and validation are resolved.
public function prepareForValidation(ActionRequest $request): void
{
$request->merge(['some' => 'additional data']);
}
authorize
Defines authorization logic.
public function authorize(ActionRequest $request): bool
{
return $request->user()->role === 'author';
}
You can also return gate responses:
use Illuminate\Auth\Access\Response;
public function authorize(ActionRequest $request): Response
{
if ($request->user()->role !== 'author') {
return Response::deny('You must be an author to create a new article.');
}
return Response::allow();
}
rules
Defines validation rules.
public function rules(): array
{
return [
'title' => ['required', 'min:8'],
'body' => ['required', IsValidMarkdown::class],
];
}
withValidator
Adds custom validation logic with an after hook.
use Illuminate\Validation\Validator;
public function withValidator(Validator $validator, ActionRequest $request): void
{
$validator->after(function (Validator $validator) use ($request) {
if (! Hash::check($request->get('current_password'), $request->user()->password)) {
$validator->errors()->add('current_password', 'Wrong password.');
}
});
}
afterValidator
Alternative to add post-validation checks.
use Illuminate\Validation\Validator;
public function afterValidator(Validator $validator, ActionRequest $request): void
{
if (! Hash::check($request->get('current_password'), $request->user()->password)) {
$validator->errors()->add('current_password', 'Wrong password.');
}
}
getValidator
Provides a custom validator instead of default rules pipeline.
use Illuminate\Validation\Factory;
use Illuminate\Validation\Validator;
public function getValidator(Factory $factory, ActionRequest $request): Validator
{
return $factory->make($request->only('title', 'body'), [
'title' => ['required', 'min:8'],
'body' => ['required', IsValidMarkdown::class],
]);
}
getValidationData
Defines which data is validated (default: $request->all()).
public function getValidationData(ActionRequest $request): array
{
return $request->all();
}
getValidationMessages
Custom validation error messages.
public function getValidationMessages(): array
{
return [
'title.required' => 'Looks like you forgot the title.',
'body.required' => 'Is that really all you have to say?',
];
}
getValidationAttributes
Human-friendly names for request attributes.
public function getValidationAttributes(): array
{
return [
'title' => 'headline',
'body' => 'content',
];
}
getValidationRedirect
Custom redirect URL on validation failure.
public function getValidationRedirect(UrlGenerator $url): string
{
return $url->to('/my-custom-redirect-url');
}
getValidationErrorBag
Custom error bag name on validation failure (default: default).
public function getValidationErrorBag(): string
{
return 'my_custom_error_bag';
}
getValidationFailure
Override validation failure behavior.
public function getValidationFailure(): void
{
throw new MyCustomValidationException();
}
getAuthorizationFailure
Override authorization failure behavior.
public function getAuthorizationFailure(): void
{
throw new MyCustomAuthorizationException();
}
Checklist
- Route wiring points to the action class.
asController(...)delegates tohandle(...).- Validation/authorization methods are explicit where needed.
- Response mapping is split by channel (
jsonResponse,htmlResponse) when useful. - HTTP tests cover both success and validation/authorization failure branches.
Common pitfalls
- Putting response/redirect logic in
handle(...). - Duplicating business rules in
asController(...)instead of delegating. - Assuming action route discovery works without
Actions::registerRoutes(...)when using in-actionroutes().