Rename folders to match PHP PSR-4 autoloading conventions: - schemas → Schemas - shared → Shared - Wordpress → WordPress (in all locations) Fixes deployment issues on Linux servers where filesystem is case-sensitive. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
428 lines
11 KiB
Markdown
428 lines
11 KiB
Markdown
# Capa de Aplicación (Application Layer)
|
|
|
|
## 📋 Propósito
|
|
|
|
La **Capa de Aplicación** contiene los **Use Cases** que orquestan la lógica de negocio de la aplicación. Actúa como punto de entrada coordinando el flujo entre la UI/API y la Capa de Dominio.
|
|
|
|
Esta capa es el **corazón de la arquitectura limpia**, encapsulando las reglas de negocio específicas de la aplicación sin conocer detalles de implementación.
|
|
|
|
## 🎯 Responsabilidades
|
|
|
|
### ✅ QUÉ HACE
|
|
|
|
- **Orquestar flujo de la aplicación**: Coordina la secuencia de operaciones necesarias para completar un caso de uso
|
|
- **Coordinar llamadas entre capas**: Actúa como intermediario entre la presentación y el dominio
|
|
- **Transformar datos (DTOs)**: Utiliza Data Transfer Objects para encapsular entrada/salida
|
|
- **Manejar transacciones**: Coordina operaciones que deben ejecutarse de forma atómica
|
|
- **Validar entrada**: Verifica que los datos de entrada sean válidos antes de procesarlos
|
|
- **Gestionar cache**: Coordina estrategias de cache para optimizar rendimiento
|
|
|
|
### ❌ QUÉ NO HACE
|
|
|
|
- **NO contiene lógica de negocio**: La lógica de dominio vive en la Capa de Dominio
|
|
- **NO conoce detalles de implementación**: Solo depende de interfaces, nunca de implementaciones concretas
|
|
- **NO accede directamente a BD**: Usa repositorios a través de interfaces
|
|
- **NO maneja detalles de UI**: No conoce si la petición viene de REST, CLI o WordPress Admin
|
|
|
|
## 📁 Estructura
|
|
|
|
```
|
|
Application/
|
|
├── UseCases/
|
|
│ ├── SaveComponent/
|
|
│ │ ├── SaveComponentUseCase.php (Orquestador)
|
|
│ │ ├── SaveComponentRequest.php (DTO entrada)
|
|
│ │ └── SaveComponentResponse.php (DTO salida)
|
|
│ ├── GetComponent/
|
|
│ │ ├── GetComponentUseCase.php
|
|
│ │ ├── GetComponentRequest.php
|
|
│ │ └── GetComponentResponse.php
|
|
│ ├── SyncSchema/
|
|
│ │ ├── SyncSchemaUseCase.php
|
|
│ │ ├── SyncSchemaRequest.php
|
|
│ │ └── SyncSchemaResponse.php
|
|
│ └── DeleteComponent/
|
|
│ ├── DeleteComponentUseCase.php
|
|
│ ├── DeleteComponentRequest.php
|
|
│ └── DeleteComponentResponse.php
|
|
└── README.md (este archivo)
|
|
```
|
|
|
|
## 🔧 Use Cases Disponibles
|
|
|
|
### 1. SaveComponent
|
|
|
|
**Propósito**: Guardar o actualizar la configuración de un componente.
|
|
|
|
**Flujo**:
|
|
1. Validar datos de entrada
|
|
2. Crear/actualizar entidad Component
|
|
3. Persistir en repositorio
|
|
4. Invalidar cache
|
|
5. Retornar confirmación
|
|
|
|
**Ejemplo de uso**:
|
|
|
|
```php
|
|
use ROITheme\Shared\Application\UseCases\SaveComponent\SaveComponentUseCase;
|
|
use ROITheme\Shared\Application\UseCases\SaveComponent\SaveComponentRequest;
|
|
|
|
$useCase = new SaveComponentUseCase($repository, $validator, $cache);
|
|
$request = new SaveComponentRequest('top_bar', [
|
|
'background_color' => '#ffffff',
|
|
'text_color' => '#000000',
|
|
'show_logo' => true
|
|
]);
|
|
|
|
$response = $useCase->execute($request);
|
|
|
|
if ($response->isSuccess()) {
|
|
echo "Componente guardado exitosamente";
|
|
} else {
|
|
echo "Error: " . $response->getError();
|
|
}
|
|
```
|
|
|
|
### 2. GetComponent
|
|
|
|
**Propósito**: Obtener la configuración de un componente con cache-first strategy.
|
|
|
|
**Flujo**:
|
|
1. Verificar cache
|
|
2. Si existe en cache → retornar
|
|
3. Si no → consultar repositorio
|
|
4. Guardar en cache
|
|
5. Retornar datos
|
|
|
|
**Ejemplo de uso**:
|
|
|
|
```php
|
|
use ROITheme\Shared\Application\UseCases\GetComponent\GetComponentUseCase;
|
|
use ROITheme\Shared\Application\UseCases\GetComponent\GetComponentRequest;
|
|
|
|
$useCase = new GetComponentUseCase($repository, $cache);
|
|
$request = new GetComponentRequest('top_bar');
|
|
|
|
$response = $useCase->execute($request);
|
|
|
|
if ($response->isSuccess()) {
|
|
$data = $response->getData();
|
|
// Procesar datos del componente
|
|
} else {
|
|
echo "Error: " . $response->getError();
|
|
}
|
|
```
|
|
|
|
### 3. SyncSchema
|
|
|
|
**Propósito**: Sincronizar múltiples componentes desde un archivo JSON de schemas.
|
|
|
|
**Flujo**:
|
|
1. Leer archivo JSON
|
|
2. Validar formato
|
|
3. Procesar cada componente del schema
|
|
4. Identificar cambios (agregados/actualizados/eliminados)
|
|
5. Retornar resumen de cambios
|
|
|
|
**Ejemplo de uso**:
|
|
|
|
```php
|
|
use ROITheme\Shared\Application\UseCases\SyncSchema\SyncSchemaUseCase;
|
|
use ROITheme\Shared\Application\UseCases\SyncSchema\SyncSchemaRequest;
|
|
|
|
$useCase = new SyncSchemaUseCase($componentRepo, $defaultsRepo);
|
|
$request = new SyncSchemaRequest('/path/to/schemas.json');
|
|
|
|
$response = $useCase->execute($request);
|
|
|
|
if ($response->isSuccess()) {
|
|
echo $response->getSummary();
|
|
// Output: "Added: 2, Updated: 3, Deleted: 1"
|
|
} else {
|
|
foreach ($response->getErrors() as $error) {
|
|
echo "Error: {$error}\n";
|
|
}
|
|
}
|
|
```
|
|
|
|
### 4. DeleteComponent
|
|
|
|
**Propósito**: Eliminar un componente del sistema.
|
|
|
|
**Flujo**:
|
|
1. Verificar que el componente existe
|
|
2. Eliminar de repositorio
|
|
3. Invalidar cache
|
|
4. Retornar confirmación
|
|
|
|
**Ejemplo de uso**:
|
|
|
|
```php
|
|
use ROITheme\Shared\Application\UseCases\DeleteComponent\DeleteComponentUseCase;
|
|
use ROITheme\Shared\Application\UseCases\DeleteComponent\DeleteComponentRequest;
|
|
|
|
$useCase = new DeleteComponentUseCase($repository, $cache);
|
|
$request = new DeleteComponentRequest('old_component');
|
|
|
|
$response = $useCase->execute($request);
|
|
|
|
if ($response->isSuccess()) {
|
|
echo $response->getMessage();
|
|
} else {
|
|
echo "Error: " . $response->getError();
|
|
}
|
|
```
|
|
|
|
## 🏛️ Principios Arquitectónicos
|
|
|
|
### Regla de Dependencias
|
|
|
|
```
|
|
Application Layer
|
|
↓ (depende de)
|
|
Domain Layer (solo interfaces)
|
|
↑
|
|
NO depende de Infrastructure Layer
|
|
```
|
|
|
|
La capa de aplicación **solo** puede depender de la capa de dominio, y únicamente de sus **interfaces**, nunca de implementaciones concretas.
|
|
|
|
### Dependency Inversion Principle
|
|
|
|
**✅ CORRECTO**:
|
|
|
|
```php
|
|
namespace ROITheme\Shared\Application\UseCases\SaveComponent;
|
|
|
|
use ROITheme\Shared\Domain\Contracts\ComponentRepositoryInterface;
|
|
use ROITheme\Shared\Domain\Contracts\ValidationServiceInterface;
|
|
|
|
final class SaveComponentUseCase
|
|
{
|
|
public function __construct(
|
|
private ComponentRepositoryInterface $repository, // ✅ Interfaz
|
|
private ValidationServiceInterface $validator, // ✅ Interfaz
|
|
private CacheServiceInterface $cache // ✅ Interfaz
|
|
) {}
|
|
}
|
|
```
|
|
|
|
**❌ INCORRECTO**:
|
|
|
|
```php
|
|
use ROITheme\Infrastructure\Persistence\WordPress\WordPressComponentRepository;
|
|
|
|
final class SaveComponentUseCase
|
|
{
|
|
public function __construct(
|
|
private WordPressComponentRepository $repository // ❌ Implementación concreta
|
|
) {}
|
|
}
|
|
```
|
|
|
|
### DTOs Inmutables
|
|
|
|
Todos los Request y Response utilizan `readonly class` para garantizar inmutabilidad:
|
|
|
|
```php
|
|
final readonly class SaveComponentRequest
|
|
{
|
|
public function __construct(
|
|
private string $componentName,
|
|
private array $data
|
|
) {}
|
|
|
|
// Solo getters, sin setters
|
|
public function getComponentName(): string
|
|
{
|
|
return $this->componentName;
|
|
}
|
|
}
|
|
```
|
|
|
|
### Factory Methods en Responses
|
|
|
|
Los responses utilizan factory methods para encapsular lógica de creación:
|
|
|
|
```php
|
|
final readonly class SaveComponentResponse
|
|
{
|
|
// Constructor privado
|
|
private function __construct(
|
|
private bool $success,
|
|
private ?string $error
|
|
) {}
|
|
|
|
// Factory methods públicos
|
|
public static function success(): self
|
|
{
|
|
return new self(true, null);
|
|
}
|
|
|
|
public static function failure(string $error): self
|
|
{
|
|
return new self(false, $error);
|
|
}
|
|
}
|
|
```
|
|
|
|
## 🧪 Testing
|
|
|
|
### Estrategia de Testing
|
|
|
|
Todos los Use Cases tienen tests unitarios con mocks de dependencias:
|
|
|
|
```php
|
|
namespace ROITheme\Tests\Unit\Application\UseCases;
|
|
|
|
use PHPUnit\Framework\TestCase;
|
|
use ROITheme\Shared\Application\UseCases\SaveComponent\SaveComponentUseCase;
|
|
use ROITheme\Shared\Domain\Contracts\ComponentRepositoryInterface;
|
|
use ROITheme\Shared\Domain\Contracts\ValidationServiceInterface;
|
|
|
|
class SaveComponentUseCaseTest extends TestCase
|
|
{
|
|
private ComponentRepositoryInterface $repository;
|
|
private ValidationServiceInterface $validator;
|
|
private SaveComponentUseCase $useCase;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
$this->repository = $this->createMock(ComponentRepositoryInterface::class);
|
|
$this->validator = $this->createMock(ValidationServiceInterface::class);
|
|
|
|
$this->useCase = new SaveComponentUseCase(
|
|
$this->repository,
|
|
$this->validator,
|
|
$this->cache
|
|
);
|
|
}
|
|
|
|
public function test_saves_component_successfully(): void
|
|
{
|
|
// Test implementation
|
|
}
|
|
}
|
|
```
|
|
|
|
### Ubicación de Tests
|
|
|
|
```
|
|
tests/Unit/Application/UseCases/
|
|
├── SaveComponentUseCaseTest.php
|
|
├── GetComponentUseCaseTest.php
|
|
├── SyncSchemaUseCaseTest.php
|
|
└── DeleteComponentUseCaseTest.php
|
|
```
|
|
|
|
### Cobertura Esperada
|
|
|
|
- **Objetivo**: 95%
|
|
- **Mínimo aceptable**: 90%
|
|
|
|
### Ejecutar Tests
|
|
|
|
```bash
|
|
# Todos los tests de Application
|
|
cd _planeacion/roi-theme/_testing-suite
|
|
vendor/bin/phpunit tests/Unit/Application
|
|
|
|
# Test específico
|
|
vendor/bin/phpunit tests/Unit/Application/UseCases/SaveComponentUseCaseTest.php
|
|
|
|
# Con cobertura
|
|
vendor/bin/phpunit tests/Unit/Application --coverage-text
|
|
|
|
# Reporte HTML de cobertura
|
|
vendor/bin/phpunit tests/Unit/Application --coverage-html coverage
|
|
```
|
|
|
|
## 🔍 Requisitos Técnicos
|
|
|
|
Todos los archivos de la capa de aplicación deben cumplir:
|
|
|
|
### 1. Strict Types
|
|
|
|
```php
|
|
<?php
|
|
declare(strict_types=1); // ✅ Obligatorio en todos los archivos
|
|
```
|
|
|
|
### 2. Namespace Correcto
|
|
|
|
```php
|
|
namespace ROITheme\Shared\Application\UseCases\{UseCase};
|
|
```
|
|
|
|
Patrón: **Context-First** → `ROITheme\Shared\Application\...`
|
|
|
|
### 3. PHPDoc Completo
|
|
|
|
```php
|
|
/**
|
|
* SaveComponentUseCase - Guardar/actualizar componente
|
|
*
|
|
* RESPONSABILIDAD: Orquestar guardado de componente
|
|
* ...
|
|
*
|
|
* @package ROITheme\Shared\Application\UseCases\SaveComponent
|
|
*/
|
|
final class SaveComponentUseCase
|
|
{
|
|
// ...
|
|
}
|
|
```
|
|
|
|
### 4. Type Hints Estrictos
|
|
|
|
```php
|
|
// ✅ CORRECTO
|
|
public function execute(SaveComponentRequest $request): SaveComponentResponse
|
|
{
|
|
// ...
|
|
}
|
|
|
|
// ❌ INCORRECTO
|
|
public function execute($request) // Sin type hints
|
|
{
|
|
// ...
|
|
}
|
|
```
|
|
|
|
## 📚 Referencias
|
|
|
|
- **Documentación de Fase**: `_planeacion/roi-theme/_MIGRACION-CLEAN-ARCHITECTURE/Fase-05/FASE-05-PLAN-IMPLEMENTACION.md`
|
|
- **Clean Architecture**: Robert C. Martin
|
|
- **Dependency Inversion Principle**: SOLID Principles
|
|
|
|
## ✅ Checklist de Validación
|
|
|
|
Para validar que un Use Case cumple con los estándares:
|
|
|
|
- [ ] Usa `declare(strict_types=1)`
|
|
- [ ] Namespace correcto: `ROITheme\Shared\Application\UseCases\{UseCase}`
|
|
- [ ] PHPDoc completo en clase
|
|
- [ ] Solo depende de interfaces del Domain
|
|
- [ ] Request es `final readonly class`
|
|
- [ ] Response es `final readonly class` con factory methods
|
|
- [ ] UseCase es `final class`
|
|
- [ ] Constructor injection de dependencias
|
|
- [ ] Método `execute()` con type hints
|
|
- [ ] Tests unitarios con >= 90% cobertura
|
|
- [ ] Sin dependencias de Infrastructure
|
|
|
|
## 🚀 Próximos Pasos
|
|
|
|
Después de completar la Capa de Aplicación:
|
|
|
|
1. **Fase 6**: Infrastructure Layer (Repositorios, Adaptadores)
|
|
2. **Fase 7**: API Layer (REST Endpoints)
|
|
3. **Fase 8**: Integration Tests
|
|
4. **Fase 9**: Migración gradual del código legacy
|
|
|
|
---
|
|
|
|
**Mantenedor**: ROI Theme Development Team
|
|
**Última actualización**: 2025-01-19
|
|
**Versión**: 1.0.0
|