Skip to content

AbstractController ​

v1.1.0

The 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:

php
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.

RequestFormRequestDTOServiceRepository

This keeps HTTP concerns isolated from business logic.


Protected Properties ​

$service ​

php
protected mixed $service;

Holds the injected Service instance.

The Controller never talks directly to the Model.

Instead:

text
Controller
    ↓
 Service
    ↓
Repository
    ↓
 Model

Example:

php
public function __construct(UserService $service)
{
    $this->service = $service;
}

$requestValidate ​

php
protected ?string $requestValidate;

Defines which FormRequest validates the store() action.

Example:

php
protected ?string $requestValidate = UserRequest::class;

During execution:

  1. Laravel validates the request.
  2. Validation errors become HTTP 422 automatically.
  3. The validated payload becomes a DTO.

$requestValidateUpdate ​

php
protected ?string $requestValidateUpdate;

Defines the FormRequest used during updates.

Example:

php
protected ?string $requestValidateUpdate = UserUpdateRequest::class;

This allows different validation rules for create and update.


$requestDto ​

php
protected ?string $requestDto;

Defines which DTO will be instantiated during creation.

Example:

php
protected ?string $requestDto = UserDTO::class;

Internally:

php
UserDTO::fromRequest($request);

$requestDtoUpdate ​

Used by update().

php
protected ?string $requestDtoUpdate = UserUpdateDTO::class;

This keeps update-specific fields isolated.


$resource ​

Defines which Resource serializes responses.

Example:

php
protected ?string $resource = UserResource::class;

Instead of returning Models directly:

php
return new UserResource($user);

Output:

json
{
  "public_id": "01JXYZABCDEF123",
  "nome": "John Doe"
}

$with ​

php
protected array $with = [];

Automatically eager-loads relationships.

Example:

php
protected array $with = [
    'municipio'
];

Equivalent to:

php
User::with('municipio');

CRUD Methods ​

index() ​

Returns a paginated Resource collection.

Flow:

text
Repository
   ↓
paginate()
   ↓
Resource::collection()

Example response:

json
{
  "data": [],
  "links": {},
  "meta": {}
}

show() ​

Finds one record.

Supports public identifiers automatically.

Example:

text
GET /api/users/01JXYZABCDEF

The Controller delegates lookup to the Repository.


store() ​

Creates a new record.

Execution:

  1. Validate Request.
  2. Create DTO.
  3. Execute Service.
  4. Serialize Resource.
  5. Return HTTP 201.

Example:

php
POST /api/users

Request:

json
{
  "nome": "John",
  "email": "john@example.com"
}

update() ​

Uses update-specific Request and DTO.

Flow:

text
Request
   ↓
Update Request
   ↓
Update DTO
   ↓
Service

destroy() ​

Deletes the record.

When the Model uses SoftDeletes:

php
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:

php
$request->validated();

the Controller executes:

php
UserDTO::fromRequest($request);

Benefits:

  • typed objects
  • immutable payload
  • cleaner Services

Automatic Resources ​

Generated Controllers never expose Models directly.

Instead:

php
return new UserResource($user);

Advantages:

  • hide internal IDs
  • consistent API responses
  • easier frontend integration

Pagination ​

Pagination is automatic.

Example:

php
$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:

json
{
  "type": "error",
  "status": 404,
  "message": "Resource not found."
}

Success Response ​

Successful operations share the same structure.

json
{
  "type": "success",
  "status": 200,
  "data": {}
}

Error Response ​

Validation:

json
{
  "type": "error",
  "status": 422
}

Authentication:

json
{
  "type": "error",
  "status": 401
}

Not Found:

json
{
  "type": "error",
  "status": 404
}

Permissions ​

Authorization can be customized by overriding the generated methods.

Example:

php
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.

Released under the MIT License.