COMPLETADO: Fase 1 de la migración a Clean Architecture + POO ## Estructura de Carpetas - ✓ Estructura completa de 4 capas (Domain, Application, Infrastructure, Presentation) - ✓ Carpetas de Use Cases (SaveComponent, GetComponent, DeleteComponent, SyncSchema) - ✓ Estructura de tests (Unit, Integration, E2E) - ✓ Carpetas de schemas y templates ## Composer y Autoloading - ✓ PSR-4 autoloading configurado para ROITheme namespace - ✓ Autoloader optimizado regenerado ## DI Container - ✓ DIContainer implementado con patrón Singleton - ✓ Métodos set(), get(), has() para gestión de servicios - ✓ Getters específicos para ComponentRepository, ValidationService, CacheService - ✓ Placeholders que serán implementados en Fase 5 - ✓ Prevención de clonación y deserialización ## Interfaces - ✓ ComponentRepositoryInterface (Domain) - ✓ ValidationServiceInterface (Application) - ✓ CacheServiceInterface (Application) - ✓ Component entity placeholder (Domain) ## Bootstrap - ✓ functions.php actualizado con carga de Composer autoloader - ✓ Inicialización del DIContainer - ✓ Helper function roi_container() disponible globalmente ## Tests - ✓ 10 tests unitarios para DIContainer (100% cobertura) - ✓ Total: 13 tests unitarios, 28 assertions - ✓ Suite de tests pasando correctamente ## Validación - ✓ Script de validación automatizado (48/48 checks pasados) - ✓ 100% de validaciones exitosas La arquitectura base está lista para la Fase 2. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
290 lines
8.3 KiB
PHP
290 lines
8.3 KiB
PHP
<?php
|
|
/**
|
|
* Database Manager Class
|
|
*
|
|
* Gestión de tablas personalizadas del tema
|
|
*
|
|
* @package ROI_Theme
|
|
* @since 2.2.0
|
|
*/
|
|
|
|
if (!defined('ABSPATH')) {
|
|
exit;
|
|
}
|
|
|
|
class ROI_DB_Manager {
|
|
|
|
/**
|
|
* Nombre de la tabla de componentes (sin prefijo)
|
|
*/
|
|
const TABLE_COMPONENTS = 'roi_theme_components';
|
|
|
|
/**
|
|
* Nombre de la tabla de defaults (sin prefijo)
|
|
*/
|
|
const TABLE_DEFAULTS = 'roi_theme_components_defaults';
|
|
|
|
/**
|
|
* Versión de la base de datos
|
|
*/
|
|
const DB_VERSION = '1.0';
|
|
|
|
/**
|
|
* Opción para almacenar la versión de la DB
|
|
*/
|
|
const DB_VERSION_OPTION = 'roi_db_version';
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
public function __construct() {
|
|
// Hook para verificar/actualizar DB en cada carga
|
|
add_action('admin_init', array($this, 'maybe_create_tables'));
|
|
}
|
|
|
|
/**
|
|
* Obtener nombre completo de tabla con prefijo
|
|
*
|
|
* @param string $table_type Tipo de tabla: 'components' (personalizaciones) o 'defaults' (valores por defecto)
|
|
* @return string Nombre completo de la tabla con prefijo
|
|
*/
|
|
public function get_table_name($table_type = 'components') {
|
|
global $wpdb;
|
|
|
|
if ($table_type === 'defaults') {
|
|
return $wpdb->prefix . self::TABLE_DEFAULTS;
|
|
}
|
|
|
|
return $wpdb->prefix . self::TABLE_COMPONENTS;
|
|
}
|
|
|
|
/**
|
|
* Verificar si las tablas necesitan ser creadas o actualizadas
|
|
*/
|
|
public function maybe_create_tables() {
|
|
$installed_version = get_option(self::DB_VERSION_OPTION);
|
|
|
|
if ($installed_version !== self::DB_VERSION) {
|
|
$this->create_tables();
|
|
update_option(self::DB_VERSION_OPTION, self::DB_VERSION);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Crear tablas personalizadas
|
|
* Crea tanto la tabla de componentes (personalizaciones) como la de defaults
|
|
*/
|
|
public function create_tables() {
|
|
global $wpdb;
|
|
|
|
$charset_collate = $wpdb->get_charset_collate();
|
|
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
|
|
|
|
$success = true;
|
|
|
|
// Estructura común para ambas tablas
|
|
$table_structure = "(
|
|
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
|
|
component_name VARCHAR(50) NOT NULL,
|
|
config_key VARCHAR(100) NOT NULL,
|
|
config_value TEXT NOT NULL,
|
|
data_type ENUM('string', 'boolean', 'integer', 'json') DEFAULT 'string',
|
|
version VARCHAR(10) DEFAULT NULL,
|
|
updated_at DATETIME NOT NULL,
|
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
PRIMARY KEY (id),
|
|
UNIQUE KEY component_config (component_name, config_key),
|
|
INDEX idx_component (component_name),
|
|
INDEX idx_updated (updated_at)
|
|
) $charset_collate;";
|
|
|
|
// Crear tabla de componentes (personalizaciones del usuario)
|
|
$table_components = $this->get_table_name('components');
|
|
$sql_components = "CREATE TABLE $table_components $table_structure";
|
|
dbDelta($sql_components);
|
|
|
|
if ($wpdb->get_var("SHOW TABLES LIKE '$table_components'") === $table_components) {
|
|
error_log("ROI DB Manager: Tabla $table_components creada/actualizada exitosamente");
|
|
} else {
|
|
error_log("ROI DB Manager: Error al crear tabla $table_components");
|
|
$success = false;
|
|
}
|
|
|
|
// Crear tabla de defaults (valores por defecto del tema)
|
|
$table_defaults = $this->get_table_name('defaults');
|
|
$sql_defaults = "CREATE TABLE $table_defaults $table_structure";
|
|
dbDelta($sql_defaults);
|
|
|
|
if ($wpdb->get_var("SHOW TABLES LIKE '$table_defaults'") === $table_defaults) {
|
|
error_log("ROI DB Manager: Tabla $table_defaults creada/actualizada exitosamente");
|
|
} else {
|
|
error_log("ROI DB Manager: Error al crear tabla $table_defaults");
|
|
$success = false;
|
|
}
|
|
|
|
return $success;
|
|
}
|
|
|
|
/**
|
|
* Verificar si una tabla existe
|
|
*
|
|
* @param string $table_type Tipo de tabla: 'components' o 'defaults'
|
|
* @return bool True si la tabla existe
|
|
*/
|
|
public function table_exists($table_type = 'components') {
|
|
global $wpdb;
|
|
$table_name = $this->get_table_name($table_type);
|
|
return $wpdb->get_var("SHOW TABLES LIKE '$table_name'") === $table_name;
|
|
}
|
|
|
|
/**
|
|
* Guardar configuración de un componente
|
|
*
|
|
* @param string $component_name Nombre del componente
|
|
* @param string $config_key Clave de configuración
|
|
* @param mixed $config_value Valor de configuración
|
|
* @param string $data_type Tipo de dato (string, boolean, integer, json)
|
|
* @param string $version Versión del tema
|
|
* @param string $table_type Tipo de tabla: 'components' (personalizaciones) o 'defaults' (valores por defecto)
|
|
* @return bool|int ID del registro o false en caso de error
|
|
*/
|
|
public function save_config($component_name, $config_key, $config_value, $data_type = 'string', $version = null, $table_type = 'components') {
|
|
global $wpdb;
|
|
$table_name = $this->get_table_name($table_type);
|
|
|
|
// Convertir valor según tipo
|
|
if ($data_type === 'json' && is_array($config_value)) {
|
|
$config_value = json_encode($config_value, JSON_UNESCAPED_UNICODE);
|
|
} elseif ($data_type === 'boolean') {
|
|
$config_value = $config_value ? '1' : '0';
|
|
}
|
|
|
|
// Usar ON DUPLICATE KEY UPDATE para INSERT o UPDATE
|
|
$result = $wpdb->query($wpdb->prepare(
|
|
"INSERT INTO $table_name (component_name, config_key, config_value, data_type, version, updated_at)
|
|
VALUES (%s, %s, %s, %s, %s, %s)
|
|
ON DUPLICATE KEY UPDATE
|
|
config_value = VALUES(config_value),
|
|
data_type = VALUES(data_type),
|
|
version = VALUES(version),
|
|
updated_at = VALUES(updated_at)",
|
|
$component_name,
|
|
$config_key,
|
|
$config_value,
|
|
$data_type,
|
|
$version,
|
|
current_time('mysql')
|
|
));
|
|
|
|
return $result !== false ? $wpdb->insert_id : false;
|
|
}
|
|
|
|
/**
|
|
* Obtener configuración de un componente
|
|
*
|
|
* @param string $component_name Nombre del componente
|
|
* @param string $config_key Clave específica (opcional)
|
|
* @param string $table_type Tipo de tabla: 'components' (personalizaciones) o 'defaults' (valores por defecto)
|
|
* @return array|mixed Configuración completa o valor específico
|
|
*/
|
|
public function get_config($component_name, $config_key = null, $table_type = 'components') {
|
|
global $wpdb;
|
|
$table_name = $this->get_table_name($table_type);
|
|
|
|
if ($config_key !== null) {
|
|
// Obtener un valor específico
|
|
$row = $wpdb->get_row($wpdb->prepare(
|
|
"SELECT config_value, data_type FROM $table_name
|
|
WHERE component_name = %s AND config_key = %s",
|
|
$component_name,
|
|
$config_key
|
|
));
|
|
|
|
if ($row) {
|
|
return $this->parse_value($row->config_value, $row->data_type);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
// Obtener toda la configuración del componente
|
|
$rows = $wpdb->get_results($wpdb->prepare(
|
|
"SELECT config_key, config_value, data_type FROM $table_name
|
|
WHERE component_name = %s",
|
|
$component_name
|
|
));
|
|
|
|
$config = array();
|
|
foreach ($rows as $row) {
|
|
$config[$row->config_key] = $this->parse_value($row->config_value, $row->data_type);
|
|
}
|
|
|
|
return $config;
|
|
}
|
|
|
|
/**
|
|
* Parsear valor según tipo de dato
|
|
*
|
|
* @param string $value Valor almacenado
|
|
* @param string $data_type Tipo de dato
|
|
* @return mixed Valor parseado
|
|
*/
|
|
private function parse_value($value, $data_type) {
|
|
switch ($data_type) {
|
|
case 'boolean':
|
|
return (bool) $value;
|
|
case 'integer':
|
|
return (int) $value;
|
|
case 'json':
|
|
return json_decode($value, true);
|
|
default:
|
|
return $value;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Eliminar configuraciones de un componente
|
|
*
|
|
* @param string $component_name Nombre del componente
|
|
* @param string $config_key Clave específica (opcional)
|
|
* @param string $table_type Tipo de tabla: 'components' (personalizaciones) o 'defaults' (valores por defecto)
|
|
* @return bool Éxito de la operación
|
|
*/
|
|
public function delete_config($component_name, $config_key = null, $table_type = 'components') {
|
|
global $wpdb;
|
|
$table_name = $this->get_table_name($table_type);
|
|
|
|
if ($config_key !== null) {
|
|
return $wpdb->delete(
|
|
$table_name,
|
|
array(
|
|
'component_name' => $component_name,
|
|
'config_key' => $config_key
|
|
),
|
|
array('%s', '%s')
|
|
) !== false;
|
|
}
|
|
|
|
// Eliminar todas las configuraciones del componente
|
|
return $wpdb->delete(
|
|
$table_name,
|
|
array('component_name' => $component_name),
|
|
array('%s')
|
|
) !== false;
|
|
}
|
|
|
|
/**
|
|
* Listar todos los componentes con configuraciones
|
|
*
|
|
* @param string $table_type Tipo de tabla: 'components' (personalizaciones) o 'defaults' (valores por defecto)
|
|
* @return array Lista de nombres de componentes
|
|
*/
|
|
public function list_components($table_type = 'components') {
|
|
global $wpdb;
|
|
$table_name = $this->get_table_name($table_type);
|
|
|
|
return $wpdb->get_col(
|
|
"SELECT DISTINCT component_name FROM $table_name ORDER BY component_name"
|
|
);
|
|
}
|
|
}
|