*/ 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 $styles Array de estilos * @return array 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 $styles Array de estilos * @return array 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 $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) ); } }