Files
roi-theme/admin/includes/class-data-migrator.php
2025-11-13 21:51:06 -06:00

311 lines
6.7 KiB
PHP

<?php
/**
* Data Migrator Class
*
* Migración de datos de wp_options a tabla personalizada
*
* @package Apus_Theme
* @since 2.2.0
*/
if (!defined('ABSPATH')) {
exit;
}
class APUS_Data_Migrator {
/**
* Opción para trackear si la migración se completó
*/
const MIGRATION_FLAG = 'apus_data_migrated';
/**
* Opción antigua en wp_options
*/
const OLD_OPTION_NAME = 'apus_theme_settings';
/**
* DB Manager instance
*/
private $db_manager;
/**
* Constructor
*/
public function __construct() {
$this->db_manager = new APUS_DB_Manager();
}
/**
* Verificar si la migración ya se ejecutó
*/
public function is_migrated() {
return get_option(self::MIGRATION_FLAG) === '1';
}
/**
* Ejecutar migración si es necesaria
*/
public function maybe_migrate() {
if ($this->is_migrated()) {
return array(
'success' => true,
'message' => 'La migración ya fue ejecutada anteriormente'
);
}
if (!$this->db_manager->table_exists()) {
return array(
'success' => false,
'message' => 'La tabla de destino no existe'
);
}
return $this->migrate();
}
/**
* Ejecutar migración completa
*/
public function migrate() {
global $wpdb;
// Comenzar transacción
$wpdb->query('START TRANSACTION');
try {
// Obtener datos de wp_options
$old_data = get_option(self::OLD_OPTION_NAME);
if (empty($old_data)) {
throw new Exception('No hay datos para migrar en wp_options');
}
$total_migrated = 0;
// Verificar estructura de datos
if (!isset($old_data['components']) || !is_array($old_data['components'])) {
throw new Exception('Estructura de datos inválida');
}
// Obtener versión y timestamp
$version = isset($old_data['version']) ? $old_data['version'] : APUS_ADMIN_PANEL_VERSION;
// Migrar cada componente
foreach ($old_data['components'] as $component_name => $component_data) {
if (!is_array($component_data)) {
continue;
}
$migrated = $this->migrate_component($component_name, $component_data, $version);
$total_migrated += $migrated;
}
// Marcar migración como completada
update_option(self::MIGRATION_FLAG, '1', false);
// Commit transacción
$wpdb->query('COMMIT');
error_log("APUS Data Migrator: Migración completada. Total de registros: $total_migrated");
return array(
'success' => true,
'message' => 'Migración completada exitosamente',
'total_migrated' => $total_migrated
);
} catch (Exception $e) {
// Rollback en caso de error
$wpdb->query('ROLLBACK');
error_log("APUS Data Migrator: Error en migración - " . $e->getMessage());
return array(
'success' => false,
'message' => 'Error en migración: ' . $e->getMessage()
);
}
}
/**
* Migrar un componente específico
*
* @param string $component_name Nombre del componente
* @param array $component_data Datos del componente
* @param string $version Versión
* @return int Número de registros migrados
*/
private function migrate_component($component_name, $component_data, $version) {
$count = 0;
foreach ($component_data as $key => $value) {
// Determinar tipo de dato
$data_type = $this->determine_data_type($key, $value);
// Si es un array/objeto anidado (como custom_styles), guardarlo como JSON
if ($data_type === 'json') {
$result = $this->db_manager->save_config(
$component_name,
$key,
$value,
$data_type,
$version
);
} else {
$result = $this->db_manager->save_config(
$component_name,
$key,
$value,
$data_type,
$version
);
}
if ($result !== false) {
$count++;
}
}
return $count;
}
/**
* Determinar el tipo de dato
*
* @param string $key Clave de configuración
* @param mixed $value Valor
* @return string Tipo de dato (string, boolean, integer, json)
*/
private function determine_data_type($key, $value) {
if (is_bool($value)) {
return 'boolean';
}
if (is_int($value)) {
return 'integer';
}
if (is_array($value)) {
return 'json';
}
// Por nombre de clave
if (in_array($key, array('enabled', 'show_on_mobile', 'show_on_desktop', 'show_icon', 'show_link'))) {
return 'boolean';
}
return 'string';
}
/**
* Crear backup de datos antiguos
*
* @return bool Éxito de la operación
*/
public function backup_old_data() {
$old_data = get_option(self::OLD_OPTION_NAME);
if (empty($old_data)) {
return false;
}
$backup_option = self::OLD_OPTION_NAME . '_backup_' . time();
return update_option($backup_option, $old_data, false);
}
/**
* Restaurar desde backup (rollback)
*
* @param string $backup_option Nombre de la opción de backup
* @return bool Éxito de la operación
*/
public function rollback($backup_option) {
$backup_data = get_option($backup_option);
if (empty($backup_data)) {
return false;
}
// Restaurar datos antiguos
update_option(self::OLD_OPTION_NAME, $backup_data, false);
// Limpiar flag de migración
delete_option(self::MIGRATION_FLAG);
// Limpiar tabla personalizada
global $wpdb;
$table_name = $this->db_manager->get_table_name();
$wpdb->query("TRUNCATE TABLE $table_name");
return true;
}
/**
* Comparar datos entre wp_options y tabla personalizada
*
* @return array Resultado de la comparación
*/
public function verify_migration() {
$old_data = get_option(self::OLD_OPTION_NAME);
if (empty($old_data) || !isset($old_data['components'])) {
return array(
'success' => false,
'message' => 'No hay datos en wp_options para comparar'
);
}
$discrepancies = array();
foreach ($old_data['components'] as $component_name => $component_data) {
$new_data = $this->db_manager->get_config($component_name);
foreach ($component_data as $key => $old_value) {
$new_value = isset($new_data[$key]) ? $new_data[$key] : null;
// Comparar valores (teniendo en cuenta conversiones de tipo)
if ($this->normalize_value($old_value) !== $this->normalize_value($new_value)) {
$discrepancies[] = array(
'component' => $component_name,
'key' => $key,
'old_value' => $old_value,
'new_value' => $new_value
);
}
}
}
if (empty($discrepancies)) {
return array(
'success' => true,
'message' => 'Migración verificada: todos los datos coinciden'
);
}
return array(
'success' => false,
'message' => 'Se encontraron discrepancias en la migración',
'discrepancies' => $discrepancies
);
}
/**
* Normalizar valor para comparación
*
* @param mixed $value Valor a normalizar
* @return mixed Valor normalizado
*/
private function normalize_value($value) {
if (is_bool($value)) {
return $value ? 1 : 0;
}
if (is_array($value)) {
return json_encode($value);
}
return $value;
}
}