Files
roi-theme/Shared/Infrastructure/Services/CSSGeneratorService.php
FrankZamora 90863cd8f5 fix(structure): Correct case-sensitivity for Linux compatibility
Rename folders to match PHP PSR-4 autoloading conventions:
- schemas → Schemas
- shared → Shared
- Wordpress → WordPress (in all locations)

Fixes deployment issues on Linux servers where filesystem is case-sensitive.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-26 22:53:34 -06:00

181 lines
5.0 KiB
PHP

<?php
declare(strict_types=1);
namespace ROITheme\Shared\Infrastructure\Services;
use ROITheme\Shared\Domain\Contracts\CSSGeneratorInterface;
/**
* Class CSSGeneratorService
*
* Implementación concreta del generador de CSS.
* Convierte arrays de configuración de estilos en reglas CSS válidas y formateadas.
*
* Responsabilidades:
* - Generar string CSS a partir de selector y estilos
* - Convertir propiedades snake_case → kebab-case
* - Normalizar nombres de propiedades (text_color → color)
* - Formatear reglas CSS con indentación legible
* - Sanitizar valores para prevenir inyección
*
* @package ROITheme\Shared\Infrastructure\Services
*/
final class CSSGeneratorService implements CSSGeneratorInterface
{
/**
* Mapa de nombres de propiedades CSS normalizadas.
*
* @var array<string, string>
*/
private const PROPERTY_MAP = [
'text-color' => 'color',
'bg-color' => 'background-color',
];
/**
* {@inheritDoc}
*/
public function generate(string $selector, array $styles): string
{
if (empty($styles)) {
return '';
}
// Filtrar valores vacíos o null
$styles = $this->filterEmptyValues($styles);
if (empty($styles)) {
return '';
}
// Convertir array de estilos a propiedades CSS
$cssProperties = $this->buildCSSProperties($styles);
// Formatear regla CSS completa
return $this->formatCSSRule($selector, $cssProperties);
}
/**
* Filtra valores vacíos, null o que solo contienen espacios en blanco.
*
* @param array<string, mixed> $styles Array de estilos
* @return array<string, string> Array filtrado
*/
private function filterEmptyValues(array $styles): array
{
return array_filter(
$styles,
fn($value) => $value !== null && $value !== '' && trim((string)$value) !== ''
);
}
/**
* Convierte array de estilos a propiedades CSS formateadas.
*
* @param array<string, string> $styles Array de estilos
* @return array<int, string> Array de propiedades CSS formateadas
*/
private function buildCSSProperties(array $styles): array
{
$properties = [];
foreach ($styles as $property => $value) {
// Convertir snake_case a kebab-case
$cssProperty = $this->convertToKebabCase($property);
// Normalizar nombre de propiedad
$cssProperty = $this->normalizePropertyName($cssProperty);
// Sanitizar valor
$sanitizedValue = $this->sanitizeValue((string)$value);
// Agregar propiedad formateada
$properties[] = sprintf('%s: %s;', $cssProperty, $sanitizedValue);
}
return $properties;
}
/**
* Convierte snake_case a kebab-case.
*
* Ejemplos:
* - background_color → background-color
* - font_size → font-size
* - padding_top → padding-top
*
* @param string $property Nombre de propiedad en snake_case
* @return string Nombre de propiedad en kebab-case
*/
private function convertToKebabCase(string $property): string
{
return str_replace('_', '-', strtolower($property));
}
/**
* Normaliza nombres de propiedades CSS a su forma estándar.
*
* Mapea alias comunes a nombres de propiedades CSS estándar:
* - text-color → color
* - bg-color → background-color
*
* @param string $property Nombre de propiedad
* @return string Nombre de propiedad normalizado
*/
private function normalizePropertyName(string $property): string
{
return self::PROPERTY_MAP[$property] ?? $property;
}
/**
* Sanitiza valores CSS para prevenir inyección de código.
*
* Remueve tags HTML y caracteres potencialmente peligrosos,
* manteniendo valores CSS válidos como colores, unidades, etc.
*
* @param string $value Valor CSS sin sanitizar
* @return string Valor CSS sanitizado
*/
private function sanitizeValue(string $value): string
{
// Remover tags HTML
$value = strip_tags($value);
// Remover caracteres de control excepto espacios
$value = preg_replace('/[^\P{C}\s]/u', '', $value);
// Trim espacios
$value = trim($value);
return $value;
}
/**
* Formatea la regla CSS completa con selector y propiedades.
*
* Genera CSS con formato legible:
* ```css
* .selector {
* property: value;
* property2: value2;
* }
* ```
*
* @param string $selector Selector CSS
* @param array<int, string> $properties Array de propiedades formateadas
* @return string Regla CSS completa
*/
private function formatCSSRule(string $selector, array $properties): string
{
if (empty($properties)) {
return '';
}
return sprintf(
"%s {\n %s\n}",
$selector,
implode("\n ", $properties)
);
}
}