Language:

Search

Adaptadores: Controladores, Requests y Eloquent

  • Share this:
Adaptadores: Controladores, Requests y Eloquent

En los artículos anteriores estuvimos construyendo nuestro núcleo independiente de Laravel:

El dominio con entidades, value objects y repositorios.

La capa de aplicación con casos de uso y servicios.

Pero claro, si nos quedamos ahí, nuestra app es como una máquina perfecta… desconectada de todo.
Necesitamos que alguien “enchufe” nuestro sistema al mundo real: HTTP, base de datos, colas, APIs externas.

Ahí entran los adaptadores.


¿Qué es un Adaptador?

Un adaptador es simplemente una pieza de código que:

  • Traduce lo que viene de fuera (una request HTTP, por ejemplo) al lenguaje que entiende nuestra aplicación (DTOs, casos de uso).
  • O al revés: convierte una respuesta del caso de uso en algo que el “mundo exterior” entiende (JSON, HTML, etc.).

Piensa que los adaptadores son como los enchufes de un país.
El dominio y la aplicación son universales, pero cada entorno necesita su adaptador para conectarse.


Adaptadores de Entrada: Controladores y Requests

En Laravel, el adaptador de entrada más común es un Controller.

Un controlador no contiene lógica de negocio, su único trabajo es:

  • Recibir la request.
  • Transformar esos datos en un DTO.
  • Ejecutar un caso de uso.
  • Devolver una respuesta (JSON, vista, etc.).

Ejemplo:

// src/Infrastructure/Http/Controllers/UserController.php

namespace Src\Infrastructure\Http\Controllers;

use App\Http\Controllers\Controller;
use Src\Application\User\UseCases\RegisterUserUseCase;
use Src\Application\User\DTOs\RegisterUserDTO;
use Src\Infrastructure\Http\Requests\RegisterUserRequest;

class UserController extends Controller
{
    public function register(RegisterUserRequest $request, RegisterUserUseCase $useCase)
    {
        $dto = new RegisterUserDTO(
            $request->name,
            $request->email
        );

        $useCase->execute($dto);

        return response()->json(['message' => 'Usuario registrado correctamente']);
    }
}


Requests: validando antes de llegar al caso de uso

Laravel nos da una herramienta genial: los Form Request.
En la arquitectura hexagonal, los usamos como adaptadores de validación, nunca en el dominio.

// src/Infrastructure/Http/Requests/RegisterUserRequest.php

namespace Src\Infrastructure\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class RegisterUserRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'name'  => ['required', 'string'],
            'email' => ['required', 'email', 'unique:users,email'],
        ];
    }
}


De esta forma, si la request llega al caso de uso, ya sabemos que los datos son válidos.


Adaptadores de Salida: Eloquent como repositorio

Aquí viene una de las partes más jugosas: usar Eloquent sin ensuciar el dominio.

¿Cómo lo hacemos?
Con una implementación del repositorio definida en el dominio.

// src/Infrastructure/Persistence/Eloquent/EloquentUserRepository.php

namespace Src\Infrastructure\Persistence\Eloquent;

use Src\Domain\User\Entities\User as UserEntity;
use Src\Domain\User\Repositories\UserRepositoryInterface;
use App\Models\User as EloquentUser;

class EloquentUserRepository implements UserRepositoryInterface
{
    public function save(UserEntity $user): void
    {
        EloquentUser::create([
            'name'  => $user->name(),
            'email' => $user->email()->value()
        ]);
    }

    public function findById(int $id): ?UserEntity
    {
        $user = EloquentUser::find($id);

        if (!$user) {
            return null;
        }

        return new UserEntity($user->name, new Email($user->email));
    }
}


Aquí usamos Eloquent, pero está confinado en infraestructura.
El dominio ni se entera de que existe Eloquent.


Conexión: Service Providers 

Para que Laravel sepa qué implementación usar cuando pedimos un UserRepositoryInterface, lo configuramos en un Service Provider:

// src/Infrastructure/Providers/AppServiceProvider.php

namespace Src\Infrastructure\Providers;

use Illuminate\Support\ServiceProvider;
use Src\Domain\User\Repositories\UserRepositoryInterface;
use Src\Infrastructure\Persistence\Eloquent\EloquentUserRepository;

class AppServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->bind(
            UserRepositoryInterface::class,
            EloquentUserRepository::class
        );
    }
}


Y ya está. Cada vez que inyectemos UserRepositoryInterface en un caso de uso, Laravel sabrá que debe usar la implementación de Eloquent.


Errores comunes

  1. Meter lógica en el controlador
    → El controlador no debería decidir reglas, solo delegar al caso de uso.
  2. Usar Eloquent directamente en el dominio
    → Rompe la independencia. Si mañana cambias de ORM, tendrías que reescribir todo el dominio.
  3. No usar requests para validar
    → Terminas con casos de uso que reciben datos sucios.
  4. Confundir DTOs con Requests
    → El DTO es para el caso de uso, el Request es para validar entrada HTTP.

Conclusión

Los adaptadores son la “piel” de tu aplicación.
No son el corazón (ese es el dominio), ni el cerebro que orquesta (casos de uso), pero son lo que permite que tu sistema se comunique con el mundo.

Laravel es un gran aliado aquí, porque nos da herramientas muy potentes para crear adaptadores: controladores, requests, Eloquent.
Lo importante es mantenerlos en su lugar, sin dejar que se cuelen al dominio.

En el próximo artículo veremos cómo testear esta arquitectura: desde casos de uso aislados hasta pruebas de integración con Laravel.
 


 

Carlos Santiago

Carlos Santiago

Laravel Developer