Files
roi-theme/Admin/CustomCSSManager/Domain/ValueObjects/SnippetId.php
FrankZamora 1e6a076904 chore: purgar archivos no utilizados (plan 101 fase 1)
- eliminar carpetas vacias admin/herosection y bootstrapicons
- eliminar 7 scripts legacy con credenciales hardcodeadas
- eliminar formbuilder duplicado en shared/infrastructure/ui
- eliminar 11 archivos .gitkeep en carpetas con contenido

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 18:09:52 -06:00

125 lines
3.3 KiB
PHP

<?php
declare(strict_types=1);
namespace ROITheme\Admin\CustomCSSManager\Domain\ValueObjects;
use ROITheme\Shared\Domain\Exceptions\ValidationException;
/**
* Value Object para ID único de snippet CSS
*
* Soporta tres formatos:
* 1. Generado: css_[timestamp]_[random] (ej: "css_1701432000_a1b2c3")
* 2. Legacy con prefijo: css_[descriptive]_[number] (ej: "css_tablas_apu_1764624826")
* 3. Legacy kebab-case: (ej: "cls-tables-apu", "generic-tables")
*
* Esto permite migrar snippets existentes sin romper IDs.
*/
final class SnippetId
{
private const PREFIX = 'css_';
private const PATTERN_GENERATED = '/^css_[0-9]+_[a-z0-9]{6}$/';
private const PATTERN_LEGACY_PREFIX = '/^css_[a-z0-9_]+$/';
private const PATTERN_LEGACY = '/^[a-z0-9]+(-[a-z0-9]+)*$/';
private function __construct(
private readonly string $value
) {}
/**
* Crea SnippetId desde string existente (desde BD)
*
* Acepta tanto IDs generados (css_*) como IDs legacy (kebab-case).
*
* @param string $id ID existente
* @return self
* @throws ValidationException Si el formato es inválido
*/
public static function fromString(string $id): self
{
$id = trim($id);
if (empty($id)) {
throw new ValidationException('El ID del snippet no puede estar vacío');
}
if (strlen($id) > 50) {
throw new ValidationException('El ID del snippet no puede exceder 50 caracteres');
}
// Validar formato generado (css_*)
if (str_starts_with($id, self::PREFIX)) {
// Acepta formato nuevo (css_timestamp_random) o legacy (css_descriptivo_numero)
if (!preg_match(self::PATTERN_GENERATED, $id) && !preg_match(self::PATTERN_LEGACY_PREFIX, $id)) {
throw new ValidationException(
sprintf('Formato de ID generado inválido: %s. Esperado: css_[timestamp]_[random]', $id)
);
}
return new self($id);
}
// Validar formato legacy (kebab-case)
if (!preg_match(self::PATTERN_LEGACY, $id)) {
throw new ValidationException(
sprintf('Formato de ID inválido: %s. Use kebab-case (ej: cls-tables-apu)', $id)
);
}
return new self($id);
}
/**
* Genera un nuevo SnippetId único
*
* @return self
*/
public static function generate(): self
{
$timestamp = time();
$random = bin2hex(random_bytes(3));
return new self(self::PREFIX . $timestamp . '_' . $random);
}
/**
* Verifica si es un ID generado (vs legacy)
*
* @return bool
*/
public function isGenerated(): bool
{
return str_starts_with($this->value, self::PREFIX);
}
/**
* Obtiene el valor del ID
*
* @return string
*/
public function value(): string
{
return $this->value;
}
/**
* Compara igualdad con otro SnippetId
*
* @param SnippetId $other
* @return bool
*/
public function equals(SnippetId $other): bool
{
return $this->value === $other->value;
}
/**
* Representación string
*
* @return string
*/
public function __toString(): string
{
return $this->value;
}
}