AbstractController
v1.1.0The AbstractController is the foundation of every generated Controller.
Instead of manually implementing CRUD operations, validation, DTO conversion and standardized responses, generated Controllers inherit these behaviors automatically.
Every Controller generated by php artisan make:domain extends this class.
Overview
When extending this class, your Controller automatically gains:
- Complete REST CRUD
- Automatic FormRequest validation
- Request → DTO conversion
- Service delegation
- Resource serialization
- Standardized JSON responses
- Pagination support
- Exception normalization
- Relationship eager loading
Minimal example:
class UserController extends AbstractController
{
protected mixed $service;
protected ?string $requestValidate = UserRequest::class;
protected ?string $requestDto = UserDTO::class;
protected ?string $resource = UserResource::class;
public function __construct(UserService $service)
{
$this->service = $service;
}
}Internal flow
Every request follows the same execution pipeline.
This keeps HTTP concerns isolated from business logic.
Protected Properties
$service
protected mixed $service;Holds the injected Service instance.
The Controller never talks directly to the Model.
Instead:
Controller
↓
Service
↓
Repository
↓
ModelExample:
public function __construct(UserService $service)
{
$this->service = $service;
}$requestValidate
protected ?string $requestValidate;Defines which FormRequest validates the store() action.
Example:
protected ?string $requestValidate = UserRequest::class;During execution:
- Laravel validates the request.
- Validation errors become HTTP 422 automatically.
- The validated payload becomes a DTO.
$requestValidateUpdate
protected ?string $requestValidateUpdate;Defines the FormRequest used during updates.
Example:
protected ?string $requestValidateUpdate = UserUpdateRequest::class;This allows different validation rules for create and update.
$requestDto
protected ?string $requestDto;Defines which DTO will be instantiated during creation.
Example:
protected ?string $requestDto = UserDTO::class;Internally:
UserDTO::fromRequest($request);$requestDtoUpdate
Used by update().
protected ?string $requestDtoUpdate = UserUpdateDTO::class;This keeps update-specific fields isolated.
$resource
Defines which Resource serializes responses.
Example:
protected ?string $resource = UserResource::class;Instead of returning Models directly:
return new UserResource($user);Output:
{
"public_id": "01JXYZABCDEF123",
"nome": "John Doe"
}$with
protected array $with = [];Automatically eager-loads relationships.
Example:
protected array $with = [
'municipio'
];Equivalent to:
User::with('municipio');CRUD Methods
index()
Returns a paginated Resource collection.
Flow:
Repository
↓
paginate()
↓
Resource::collection()Example response:
{
"data": [],
"links": {},
"meta": {}
}show()
Finds one record.
Supports public identifiers automatically.
Example:
GET /api/users/01JXYZABCDEFThe Controller delegates lookup to the Repository.
store()
Creates a new record.
Execution:
- Validate Request.
- Create DTO.
- Execute Service.
- Serialize Resource.
- Return HTTP 201.
Example:
POST /api/usersRequest:
{
"nome": "John",
"email": "john@example.com"
}update()
Uses update-specific Request and DTO.
Flow:
Request
↓
Update Request
↓
Update DTO
↓
Servicedestroy()
Deletes the record.
When the Model uses SoftDeletes:
use SoftDeletes;The generated Controller automatically performs a soft delete.
Automatic DTO Conversion
One of the biggest advantages of the generated Controllers is automatic DTO conversion.
Instead of:
$request->validated();the Controller executes:
UserDTO::fromRequest($request);Benefits:
- typed objects
- immutable payload
- cleaner Services
Automatic Resources
Generated Controllers never expose Models directly.
Instead:
return new UserResource($user);Advantages:
- hide internal IDs
- consistent API responses
- easier frontend integration
Pagination
Pagination is automatic.
Example:
$this->service->paginate();Response includes:
- data
- links
- meta
No additional Controller code is required.
Exception Handling
Exceptions are normalized.
Instead of exposing internal stack traces, the Controller returns predictable JSON.
Example:
{
"type": "error",
"status": 404,
"message": "Resource not found."
}Success Response
Successful operations share the same structure.
{
"type": "success",
"status": 200,
"data": {}
}Error Response
Validation:
{
"type": "error",
"status": 422
}Authentication:
{
"type": "error",
"status": 401
}Not Found:
{
"type": "error",
"status": 404
}Permissions
Authorization can be customized by overriding the generated methods.
Example:
public function update(...)
{
$this->authorize('update', $user);
return parent::update(...);
}This keeps compatibility with Laravel Policies.
Best Practices
- Keep Controllers thin.
- Put business rules inside Services.
- Receive DTOs instead of Requests.
- Return Resources instead of Models.
- Use public identifiers for external APIs.
Generated Controllers follow the same layered architecture used throughout Laravel Domain Generator, keeping HTTP concerns separate from business logic while reducing boilerplate code.