Skip to main content

4. Capa de aplicación

4.1. Núcleo de la aplicación (QuApp, QuKernel)

Descripción General

El núcleo de la aplicación está compuesto por los componentes centrales que gestionan el ciclo de vida de las solicitudes, la resolución de dependencias y el estado global de la aplicación. Los elementos fundamentales son QuApp y QuKernel.

QuApp

QuApp actúa como un Service Locator y State Container que centraliza el acceso a los componentes fundamentales y mantiene el estado global de la aplicación.

// Ejemplo de uso de QuApp para obtener el contenedor de dependencias
$container = QuApp::getContainer();

// Establecer una acción para registrar en el log de transacciones
$actions = QuApp::getActions();
$actions[] = ['mi_tabla' => ['stored' => $entity]];
QuApp::setActions($actions);

Responsabilidades principales:

  • Gestión centralizada de la solicitud y respuesta HTTP
  • Acceso global al contenedor de dependencias
  • Mantenimiento del estado de la aplicación
  • Gestión de errores y respuestas de error
  • Coordinación del ciclo de vida de la petición
  • Registro de acciones de transacciones

Métodos clave:

  • getContainer(): Accede al contenedor de dependencias
  • getRequest(): Obtiene la instancia actual de la solicitud
  • setErrorResponse(): Establece una respuesta de error
  • getResponse(): Obtiene la respuesta actual
  • setSuccessResponse(): Establece una respuesta exitosa
  • sendResponseAndEnd(): Envía la respuesta y finaliza la ejecución
  • getActions() / setActions(): Gestiona el registro de acciones

QuKernel

QuKernel es responsable de procesar las solicitudes HTTP, coordinar la ejecución de middlewares y resolver controladores y métodos.

// Ejemplo de creación del kernel en index.php
$kernel = new QuKernel(new QuRouter, $container);
$kernel->addMiddleware(new TransactionStartMiddleware);
$kernel->addMiddleware(new AuthMiddleware);

Responsabilidades principales:

  • Coordinación del flujo de la solicitud
  • Resolución de rutas mediante el router
  • Gestión de middlewares
  • Instanciación de controladores
  • Inyección de dependencias
  • Ejecución de métodos de controlador

Métodos clave:

  • addMiddleware(): Agrega un middleware a la cadena de ejecución
  • handle(): Procesa la solicitud y genera una respuesta

4.2. Sistema de enrutamiento

El sistema de enrutamiento se basa en dos componentes principales: QuRouter y Route.

QuRouter

QuRouter es la implementación concreta de la interfaz Router que gestiona la resolución de rutas, identificando el controlador y método a ejecutar para una solicitud dada.

// Ejemplo de resolución de una ruta
$router = new QuRouter();
$resolved = $router->resolve($request);
// $resolved contiene el controlador, método y parámetros a ejecutar

Responsabilidades principales:

  • Analizar la URL de la solicitud
  • Buscar rutas coincidentes
  • Extraer parámetros dinámicos de las rutas
  • Resolver la ruta a un controlador y método específicos
  • Gestionar errores de rutas no encontradas

Route

Route es una clase estática que proporciona una API fluida para definir rutas en archivos de configuración.

// Ejemplo de definición de rutas
Route::group(ProductsController::class, function () use ($middlewares) {
Route::get('products/', 'index', $middlewares);
Route::get('products/:id', 'show', $middlewares);
Route::post('products/', 'store', $middlewares);
Route::put('products/:id', 'update', $middlewares);
Route::delete('products/:id', 'delete', $middlewares);
});

Características clave:

  • Soporte para métodos HTTP: GET, POST, PUT, DELETE
  • Agrupación de rutas por controlador
  • Parámetros dinámicos en las rutas (con notación :nombre)
  • Asociación de middlewares específicos por ruta
  • Generación de un registro centralizado de rutas

4.3. Controladores de dominio

Los controladores de dominio siguen el patrón de controlador base que puede ser extendido por controladores específicos de dominio, proporcionando una estructura coherente para el manejo de solicitudes HTTP.

DomainController

DomainController es una clase base que implementa métodos CRUD estándar y aplica validaciones definidas en el controlador.

// Ejemplo de controlador de dominio
class ProductsController extends DomainController
{
protected $productsService;

public function __construct(ProductsService $service)
{
parent::__construct($service);

$this->validations = [
'headers' => ['x-tienda' => 'required|string'],
'body' => ['name' => 'required|string'],
];
}
}

Responsabilidades principales:

  • Validación de solicitudes entrantes
  • Delegación de operaciones de negocio a los servicios
  • Formateo de respuestas HTTP
  • Manejo estándar de operaciones CRUD
  • Gestión de validaciones específicas del dominio

Métodos implementados:

  • index(): Lista recursos (con paginación)
  • show(): Obtiene un recurso por ID
  • store(): Crea un nuevo recurso
  • update(): Actualiza un recurso existente
  • delete(): Elimina un recurso
  • onFieldChange(): Maneja cambios en campos específicos

Controller básico

Además del DomainController, existe una implementación más básica de Controller que ofrece funcionalidad similar pero con menos abstracción.

// Ejemplo de controlador básico
class CartsController extends Controller
{
protected $CartsService;

public function __construct(CartsService $CartsService)
{
$this->CartsService = $CartsService;
}

public function index(Request $request)
{
return response()->json($this->CartsService->index($request), 200);
}

// Otros métodos...
}

4.4. Servicios de dominio

Los servicios de dominio implementan la lógica de negocio y actúan como intermediarios entre los controladores y los repositorios.

DomainService

DomainService es una clase base que encapsula la lógica de negocio común para operaciones CRUD y puede ser extendida para comportamientos específicos del dominio.

// Ejemplo de servicio de dominio
class ProductsService extends DomainService
{
protected $MaesartiProductosRepository;
protected $CreateMaesartiProductosDTO;
protected $MaesartiProductosDTO;

public function __construct(
MaesartiProductosRepository $MaesartiProductosRepository,
InterfaceReqDto $CreateMaesartiProductosDTO,
InterfaceResDto $MaesartiProductosDTO
) {
$this->MaesartiProductosRepository = $MaesartiProductosRepository;
$this->CreateMaesartiProductosDTO = $CreateMaesartiProductosDTO;
$this->MaesartiProductosRepository->selectable(MaesartiProductosDTO::$selectables);
$this->MaesartiProductosDTO = $MaesartiProductosDTO;
}

public function index(Request $request)
{
$this->CreateMaesartiProductosDTO->mapFilters($request);
$resources = $this->MaesartiProductosRepository->collection($request->all());
$resources['collection'] = $this->mapToDTO($resources['collection'], $this->MaesartiProductosDTO);
return $resources;
}

// Otros métodos implementados...
}

Responsabilidades principales:

  • Coordinar operaciones de negocio complejas
  • Mapear entre DTOs y entidades de dominio
  • Aplicar reglas de negocio específicas
  • Coordinar validaciones de nivel de dominio
  • Orquestar transacciones
  • Interactuar con repositorios para el acceso a datos

Métodos implementados:

  • index(): Obtiene una colección de recursos
  • selectById(): Obtiene un recurso específico por ID
  • store(): Crea un nuevo recurso
  • update(): Actualiza un recurso existente
  • delete(): Elimina un recurso
  • mapToDTO(): Convierte entidades a DTOs

Service

Además del DomainService, existe una clase más básica Service que proporciona funcionalidad similar pero con menos abstracción específica de dominio.

4.5. Organización por módulos y dominios

La aplicación organiza su funcionalidad en un sistema jerárquico de módulos y dominios que facilita la extensión y la separación de responsabilidades.

Estructura jerárquica

src/
├── ApiLayer/
│ ├── Domains/ # Dominios base de la aplicación
│ │ ├── Products/
│ │ │ ├── DTOs/
│ │ │ ├── ProductsController.php
│ │ │ ├── ProductsService.php
│ │ │ └── ProductsRoutes.php
│ │ └── ...
│ └── Modules/ # Módulos que extienden la funcionalidad base
│ ├── Permut/ # Módulo Permut
│ │ ├── Domains/
│ │ │ └── Products/
│ │ │ ├── DTOs/
│ │ │ ├── ProductsController.php
│ │ │ ├── ProductsService.php
│ │ │ └── ProductsRoutes.php
│ │ └── ...
│ ├── Tpv/ # Módulo TPV
│ │ ├── Domains/
│ │ │ ├── Carts/
│ │ │ ├── Products/
│ │ │ └── ...
│ │ ├── Middlewares/
│ │ └── ...
│ └── ...
└── ...

Dominios

Un dominio representa una unidad funcional autocontenida con su propia lógica de negocio, controladores, servicios y DTOs.

Características:

  • Cada dominio tiene su propio controlador
  • Implementa sus propios servicios específicos
  • Define sus DTOs para entrada y salida
  • Establece sus propias reglas de validación
  • Configura sus propias rutas

Módulos

Un módulo es una colección de dominios relacionados que proporcionan una funcionalidad coherente. Los módulos pueden extender o redefinir dominios base.

Características:

  • Agrupan dominios relacionados
  • Pueden extender dominios existentes
  • Pueden introducir middlewares específicos
  • Proporcionan espacio de nombres y rutas prefijadas
  • Pueden definir lógica específica del módulo

Mecanismo de extensión de dominios

La arquitectura permite extender los dominios base dentro de módulos específicos:

// Extendiendo un controlador base en un módulo
namespace ApiLayer\Modules\Permut\Domains\Products;

use ApiLayer\Domains\Products\ProductsController as DomainProductsController;

class ProductsController extends DomainProductsController
{
public function __construct(ProductsService $service)
{
parent::__construct($service);
// Aquí podemos sobreescribir las validaciones u otras propiedades
}
}

Este mecanismo permite:

  • Reutilizar la lógica base del dominio
  • Personalizar comportamientos para contextos específicos
  • Mantener una estructura coherente
  • Facilitar la evolución independiente de cada módulo
  • Promover la separación de responsabilidades

Generación de dominios y módulos

El sistema incluye herramientas para generar rápidamente nuevos dominios y módulos:

# Crear un nuevo dominio
php artesano create-domain Products p-maes_productos [Modulo]

# Crear nueva infraestructura legacy
php artesano create-legacy-infrastructure p-maes productos maesarti

Esta automatización garantiza la consistencia en la estructura y facilita la expansión del sistema.

Flujo de resolución de dominios

  1. El Router analiza la URL para determinar el módulo y dominio
  2. Se busca primero el controlador en la carpeta del módulo específico
  3. Si no se encuentra, se busca en la carpeta de dominios base
  4. Se resuelven las rutas y se ejecuta el controlador apropiado

Esta organización proporciona una arquitectura escalable y modular que facilita la extensión y el mantenimiento de la aplicación.