Migración completa a Clean Architecture con componentes funcionales
- 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>
This commit is contained in:
@@ -0,0 +1,208 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace ROITheme\Shared\Infrastructure\Persistence\WordPress;
|
||||
|
||||
use ROITheme\Shared\Domain\Contracts\ComponentSettingsRepositoryInterface;
|
||||
|
||||
/**
|
||||
* Implementaci<63>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<65>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<73>
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user