Fase-00: Estructura Clean Architecture Context-First creada
- Creada estructura shared/ con Domain, Application, Infrastructure - Documentación completa de arquitectura (5 READMEs, ~6150 líneas) - Archivos .gitkeep para preservar estructura en Git - Contextos admin/ y public/ documentados Estructura shared/: - Domain/ (ValueObjects, Exceptions, Contracts) - Application/ (Contracts, Services) - Infrastructure/ (Services, Traits) Documentación incluye: - Principios de Clean Architecture - Reglas de dependencia - Ejemplos de código - Guías de testing - Mejores prácticas Preparación completa para implementación en Fase-1.
This commit is contained in:
257
admin/README.md
Normal file
257
admin/README.md
Normal file
@@ -0,0 +1,257 @@
|
||||
# Contexto Admin - Administración de Componentes
|
||||
|
||||
## Propósito
|
||||
|
||||
El contexto `admin/` contiene **todo el código relacionado con la administración de componentes** en el panel
|
||||
de WordPress. Cada componente tiene su propia carpeta con su Clean Architecture completa.
|
||||
|
||||
## Filosofía: Context-First Architecture
|
||||
|
||||
En lugar de separar por capas (Domain, Application, Infrastructure), separamos por **contextos**
|
||||
(admin, public, shared) y cada contexto tiene sus propias capas internas.
|
||||
|
||||
## Estructura (Fase-00)
|
||||
|
||||
En Fase-00 solo creamos la estructura base. Los componentes se crearán en fases posteriores:
|
||||
|
||||
```
|
||||
admin/
|
||||
├── README.md (este archivo)
|
||||
└── .gitkeep (preserva directorio en Git)
|
||||
```
|
||||
|
||||
## Estructura Futura (Post Fase-00)
|
||||
|
||||
```
|
||||
admin/
|
||||
├── Navbar/ # Componente Navbar
|
||||
│ ├── Domain/
|
||||
│ │ ├── NavbarComponent.php # Entidad
|
||||
│ │ └── NavbarRepositoryInterface.php
|
||||
│ ├── Application/
|
||||
│ │ ├── SaveNavbarUseCase.php # Caso de uso
|
||||
│ │ └── DTO/
|
||||
│ │ └── NavbarSettingsDTO.php
|
||||
│ ├── Infrastructure/
|
||||
│ │ ├── Persistence/
|
||||
│ │ │ └── WordPressNavbarRepository.php
|
||||
│ │ ├── UI/
|
||||
│ │ │ ├── NavbarAdminPage.php # Página de admin
|
||||
│ │ │ ├── NavbarForm.php # Formulario
|
||||
│ │ │ └── views/
|
||||
│ │ │ └── navbar-settings.php
|
||||
│ │ └── API/
|
||||
│ │ └── NavbarAjaxHandler.php # AJAX endpoints
|
||||
│ └── README.md
|
||||
├── Footer/ # Otro componente
|
||||
│ └── (misma estructura)
|
||||
└── (más componentes...)
|
||||
```
|
||||
|
||||
## Principios del Contexto Admin
|
||||
|
||||
1. **Aislamiento**: Cada componente es independiente
|
||||
2. **Clean Architecture**: Cada componente tiene Domain, Application, Infrastructure
|
||||
3. **Sin acoplamiento**: Un componente no depende de otro directamente
|
||||
4. **Código compartido**: Va en `shared/` si es usado por múltiples componentes
|
||||
|
||||
## Responsabilidades
|
||||
|
||||
El contexto `admin/` se encarga de:
|
||||
|
||||
✅ **Formularios de configuración** de componentes
|
||||
✅ **Validación de entrada** del usuario administrador
|
||||
✅ **Guardado de configuraciones** en la base de datos
|
||||
✅ **Páginas de administración** en el panel de WordPress
|
||||
✅ **AJAX endpoints** para operaciones administrativas
|
||||
✅ **Permisos y capabilities** de administrador
|
||||
|
||||
❌ **NO** se encarga de:
|
||||
- Renderizado frontend de componentes (va en `public/`)
|
||||
- Lógica compartida entre contextos (va en `shared/`)
|
||||
- Configuraciones globales del tema
|
||||
|
||||
## Ejemplo de Flujo de Admin
|
||||
|
||||
### 1. Usuario administra el Navbar
|
||||
|
||||
```
|
||||
Usuario Admin (navegador)
|
||||
↓
|
||||
NavbarAdminPage.php (muestra formulario)
|
||||
↓
|
||||
Usuario envía formulario via AJAX
|
||||
↓
|
||||
NavbarAjaxHandler.php (recibe request)
|
||||
↓
|
||||
SaveNavbarUseCase.php (orquesta la lógica)
|
||||
↓
|
||||
WordPressNavbarRepository.php (guarda en DB)
|
||||
↓
|
||||
Respuesta JSON al navegador
|
||||
```
|
||||
|
||||
### 2. Código de ejemplo
|
||||
|
||||
```php
|
||||
// admin/Navbar/Application/SaveNavbarUseCase.php
|
||||
namespace ROITheme\Admin\Navbar\Application;
|
||||
|
||||
use ROITheme\Admin\Navbar\Domain\NavbarRepositoryInterface;
|
||||
use ROITheme\Shared\Application\Contracts\ValidationServiceInterface;
|
||||
|
||||
final class SaveNavbarUseCase
|
||||
{
|
||||
public function __construct(
|
||||
private readonly NavbarRepositoryInterface $repository,
|
||||
private readonly ValidationServiceInterface $validator
|
||||
) {}
|
||||
|
||||
public function execute(array $data): void
|
||||
{
|
||||
$validated = $this->validator->validate($data, [
|
||||
'logo_url' => 'url',
|
||||
'menu_items' => 'array',
|
||||
'sticky' => 'bool',
|
||||
]);
|
||||
|
||||
if ($this->validator->fails()) {
|
||||
throw new ValidationException($this->validator->errors());
|
||||
}
|
||||
|
||||
$this->repository->save($validated);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```php
|
||||
// admin/Navbar/Infrastructure/UI/NavbarAdminPage.php
|
||||
namespace ROITheme\Admin\Navbar\Infrastructure\UI;
|
||||
|
||||
final class NavbarAdminPage
|
||||
{
|
||||
public function register(): void
|
||||
{
|
||||
add_action('admin_menu', [$this, 'addMenuPage']);
|
||||
}
|
||||
|
||||
public function addMenuPage(): void
|
||||
{
|
||||
add_menu_page(
|
||||
'Navbar Settings',
|
||||
'Navbar',
|
||||
'manage_options',
|
||||
'roi-navbar-settings',
|
||||
[$this, 'render'],
|
||||
'dashicons-menu',
|
||||
30
|
||||
);
|
||||
}
|
||||
|
||||
public function render(): void
|
||||
{
|
||||
require __DIR__ . '/views/navbar-settings.php';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Relación con Otros Contextos
|
||||
|
||||
```
|
||||
admin/ → Administra configuraciones
|
||||
↓ guarda
|
||||
Base de Datos → Almacena settings
|
||||
↓ lee
|
||||
public/ → Renderiza componentes en frontend
|
||||
```
|
||||
|
||||
**Clave**: `admin/` y `public/` NO se hablan directamente. Se comunican a través de la base de datos.
|
||||
|
||||
## Reglas de Dependencia
|
||||
|
||||
✅ **PUEDE** depender de:
|
||||
- `shared/Domain/` (Value Objects, Exceptions)
|
||||
- `shared/Application/` (Contracts, Services)
|
||||
- `shared/Infrastructure/` (Implementaciones de servicios)
|
||||
- WordPress admin functions (`add_menu_page`, `add_settings_section`, etc.)
|
||||
|
||||
❌ **NO PUEDE** depender de:
|
||||
- `public/` (contexto independiente)
|
||||
- Código de frontend (JS/CSS va en Infrastructure/UI/)
|
||||
|
||||
## Testing
|
||||
|
||||
### Tests Unitarios
|
||||
```php
|
||||
// tests/Unit/Admin/Navbar/Application/SaveNavbarUseCaseTest.php
|
||||
public function test_saves_valid_navbar_settings()
|
||||
{
|
||||
$repository = $this->createMock(NavbarRepositoryInterface::class);
|
||||
$validator = $this->createMock(ValidationServiceInterface::class);
|
||||
|
||||
$useCase = new SaveNavbarUseCase($repository, $validator);
|
||||
$useCase->execute(['logo_url' => 'http://example.com/logo.png']);
|
||||
|
||||
// Assertions...
|
||||
}
|
||||
```
|
||||
|
||||
### Tests de Integración
|
||||
```php
|
||||
// tests/Integration/Admin/Navbar/Infrastructure/WordPressNavbarRepositoryTest.php
|
||||
public function test_saves_and_retrieves_navbar_settings()
|
||||
{
|
||||
$repository = new WordPressNavbarRepository();
|
||||
$settings = ['logo_url' => 'http://example.com/logo.png'];
|
||||
|
||||
$repository->save($settings);
|
||||
$retrieved = $repository->get();
|
||||
|
||||
$this->assertEquals($settings, $retrieved);
|
||||
}
|
||||
```
|
||||
|
||||
### Tests E2E (Playwright)
|
||||
```php
|
||||
// tests/E2E/Admin/NavbarAdminPageTest.php
|
||||
public function test_admin_can_save_navbar_settings()
|
||||
{
|
||||
$this->loginAsAdmin();
|
||||
$this->visit('/wp-admin/admin.php?page=roi-navbar-settings');
|
||||
$this->fillField('logo_url', 'http://example.com/logo.png');
|
||||
$this->click('Save Settings');
|
||||
$this->see('Settings saved successfully');
|
||||
}
|
||||
```
|
||||
|
||||
## Cuándo Agregar Código Aquí
|
||||
|
||||
Agrega código a `admin/` cuando:
|
||||
- Creas un nuevo componente administrable
|
||||
- Necesitas una página de configuración en el panel de WordPress
|
||||
- Manejas formularios de administrador
|
||||
- Procesas AJAX desde el admin
|
||||
- Validas o guardas configuraciones
|
||||
|
||||
No agregues aquí:
|
||||
- Renderizado frontend (va en `public/`)
|
||||
- Lógica compartida (va en `shared/`)
|
||||
- Configuraciones globales del tema
|
||||
|
||||
## Estado Actual (Fase-00)
|
||||
|
||||
En Fase-00, `admin/` solo tiene la estructura base. Los componentes se crearán en las siguientes fases:
|
||||
|
||||
- **Fase-1**: Estructura base e infraestructura
|
||||
- **Fase-2**: Migración de base de datos
|
||||
- **Fase-3**: Implementación de componentes admin
|
||||
- **Fase-4+**: Componentes adicionales
|
||||
|
||||
## Próximos Pasos
|
||||
|
||||
1. Crear primer componente en Fase-3 (ej: Navbar)
|
||||
2. Implementar Domain layer del componente
|
||||
3. Implementar Application layer (casos de uso)
|
||||
4. Implementar Infrastructure layer (WordPress integration)
|
||||
5. Crear tests unitarios e integración
|
||||
6. Repetir para cada componente
|
||||
393
public/README.md
Normal file
393
public/README.md
Normal file
@@ -0,0 +1,393 @@
|
||||
# Contexto Public - Renderizado Frontend de Componentes
|
||||
|
||||
## Propósito
|
||||
|
||||
El contexto `public/` contiene **todo el código relacionado con el renderizado de componentes en el frontend**.
|
||||
Cada componente tiene su propia carpeta con su Clean Architecture completa.
|
||||
|
||||
## Filosofía: Context-First Architecture
|
||||
|
||||
Similar a `admin/`, el contexto `public/` agrupa todo lo relacionado con la visualización pública de componentes.
|
||||
Cada componente es independiente y tiene sus propias capas de Clean Architecture.
|
||||
|
||||
## Estructura (Fase-00)
|
||||
|
||||
En Fase-00 solo creamos la estructura base. Los componentes se crearán en fases posteriores:
|
||||
|
||||
```
|
||||
public/
|
||||
├── README.md (este archivo)
|
||||
└── .gitkeep (preserva directorio en Git)
|
||||
```
|
||||
|
||||
## Estructura Futura (Post Fase-00)
|
||||
|
||||
```
|
||||
public/
|
||||
├── Navbar/ # Componente Navbar
|
||||
│ ├── Domain/
|
||||
│ │ ├── NavbarData.php # Entidad de lectura
|
||||
│ │ └── NavbarDataProviderInterface.php
|
||||
│ ├── Application/
|
||||
│ │ ├── GetNavbarDataUseCase.php # Caso de uso
|
||||
│ │ └── DTO/
|
||||
│ │ └── NavbarDataDTO.php
|
||||
│ ├── Infrastructure/
|
||||
│ │ ├── Persistence/
|
||||
│ │ │ └── WordPressNavbarDataProvider.php
|
||||
│ │ ├── UI/
|
||||
│ │ │ ├── NavbarRenderer.php # Renderizador
|
||||
│ │ │ ├── views/
|
||||
│ │ │ │ └── navbar.php # Template
|
||||
│ │ │ └── assets/
|
||||
│ │ │ ├── css/
|
||||
│ │ │ │ └── navbar.css
|
||||
│ │ │ └── js/
|
||||
│ │ │ └── navbar.js
|
||||
│ │ └── Hooks/
|
||||
│ │ └── NavbarHooks.php # WordPress hooks
|
||||
│ └── README.md
|
||||
├── Footer/ # Otro componente
|
||||
│ └── (misma estructura)
|
||||
└── (más componentes...)
|
||||
```
|
||||
|
||||
## Principios del Contexto Public
|
||||
|
||||
1. **Solo lectura**: El frontend solo lee configuraciones, no las modifica
|
||||
2. **Performance**: Optimizado para carga rápida y caché
|
||||
3. **Presentación**: Se enfoca en renderizar HTML, CSS, JS
|
||||
4. **Independencia**: Cada componente es autónomo
|
||||
|
||||
## Responsabilidades
|
||||
|
||||
El contexto `public/` se encarga de:
|
||||
|
||||
✅ **Renderizado de componentes** en el frontend
|
||||
✅ **Lectura de configuraciones** de la base de datos
|
||||
✅ **Generación de HTML** según templates
|
||||
✅ **Carga de assets** (CSS, JS) del componente
|
||||
✅ **Enqueue de scripts y estilos**
|
||||
✅ **Hooks de WordPress** para frontend (`wp_head`, `wp_footer`, etc.)
|
||||
|
||||
❌ **NO** se encarga de:
|
||||
- Administración de componentes (va en `admin/`)
|
||||
- Guardado de configuraciones
|
||||
- Lógica compartida (va en `shared/`)
|
||||
|
||||
## Ejemplo de Flujo de Public
|
||||
|
||||
### 1. Usuario visita página web
|
||||
|
||||
```
|
||||
Usuario (navegador)
|
||||
↓
|
||||
WordPress carga tema
|
||||
↓
|
||||
NavbarHooks.php (registra hook 'wp_body_open')
|
||||
↓
|
||||
Hook ejecutado
|
||||
↓
|
||||
NavbarRenderer.php (obtiene datos y renderiza)
|
||||
↓
|
||||
GetNavbarDataUseCase.php (obtiene configuración)
|
||||
↓
|
||||
WordPressNavbarDataProvider.php (lee de DB)
|
||||
↓
|
||||
navbar.php (template con HTML)
|
||||
↓
|
||||
HTML enviado al navegador
|
||||
```
|
||||
|
||||
### 2. Código de ejemplo
|
||||
|
||||
```php
|
||||
// public/Navbar/Application/GetNavbarDataUseCase.php
|
||||
namespace ROITheme\Public\Navbar\Application;
|
||||
|
||||
use ROITheme\Public\Navbar\Domain\NavbarDataProviderInterface;
|
||||
|
||||
final class GetNavbarDataUseCase
|
||||
{
|
||||
public function __construct(
|
||||
private readonly NavbarDataProviderInterface $dataProvider
|
||||
) {}
|
||||
|
||||
public function execute(): array
|
||||
{
|
||||
$data = $this->dataProvider->get();
|
||||
|
||||
// Transformar datos si es necesario
|
||||
return [
|
||||
'logo_url' => $data['logo_url'] ?? '',
|
||||
'menu_items' => $data['menu_items'] ?? [],
|
||||
'sticky' => $data['sticky'] ?? false,
|
||||
];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```php
|
||||
// public/Navbar/Infrastructure/UI/NavbarRenderer.php
|
||||
namespace ROITheme\Public\Navbar\Infrastructure\UI;
|
||||
|
||||
use ROITheme\Public\Navbar\Application\GetNavbarDataUseCase;
|
||||
|
||||
final class NavbarRenderer
|
||||
{
|
||||
public function __construct(
|
||||
private readonly GetNavbarDataUseCase $getNavbarData
|
||||
) {}
|
||||
|
||||
public function render(): void
|
||||
{
|
||||
$data = $this->getNavbarData->execute();
|
||||
|
||||
// Encolar assets
|
||||
wp_enqueue_style(
|
||||
'roi-navbar',
|
||||
get_template_directory_uri() . '/public/Navbar/Infrastructure/UI/assets/css/navbar.css',
|
||||
[],
|
||||
'1.0.0'
|
||||
);
|
||||
|
||||
wp_enqueue_script(
|
||||
'roi-navbar',
|
||||
get_template_directory_uri() . '/public/Navbar/Infrastructure/UI/assets/js/navbar.js',
|
||||
['jquery'],
|
||||
'1.0.0',
|
||||
true
|
||||
);
|
||||
|
||||
// Renderizar template
|
||||
require __DIR__ . '/views/navbar.php';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```php
|
||||
// public/Navbar/Infrastructure/Hooks/NavbarHooks.php
|
||||
namespace ROITheme\Public\Navbar\Infrastructure\Hooks;
|
||||
|
||||
use ROITheme\Public\Navbar\Infrastructure\UI\NavbarRenderer;
|
||||
|
||||
final class NavbarHooks
|
||||
{
|
||||
public function __construct(
|
||||
private readonly NavbarRenderer $renderer
|
||||
) {}
|
||||
|
||||
public function register(): void
|
||||
{
|
||||
add_action('wp_body_open', [$this->renderer, 'render']);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```php
|
||||
// public/Navbar/Infrastructure/UI/views/navbar.php
|
||||
<?php
|
||||
/**
|
||||
* Template del Navbar
|
||||
*
|
||||
* @var array $data Datos del navbar
|
||||
*/
|
||||
?>
|
||||
<nav class="roi-navbar <?= $data['sticky'] ? 'sticky' : '' ?>">
|
||||
<div class="container">
|
||||
<a href="<?= home_url() ?>">
|
||||
<img src="<?= esc_url($data['logo_url']) ?>" alt="Logo">
|
||||
</a>
|
||||
<ul class="menu">
|
||||
<?php foreach ($data['menu_items'] as $item): ?>
|
||||
<li>
|
||||
<a href="<?= esc_url($item['url']) ?>">
|
||||
<?= esc_html($item['label']) ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
```
|
||||
|
||||
## Relación con Otros Contextos
|
||||
|
||||
```
|
||||
admin/ → Guarda configuraciones
|
||||
↓
|
||||
Base de Datos → Almacena settings
|
||||
↓ lee
|
||||
public/ → Renderiza componentes
|
||||
↓
|
||||
Navegador del Usuario
|
||||
```
|
||||
|
||||
**Clave**: `public/` solo LECTURA, nunca escritura.
|
||||
|
||||
## Optimización y Caché
|
||||
|
||||
### 1. Usar Transients de WordPress
|
||||
|
||||
```php
|
||||
public function get(): array
|
||||
{
|
||||
$cached = get_transient('roi_navbar_data');
|
||||
|
||||
if ($cached !== false) {
|
||||
return $cached;
|
||||
}
|
||||
|
||||
$data = $this->fetchFromDatabase();
|
||||
set_transient('roi_navbar_data', $data, HOUR_IN_SECONDS);
|
||||
|
||||
return $data;
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Conditional Asset Loading
|
||||
|
||||
```php
|
||||
if ($data['sticky']) {
|
||||
wp_enqueue_script('roi-navbar-sticky');
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Lazy Loading de Componentes
|
||||
|
||||
```php
|
||||
add_action('wp_body_open', function() {
|
||||
if (is_front_page()) {
|
||||
// Solo cargar en homepage
|
||||
$renderer->render();
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## Reglas de Dependencia
|
||||
|
||||
✅ **PUEDE** depender de:
|
||||
- `shared/Domain/` (Value Objects, Exceptions)
|
||||
- `shared/Application/` (Contracts, Services)
|
||||
- `shared/Infrastructure/` (Implementaciones de servicios)
|
||||
- WordPress frontend functions (`wp_enqueue_style`, `wp_head`, etc.)
|
||||
|
||||
❌ **NO PUEDE** depender de:
|
||||
- `admin/` (contexto independiente)
|
||||
- Funciones de administración de WordPress
|
||||
|
||||
## Testing
|
||||
|
||||
### Tests Unitarios
|
||||
```php
|
||||
// tests/Unit/Public/Navbar/Application/GetNavbarDataUseCaseTest.php
|
||||
public function test_returns_navbar_data()
|
||||
{
|
||||
$dataProvider = $this->createMock(NavbarDataProviderInterface::class);
|
||||
$dataProvider->method('get')->willReturn(['logo_url' => 'test.png']);
|
||||
|
||||
$useCase = new GetNavbarDataUseCase($dataProvider);
|
||||
$data = $useCase->execute();
|
||||
|
||||
$this->assertEquals('test.png', $data['logo_url']);
|
||||
}
|
||||
```
|
||||
|
||||
### Tests de Integración
|
||||
```php
|
||||
// tests/Integration/Public/Navbar/Infrastructure/WordPressNavbarDataProviderTest.php
|
||||
public function test_retrieves_navbar_settings_from_db()
|
||||
{
|
||||
update_option('roi_navbar_settings', ['logo_url' => 'test.png']);
|
||||
|
||||
$provider = new WordPressNavbarDataProvider();
|
||||
$data = $provider->get();
|
||||
|
||||
$this->assertEquals('test.png', $data['logo_url']);
|
||||
}
|
||||
```
|
||||
|
||||
### Tests E2E (Playwright)
|
||||
```php
|
||||
// tests/E2E/Public/NavbarRenderingTest.php
|
||||
public function test_navbar_renders_on_homepage()
|
||||
{
|
||||
$this->visit('/');
|
||||
$this->see('.roi-navbar');
|
||||
$this->see('Logo');
|
||||
}
|
||||
```
|
||||
|
||||
### Tests de Performance
|
||||
```php
|
||||
// tests/Performance/Public/NavbarPerformanceTest.php
|
||||
public function test_navbar_renders_in_less_than_100ms()
|
||||
{
|
||||
$start = microtime(true);
|
||||
|
||||
$renderer = new NavbarRenderer($this->getNavbarDataUseCase);
|
||||
ob_start();
|
||||
$renderer->render();
|
||||
ob_end_clean();
|
||||
|
||||
$duration = (microtime(true) - $start) * 1000;
|
||||
|
||||
$this->assertLessThan(100, $duration);
|
||||
}
|
||||
```
|
||||
|
||||
## Cuándo Agregar Código Aquí
|
||||
|
||||
Agrega código a `public/` cuando:
|
||||
- Renderizas un componente en el frontend
|
||||
- Necesitas mostrar datos al usuario final
|
||||
- Cargas assets (CSS, JS) para el frontend
|
||||
- Registras hooks de frontend (`wp_head`, `wp_footer`, etc.)
|
||||
- Optimizas performance de renderizado
|
||||
|
||||
No agregues aquí:
|
||||
- Formularios de admin (van en `admin/`)
|
||||
- Guardado de configuraciones
|
||||
- Lógica compartida (va en `shared/`)
|
||||
|
||||
## Assets y Performance
|
||||
|
||||
### Organización de Assets
|
||||
```
|
||||
public/Navbar/Infrastructure/UI/assets/
|
||||
├── css/
|
||||
│ ├── navbar.css # Estilos del componente
|
||||
│ └── navbar.min.css # Versión minificada
|
||||
├── js/
|
||||
│ ├── navbar.js # JavaScript del componente
|
||||
│ └── navbar.min.js # Versión minificada
|
||||
└── images/
|
||||
└── default-logo.png # Imágenes del componente
|
||||
```
|
||||
|
||||
### Minificación y Concatenación
|
||||
En producción, usar versiones minificadas:
|
||||
```php
|
||||
$suffix = defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? '' : '.min';
|
||||
wp_enqueue_style('roi-navbar', "...navbar{$suffix}.css");
|
||||
```
|
||||
|
||||
## Estado Actual (Fase-00)
|
||||
|
||||
En Fase-00, `public/` solo tiene la estructura base. Los componentes se crearán en las siguientes fases:
|
||||
|
||||
- **Fase-1**: Estructura base e infraestructura
|
||||
- **Fase-2**: Migración de base de datos
|
||||
- **Fase-3**: Implementación de componentes públicos
|
||||
- **Fase-4+**: Componentes adicionales y optimización
|
||||
|
||||
## Próximos Pasos
|
||||
|
||||
1. Crear primer componente en Fase-3 (ej: Navbar)
|
||||
2. Implementar Domain layer (entidades de lectura)
|
||||
3. Implementar Application layer (casos de uso de lectura)
|
||||
4. Implementar Infrastructure layer (renderizado, hooks)
|
||||
5. Crear templates y assets
|
||||
6. Optimizar con caché
|
||||
7. Crear tests de performance
|
||||
8. Repetir para cada componente
|
||||
0
shared/Application/Contracts/.gitkeep
Normal file
0
shared/Application/Contracts/.gitkeep
Normal file
138
shared/Application/README.md
Normal file
138
shared/Application/README.md
Normal file
@@ -0,0 +1,138 @@
|
||||
# Capa de Aplicación - Shared (Casos de Uso Compartidos)
|
||||
|
||||
## Propósito
|
||||
|
||||
La capa de Aplicación de `shared/` contiene **casos de uso y servicios compartidos** que orquestan la lógica
|
||||
de dominio. Esta capa coordina el flujo de datos entre el dominio y la infraestructura.
|
||||
|
||||
## Principios
|
||||
|
||||
1. **Orquestación**: Coordina objetos de dominio para realizar casos de uso
|
||||
2. **Sin lógica de negocio**: Delega la lógica al dominio
|
||||
3. **Independiente de frameworks**: No depende de WordPress directamente
|
||||
4. **Contratos claros**: Define interfaces para servicios
|
||||
|
||||
## Estructura
|
||||
|
||||
```
|
||||
shared/Application/
|
||||
├── Contracts/ # Interfaces de servicios (CacheServiceInterface, etc.)
|
||||
└── Services/ # Implementaciones de servicios compartidos
|
||||
```
|
||||
|
||||
## Ejemplos de Uso
|
||||
|
||||
### Contracts (Interfaces de Servicios)
|
||||
|
||||
```php
|
||||
namespace ROITheme\Shared\Application\Contracts;
|
||||
|
||||
interface CacheServiceInterface
|
||||
{
|
||||
public function get(string $key): mixed;
|
||||
public function set(string $key, mixed $value, int $ttl = 3600): bool;
|
||||
public function delete(string $key): bool;
|
||||
public function flush(): bool;
|
||||
}
|
||||
```
|
||||
|
||||
```php
|
||||
namespace ROITheme\Shared\Application\Contracts;
|
||||
|
||||
interface ValidationServiceInterface
|
||||
{
|
||||
public function validate(array $data, array $rules): array;
|
||||
public function fails(): bool;
|
||||
public function errors(): array;
|
||||
}
|
||||
```
|
||||
|
||||
### Services (Implementaciones Abstractas)
|
||||
|
||||
Servicios que pueden tener múltiples implementaciones:
|
||||
|
||||
```php
|
||||
namespace ROITheme\Shared\Application\Services;
|
||||
|
||||
use ROITheme\Shared\Application\Contracts\ValidationServiceInterface;
|
||||
|
||||
abstract class BaseValidationService implements ValidationServiceInterface
|
||||
{
|
||||
protected array $errors = [];
|
||||
|
||||
public function fails(): bool
|
||||
{
|
||||
return !empty($this->errors);
|
||||
}
|
||||
|
||||
public function errors(): array
|
||||
{
|
||||
return $this->errors;
|
||||
}
|
||||
|
||||
abstract public function validate(array $data, array $rules): array;
|
||||
}
|
||||
```
|
||||
|
||||
## Relación con Infrastructure
|
||||
|
||||
La capa de Application **define contratos** (interfaces), pero **no implementa** la lógica específica
|
||||
de frameworks. Las implementaciones concretas van en `shared/Infrastructure/`:
|
||||
|
||||
```
|
||||
shared/Application/Contracts/CacheServiceInterface.php (interface)
|
||||
↓
|
||||
shared/Infrastructure/Services/WordPressCacheService.php (implementación)
|
||||
```
|
||||
|
||||
## Reglas de Dependencia
|
||||
|
||||
✅ **PUEDE** depender de:
|
||||
- `shared/Domain/` (Value Objects, Entities, Exceptions)
|
||||
- Interfaces dentro de `shared/Application/Contracts/`
|
||||
|
||||
❌ **NO PUEDE** depender de:
|
||||
- `shared/Infrastructure/` (implementaciones concretas)
|
||||
- `admin/` o `public/`
|
||||
- WordPress functions directamente
|
||||
- Detalles de implementación
|
||||
|
||||
## Testing
|
||||
|
||||
Los servicios de esta capa se testean con **tests unitarios usando mocks**:
|
||||
|
||||
```php
|
||||
// tests/Unit/Shared/Application/Services/SomeServiceTest.php
|
||||
public function test_validates_data_correctly()
|
||||
{
|
||||
$validator = $this->createMock(ValidationServiceInterface::class);
|
||||
$validator->method('validate')->willReturn(['name' => 'Test']);
|
||||
|
||||
$service = new SomeService($validator);
|
||||
$result = $service->process(['name' => 'Test']);
|
||||
|
||||
$this->assertTrue($result);
|
||||
}
|
||||
```
|
||||
|
||||
## Cuándo Agregar Código Aquí
|
||||
|
||||
Agrega código a `shared/Application/` cuando:
|
||||
- Defines un contrato para un servicio compartido
|
||||
- Necesitas orquestar múltiples objetos de dominio
|
||||
- El servicio será usado por admin/ y public/
|
||||
- Necesitas abstraer implementaciones de infraestructura
|
||||
|
||||
No agregues aquí:
|
||||
- Lógica de negocio (va en Domain/)
|
||||
- Implementaciones concretas de WordPress (van en Infrastructure/)
|
||||
- Lógica específica de un solo contexto
|
||||
- Código acoplado a frameworks
|
||||
|
||||
## Ejemplos de Servicios Comunes
|
||||
|
||||
- `ValidationServiceInterface`: Validación de datos
|
||||
- `CacheServiceInterface`: Manejo de caché
|
||||
- `SerializerServiceInterface`: Serialización de datos
|
||||
- `LoggerServiceInterface`: Logging
|
||||
- `EventDispatcherInterface`: Eventos del sistema
|
||||
0
shared/Application/Services/.gitkeep
Normal file
0
shared/Application/Services/.gitkeep
Normal file
0
shared/Domain/Contracts/.gitkeep
Normal file
0
shared/Domain/Contracts/.gitkeep
Normal file
0
shared/Domain/Exceptions/.gitkeep
Normal file
0
shared/Domain/Exceptions/.gitkeep
Normal file
127
shared/Domain/README.md
Normal file
127
shared/Domain/README.md
Normal file
@@ -0,0 +1,127 @@
|
||||
# Capa de Dominio - Shared (Fundación)
|
||||
|
||||
## Propósito
|
||||
|
||||
La capa de Dominio de `shared/` contiene la **lógica de negocio compartida** que utilizan todos los contextos
|
||||
(admin y public). Es la fundación del proyecto y no debe tener dependencias de frameworks, librerías externas, o
|
||||
capas superiores.
|
||||
|
||||
## Principios
|
||||
|
||||
1. **Sin dependencias externas**: No depende de WordPress, plugins, o librerías
|
||||
2. **Lógica pura**: Solo reglas de negocio y objetos de dominio
|
||||
3. **Inmutabilidad**: Los Value Objects son inmutables
|
||||
4. **Validación**: Los objetos se validan a sí mismos
|
||||
|
||||
## Estructura
|
||||
|
||||
```
|
||||
shared/Domain/
|
||||
├── ValueObjects/ # Value Objects compartidos (ComponentID, SettingValue, etc.)
|
||||
├── Exceptions/ # Excepciones de dominio (InvalidComponentException, etc.)
|
||||
└── Contracts/ # Interfaces de repositorios y servicios de dominio
|
||||
```
|
||||
|
||||
## Ejemplos de Uso
|
||||
|
||||
### Value Objects
|
||||
|
||||
Value Objects que representan conceptos del dominio:
|
||||
|
||||
```php
|
||||
namespace ROITheme\Shared\Domain\ValueObjects;
|
||||
|
||||
final class ComponentID
|
||||
{
|
||||
private int $value;
|
||||
|
||||
public function __construct(int $value)
|
||||
{
|
||||
if ($value <= 0) {
|
||||
throw new \InvalidArgumentException('Component ID must be positive');
|
||||
}
|
||||
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
public function value(): int
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
public function equals(ComponentID $other): bool
|
||||
{
|
||||
return $this->value === $other->value;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Excepciones
|
||||
|
||||
Excepciones específicas del dominio:
|
||||
|
||||
```php
|
||||
namespace ROITheme\Shared\Domain\Exceptions;
|
||||
|
||||
class InvalidComponentException extends \DomainException
|
||||
{
|
||||
public static function withId(int $id): self
|
||||
{
|
||||
return new self("Component with ID {$id} is invalid");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Contracts (Interfaces)
|
||||
|
||||
Interfaces que definen comportamientos:
|
||||
|
||||
```php
|
||||
namespace ROITheme\Shared\Domain\Contracts;
|
||||
|
||||
interface ComponentRepositoryInterface
|
||||
{
|
||||
public function findById(ComponentID $id): ?Component;
|
||||
public function save(Component $component): void;
|
||||
}
|
||||
```
|
||||
|
||||
## Reglas de Dependencia
|
||||
|
||||
✅ **PUEDE** depender de:
|
||||
- Otros objetos dentro de `shared/Domain/`
|
||||
- SPL (Standard PHP Library)
|
||||
- Nada más
|
||||
|
||||
❌ **NO PUEDE** depender de:
|
||||
- `shared/Application/`
|
||||
- `shared/Infrastructure/`
|
||||
- `admin/` o `public/`
|
||||
- WordPress functions
|
||||
- Librerías externas
|
||||
|
||||
## Testing
|
||||
|
||||
Los objetos de esta capa se testean con **tests unitarios puros**, sin necesidad de WordPress:
|
||||
|
||||
```php
|
||||
// tests/Unit/Shared/Domain/ValueObjects/ComponentIDTest.php
|
||||
public function test_creates_valid_component_id()
|
||||
{
|
||||
$id = new ComponentID(123);
|
||||
$this->assertEquals(123, $id->value());
|
||||
}
|
||||
```
|
||||
|
||||
## Cuándo Agregar Código Aquí
|
||||
|
||||
Agrega código a `shared/Domain/` cuando:
|
||||
- Es lógica de negocio pura (sin WordPress)
|
||||
- Es compartido por admin/ y public/
|
||||
- Es un concepto fundamental del dominio
|
||||
- Necesita alta cohesión y bajo acoplamiento
|
||||
|
||||
No agregues aquí:
|
||||
- Código que depende de WordPress
|
||||
- Lógica específica de un solo contexto
|
||||
- Implementaciones concretas de servicios
|
||||
0
shared/Domain/ValueObjects/.gitkeep
Normal file
0
shared/Domain/ValueObjects/.gitkeep
Normal file
217
shared/Infrastructure/README.md
Normal file
217
shared/Infrastructure/README.md
Normal file
@@ -0,0 +1,217 @@
|
||||
# Capa de Infraestructura - Shared (Implementaciones Concretas)
|
||||
|
||||
## Propósito
|
||||
|
||||
La capa de Infraestructura de `shared/` contiene **implementaciones concretas** de los servicios definidos en
|
||||
Application, utilizando WordPress y otras librerías externas.
|
||||
|
||||
## Principios
|
||||
|
||||
1. **Implementaciones concretas**: Código que interactúa con WordPress y librerías
|
||||
2. **Cumple contratos**: Implementa las interfaces definidas en Application
|
||||
3. **Detalles técnicos**: Maneja aspectos técnicos como caché, base de datos, APIs
|
||||
4. **Reusabilidad**: Servicios compartidos por todos los contextos
|
||||
|
||||
## Estructura
|
||||
|
||||
```
|
||||
shared/Infrastructure/
|
||||
├── Services/ # Implementaciones de servicios (WordPressCacheService, etc.)
|
||||
└── Traits/ # Traits reutilizables (WordPress helpers, etc.)
|
||||
```
|
||||
|
||||
## Ejemplos de Uso
|
||||
|
||||
### Services (Implementaciones Concretas)
|
||||
|
||||
Implementación de CacheService usando WordPress Transients:
|
||||
|
||||
```php
|
||||
namespace ROITheme\Shared\Infrastructure\Services;
|
||||
|
||||
use ROITheme\Shared\Application\Contracts\CacheServiceInterface;
|
||||
|
||||
final class WordPressCacheService implements CacheServiceInterface
|
||||
{
|
||||
public function get(string $key): mixed
|
||||
{
|
||||
return get_transient($this->prefixKey($key));
|
||||
}
|
||||
|
||||
public function set(string $key, mixed $value, int $ttl = 3600): bool
|
||||
{
|
||||
return set_transient($this->prefixKey($key), $value, $ttl);
|
||||
}
|
||||
|
||||
public function delete(string $key): bool
|
||||
{
|
||||
return delete_transient($this->prefixKey($key));
|
||||
}
|
||||
|
||||
public function flush(): bool
|
||||
{
|
||||
return wp_cache_flush();
|
||||
}
|
||||
|
||||
private function prefixKey(string $key): string
|
||||
{
|
||||
return 'roi_theme_' . $key;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Implementación de ValidationService usando WordPress Sanitization:
|
||||
|
||||
```php
|
||||
namespace ROITheme\Shared\Infrastructure\Services;
|
||||
|
||||
use ROITheme\Shared\Application\Services\BaseValidationService;
|
||||
|
||||
final class WordPressValidationService extends BaseValidationService
|
||||
{
|
||||
public function validate(array $data, array $rules): array
|
||||
{
|
||||
$validated = [];
|
||||
|
||||
foreach ($rules as $field => $rule) {
|
||||
if (!isset($data[$field])) {
|
||||
$this->errors[$field] = "Field {$field} is required";
|
||||
continue;
|
||||
}
|
||||
|
||||
$validated[$field] = match($rule) {
|
||||
'email' => sanitize_email($data[$field]),
|
||||
'text' => sanitize_text_field($data[$field]),
|
||||
'int' => intval($data[$field]),
|
||||
'url' => esc_url_raw($data[$field]),
|
||||
default => $data[$field]
|
||||
};
|
||||
}
|
||||
|
||||
return $validated;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Traits (Helpers Reutilizables)
|
||||
|
||||
Traits para funcionalidad común de WordPress:
|
||||
|
||||
```php
|
||||
namespace ROITheme\Shared\Infrastructure\Traits;
|
||||
|
||||
trait WordPressMetaDataTrait
|
||||
{
|
||||
private function getMeta(int $postId, string $key, bool $single = true): mixed
|
||||
{
|
||||
return get_post_meta($postId, $this->prefixMetaKey($key), $single);
|
||||
}
|
||||
|
||||
private function updateMeta(int $postId, string $key, mixed $value): bool
|
||||
{
|
||||
return update_post_meta($postId, $this->prefixMetaKey($key), $value);
|
||||
}
|
||||
|
||||
private function deleteMeta(int $postId, string $key): bool
|
||||
{
|
||||
return delete_post_meta($postId, $this->prefixMetaKey($key));
|
||||
}
|
||||
|
||||
private function prefixMetaKey(string $key): string
|
||||
{
|
||||
return '_roi_' . $key;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Relación con Application
|
||||
|
||||
La capa Infrastructure **implementa** los contratos definidos en Application:
|
||||
|
||||
```
|
||||
shared/Application/Contracts/CacheServiceInterface.php (interface)
|
||||
↓ implementa
|
||||
shared/Infrastructure/Services/WordPressCacheService.php (implementación)
|
||||
```
|
||||
|
||||
## Inyección de Dependencias
|
||||
|
||||
Los servicios se registran en el DI Container y se inyectan a través de constructores:
|
||||
|
||||
```php
|
||||
// En el DI Container (configuración)
|
||||
$container->bind(
|
||||
CacheServiceInterface::class,
|
||||
WordPressCacheService::class
|
||||
);
|
||||
|
||||
// En el código que usa el servicio
|
||||
public function __construct(
|
||||
private readonly CacheServiceInterface $cache
|
||||
) {}
|
||||
```
|
||||
|
||||
## Reglas de Dependencia
|
||||
|
||||
✅ **PUEDE** depender de:
|
||||
- `shared/Domain/` (Value Objects, Entities)
|
||||
- `shared/Application/` (especialmente Contracts)
|
||||
- WordPress functions
|
||||
- Librerías externas (Composer packages)
|
||||
|
||||
❌ **NO PUEDE** depender de:
|
||||
- `admin/` o `public/` (contextos específicos)
|
||||
|
||||
## Testing
|
||||
|
||||
Los servicios de Infrastructure se testean con **tests de integración** que usan WordPress:
|
||||
|
||||
```php
|
||||
// tests/Integration/Shared/Infrastructure/Services/WordPressCacheServiceTest.php
|
||||
public function test_stores_and_retrieves_from_cache()
|
||||
{
|
||||
$cache = new WordPressCacheService();
|
||||
|
||||
$cache->set('test_key', 'test_value', 3600);
|
||||
$result = $cache->get('test_key');
|
||||
|
||||
$this->assertEquals('test_value', $result);
|
||||
}
|
||||
```
|
||||
|
||||
## Cuándo Agregar Código Aquí
|
||||
|
||||
Agrega código a `shared/Infrastructure/` cuando:
|
||||
- Implementas un servicio definido en Application/Contracts/
|
||||
- Necesitas interactuar con WordPress (base de datos, caché, opciones, etc.)
|
||||
- Integras una librería externa
|
||||
- Creas utilidades de bajo nivel compartidas
|
||||
|
||||
No agregues aquí:
|
||||
- Lógica de negocio (va en Domain/)
|
||||
- Definiciones de interfaces (van en Application/Contracts/)
|
||||
- Código específico de admin o public
|
||||
- Código sin contrato (sin interface)
|
||||
|
||||
## Servicios Comunes en Infrastructure
|
||||
|
||||
### Services/
|
||||
- `WordPressCacheService`: Caché usando WordPress Transients
|
||||
- `WordPressValidationService`: Validación con WordPress sanitization
|
||||
- `WordPressLoggerService`: Logging usando error_log o debug.log
|
||||
- `WordPressDatabaseService`: Interacciones directas con $wpdb
|
||||
|
||||
### Traits/
|
||||
- `WordPressMetaDataTrait`: Helpers para post meta
|
||||
- `WordPressTaxonomyTrait`: Helpers para términos y taxonomías
|
||||
- `WordPressHooksTrait`: Helpers para actions y filters
|
||||
- `WordPressSanitizationTrait`: Helpers para sanitización
|
||||
|
||||
## Patrón de Diseño
|
||||
|
||||
Seguimos el patrón **Adapter**:
|
||||
- WordPress es el "adaptee" (sistema externo)
|
||||
- Nuestros Services son "adapters"
|
||||
- Los Contracts son las interfaces que queremos
|
||||
|
||||
Esto permite cambiar WordPress por otro sistema en el futuro sin afectar el código de negocio.
|
||||
0
shared/Infrastructure/Services/.gitkeep
Normal file
0
shared/Infrastructure/Services/.gitkeep
Normal file
0
shared/Infrastructure/Traits/.gitkeep
Normal file
0
shared/Infrastructure/Traits/.gitkeep
Normal file
Reference in New Issue
Block a user