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 dependenciasgetRequest(): Obtiene la instancia actual de la solicitudsetErrorResponse(): Establece una respuesta de errorgetResponse(): Obtiene la respuesta actualsetSuccessResponse(): Establece una respuesta exitosasendResponseAndEnd(): Envía la respuesta y finaliza la ejecucióngetActions()/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ónhandle(): 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 IDstore(): Crea un nuevo recursoupdate(): Actualiza un recurso existentedelete(): Elimina un recursoonFieldChange(): 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 recursosselectById(): Obtiene un recurso específico por IDstore(): Crea un nuevo recursoupdate(): Actualiza un recurso existentedelete(): Elimina un recursomapToDTO(): 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
- El Router analiza la URL para determinar el módulo y dominio
- Se busca primero el controlador en la carpeta del módulo específico
- Si no se encuentra, se busca en la carpeta de dominios base
- 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.