- Reorganización de estructura: Admin/, Public/, Shared/, Schemas/ - 12 componentes migrados: TopNotificationBar, Navbar, CtaLetsTalk, Hero, FeaturedImage, TableOfContents, CtaBoxSidebar, SocialShare, CtaPost, RelatedPost, ContactForm, Footer - Panel de administración con tabs Bootstrap 5 funcionales - Schemas JSON para configuración de componentes - Renderers dinámicos con CSSGeneratorService (cero CSS hardcodeado) - FormBuilders para UI admin con Design System consistente - Fix: Bootstrap JS cargado en header para tabs funcionales - Fix: buildTextInput maneja valores mixed (bool/string) - Eliminación de estructura legacy (src/, admin/, assets/css/componente-*) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
209 lines
5.3 KiB
PHP
209 lines
5.3 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace ROITheme\Shared\Infrastructure\Persistence\WordPress;
|
|
|
|
use ROITheme\Shared\Domain\Contracts\ComponentSettingsRepositoryInterface;
|
|
|
|
/**
|
|
* Implementación de repositorio de configuraciones usando WordPress/MySQL
|
|
*
|
|
* Infrastructure Layer - WordPress specific
|
|
* Trabaja con la tabla wp_roi_theme_component_settings
|
|
*
|
|
* @package ROITheme\Shared\Infrastructure\Persistence\WordPress
|
|
*/
|
|
final class WordPressComponentSettingsRepository implements ComponentSettingsRepositoryInterface
|
|
{
|
|
private string $tableName;
|
|
|
|
public function __construct(
|
|
private \wpdb $wpdb
|
|
) {
|
|
$this->tableName = $this->wpdb->prefix . 'roi_theme_component_settings';
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
public function getComponentSettings(string $componentName): array
|
|
{
|
|
$sql = $this->wpdb->prepare(
|
|
"SELECT group_name, attribute_name, attribute_value
|
|
FROM {$this->tableName}
|
|
WHERE component_name = %s
|
|
ORDER BY group_name, attribute_name",
|
|
$componentName
|
|
);
|
|
|
|
$rows = $this->wpdb->get_results($sql, ARRAY_A);
|
|
|
|
if (empty($rows)) {
|
|
return [];
|
|
}
|
|
|
|
// Agrupar por grupo
|
|
$settings = [];
|
|
foreach ($rows as $row) {
|
|
$groupName = $row['group_name'];
|
|
$attributeName = $row['attribute_name'];
|
|
$value = $row['attribute_value'];
|
|
|
|
// Convertir valores según tipo
|
|
$value = $this->unserializeValue($value);
|
|
|
|
if (!isset($settings[$groupName])) {
|
|
$settings[$groupName] = [];
|
|
}
|
|
|
|
$settings[$groupName][$attributeName] = $value;
|
|
}
|
|
|
|
return $settings;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
public function saveComponentSettings(string $componentName, array $settings): int
|
|
{
|
|
$updated = 0;
|
|
|
|
foreach ($settings as $groupName => $attributes) {
|
|
foreach ($attributes as $attributeName => $value) {
|
|
if ($this->saveFieldValue($componentName, $groupName, $attributeName, $value)) {
|
|
$updated++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $updated;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
public function getFieldValue(string $componentName, string $groupName, string $attributeName): mixed
|
|
{
|
|
$sql = $this->wpdb->prepare(
|
|
"SELECT attribute_value
|
|
FROM {$this->tableName}
|
|
WHERE component_name = %s
|
|
AND group_name = %s
|
|
AND attribute_name = %s
|
|
LIMIT 1",
|
|
$componentName,
|
|
$groupName,
|
|
$attributeName
|
|
);
|
|
|
|
$value = $this->wpdb->get_var($sql);
|
|
|
|
if ($value === null) {
|
|
return null;
|
|
}
|
|
|
|
return $this->unserializeValue($value);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
public function saveFieldValue(string $componentName, string $groupName, string $attributeName, mixed $value): bool
|
|
{
|
|
// Serializar valor
|
|
$serializedValue = $this->serializeValue($value);
|
|
|
|
// Intentar actualizar
|
|
$result = $this->wpdb->update(
|
|
$this->tableName,
|
|
['attribute_value' => $serializedValue],
|
|
[
|
|
'component_name' => $componentName,
|
|
'group_name' => $groupName,
|
|
'attribute_name' => $attributeName
|
|
],
|
|
['%s'],
|
|
['%s', '%s', '%s']
|
|
);
|
|
|
|
return $result !== false;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
public function resetToDefaults(string $componentName, string $schemaPath): int
|
|
{
|
|
if (!file_exists($schemaPath)) {
|
|
return 0;
|
|
}
|
|
|
|
$schema = json_decode(file_get_contents($schemaPath), true);
|
|
|
|
if (!$schema || !isset($schema['groups'])) {
|
|
return 0;
|
|
}
|
|
|
|
$updated = 0;
|
|
|
|
// Iterar grupos y campos del schema
|
|
foreach ($schema['groups'] as $groupName => $group) {
|
|
foreach ($group['fields'] as $fieldName => $field) {
|
|
$defaultValue = $field['default'] ?? '';
|
|
|
|
if ($this->saveFieldValue($componentName, $groupName, $fieldName, $defaultValue)) {
|
|
$updated++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $updated;
|
|
}
|
|
|
|
/**
|
|
* Serializa un valor para guardarlo en la BD
|
|
*
|
|
* @param mixed $value
|
|
* @return string
|
|
*/
|
|
private function serializeValue(mixed $value): string
|
|
{
|
|
if (is_bool($value)) {
|
|
return $value ? '1' : '0';
|
|
}
|
|
|
|
if (is_array($value)) {
|
|
return json_encode($value);
|
|
}
|
|
|
|
return (string) $value;
|
|
}
|
|
|
|
/**
|
|
* Deserializa un valor desde la BD
|
|
*
|
|
* @param string $value
|
|
* @return mixed
|
|
*/
|
|
private function unserializeValue(string $value): mixed
|
|
{
|
|
// Intentar decodificar JSON
|
|
if (str_starts_with($value, '{') || str_starts_with($value, '[')) {
|
|
$decoded = json_decode($value, true);
|
|
if (json_last_error() === JSON_ERROR_NONE) {
|
|
return $decoded;
|
|
}
|
|
}
|
|
|
|
// Convertir booleanos
|
|
if ($value === '1' || $value === '0') {
|
|
return $value === '1';
|
|
}
|
|
|
|
// Devolver como está
|
|
return $value;
|
|
}
|
|
}
|