Nuevo sistema de gestión de CSS personalizado con panel admin: - Admin/CustomCSSManager: CRUD de snippets CSS (crítico/diferido) - Public/CustomCSSManager: Inyección dinámica en frontend - Schema JSON para configuración del componente Migración de CSS estático a BD: - Tablas APU (~14KB) → snippet diferido en BD - Tablas Genéricas (~10KB) → snippet diferido en BD - Comentadas funciones legacy en enqueue-scripts.php Limpieza de archivos obsoletos: - Eliminado build-bootstrap-subset.js - Eliminado migrate-legacy-options.php - Eliminado minify-css.php - Eliminado purgecss.config.js Beneficios: - CSS editable desde admin sin tocar código - Soporte crítico (head) y diferido (footer) - Filtrado por scope (all/home/single/archive) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
75 lines
2.0 KiB
PHP
75 lines
2.0 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace ROITheme\Admin\CustomCSSManager\Domain\ValueObjects;
|
|
|
|
use ROITheme\Shared\Domain\Exceptions\ValidationException;
|
|
|
|
/**
|
|
* Value Object para código CSS validado
|
|
*/
|
|
final class CSSCode
|
|
{
|
|
private const MAX_SIZE_CRITICAL = 14336; // 14KB para CSS crítico
|
|
private const MAX_SIZE_DEFERRED = 102400; // 100KB para CSS diferido
|
|
|
|
private function __construct(
|
|
private readonly string $value
|
|
) {}
|
|
|
|
public static function fromString(string $css): self
|
|
{
|
|
$sanitized = self::sanitize($css);
|
|
self::validate($sanitized);
|
|
return new self($sanitized);
|
|
}
|
|
|
|
private static function sanitize(string $css): string
|
|
{
|
|
// Eliminar etiquetas <style>
|
|
$css = preg_replace('/<\/?style[^>]*>/i', '', $css);
|
|
|
|
// Eliminar comentarios HTML
|
|
$css = preg_replace('/<!--.*?-->/s', '', $css);
|
|
|
|
return trim($css);
|
|
}
|
|
|
|
private static function validate(string $css): void
|
|
{
|
|
// Detectar código potencialmente peligroso
|
|
$dangerous = ['javascript:', 'expression(', '@import', 'behavior:'];
|
|
foreach ($dangerous as $pattern) {
|
|
if (stripos($css, $pattern) !== false) {
|
|
throw new ValidationException("CSS contiene patrón no permitido: {$pattern}");
|
|
}
|
|
}
|
|
}
|
|
|
|
public function validateForLoadType(LoadType $loadType): void
|
|
{
|
|
$maxSize = $loadType->isCritical()
|
|
? self::MAX_SIZE_CRITICAL
|
|
: self::MAX_SIZE_DEFERRED;
|
|
|
|
if (strlen($this->value) > $maxSize) {
|
|
throw new ValidationException(
|
|
sprintf('CSS excede el tamaño máximo de %d bytes para tipo %s',
|
|
$maxSize,
|
|
$loadType->value()
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
public function value(): string
|
|
{
|
|
return $this->value;
|
|
}
|
|
|
|
public function isEmpty(): bool
|
|
{
|
|
return empty($this->value);
|
|
}
|
|
}
|