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>
170 lines
4.4 KiB
PHP
170 lines
4.4 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace ROITheme\Shared\Domain\ValueObjects;
|
|
|
|
use ROITheme\Shared\Domain\Exceptions\InvalidComponentException;
|
|
|
|
/**
|
|
* ComponentName - Value Object inmutable para nombre de componente
|
|
*
|
|
* RESPONSABILIDAD: Representar y validar el nombre de un componente del tema
|
|
*
|
|
* REGLAS DE NEGOCIO:
|
|
* - El nombre no puede estar vacío
|
|
* - El nombre debe tener entre 3 y 50 caracteres
|
|
* - El nombre solo puede contener letras minúsculas, números, guiones bajos y guiones
|
|
* - El nombre debe comenzar con una letra
|
|
*
|
|
* INVARIANTES:
|
|
* - Una vez creado, el nombre no puede cambiar (inmutable)
|
|
* - El nombre siempre está en formato normalizado (lowercase, sin espacios)
|
|
*
|
|
* USO:
|
|
* ```php
|
|
* $name = new ComponentName('top_bar');
|
|
* echo $name->value(); // "top_bar"
|
|
* echo $name->toString(); // "top_bar"
|
|
* ```
|
|
*
|
|
* @package ROITheme\Shared\Domain\ValueObjects
|
|
*/
|
|
final readonly class ComponentName
|
|
{
|
|
/**
|
|
* Longitud mínima del nombre
|
|
*/
|
|
private const MIN_LENGTH = 3;
|
|
|
|
/**
|
|
* Longitud máxima del nombre
|
|
*/
|
|
private const MAX_LENGTH = 50;
|
|
|
|
/**
|
|
* Patrón regex para validar formato del nombre
|
|
* - Debe comenzar con letra minúscula
|
|
* - Puede contener letras minúsculas, números, guiones bajos y guiones
|
|
*/
|
|
private const PATTERN = '/^[a-z][a-z0-9_-]*$/';
|
|
|
|
/**
|
|
* @param string $value Nombre del componente
|
|
* @throws InvalidComponentException Si el nombre no cumple las reglas de negocio
|
|
*/
|
|
public function __construct(private string $value)
|
|
{
|
|
$this->validate();
|
|
}
|
|
|
|
/**
|
|
* Obtener el valor del nombre
|
|
*
|
|
* @return string
|
|
*/
|
|
public function value(): string
|
|
{
|
|
return $this->value;
|
|
}
|
|
|
|
/**
|
|
* Convertir a string
|
|
*
|
|
* @return string
|
|
*/
|
|
public function toString(): string
|
|
{
|
|
return $this->value;
|
|
}
|
|
|
|
/**
|
|
* Comparar con otro ComponentName
|
|
*
|
|
* @param ComponentName $other
|
|
* @return bool
|
|
*/
|
|
public function equals(ComponentName $other): bool
|
|
{
|
|
return $this->value === $other->value;
|
|
}
|
|
|
|
/**
|
|
* Validar reglas de negocio del nombre
|
|
*
|
|
* @throws InvalidComponentException
|
|
* @return void
|
|
*/
|
|
private function validate(): void
|
|
{
|
|
// Regla 1: No puede estar vacío
|
|
if (empty($this->value)) {
|
|
throw new InvalidComponentException('Component name cannot be empty');
|
|
}
|
|
|
|
// Regla 2: Longitud entre MIN y MAX
|
|
$length = strlen($this->value);
|
|
if ($length < self::MIN_LENGTH || $length > self::MAX_LENGTH) {
|
|
throw new InvalidComponentException(
|
|
sprintf(
|
|
'Component name must be between %d and %d characters (got %d)',
|
|
self::MIN_LENGTH,
|
|
self::MAX_LENGTH,
|
|
$length
|
|
)
|
|
);
|
|
}
|
|
|
|
// Regla 3: Formato válido (lowercase, números, guiones bajos, comienza con letra)
|
|
if (!preg_match(self::PATTERN, $this->value)) {
|
|
throw new InvalidComponentException(
|
|
'Component name must start with a letter and contain only lowercase letters, numbers, underscores, and hyphens'
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Crear desde string (factory method)
|
|
*
|
|
* @param string $value
|
|
* @return self
|
|
*/
|
|
public static function fromString(string $value): self
|
|
{
|
|
return new self($value);
|
|
}
|
|
|
|
/**
|
|
* Normalizar string a formato de nombre válido
|
|
*
|
|
* Convierte:
|
|
* - "Top Bar" → "top_bar"
|
|
* - "FOOTER-CTA" → "footer_cta"
|
|
* - " sidebar " → "sidebar"
|
|
*
|
|
* @param string $value
|
|
* @return self
|
|
*/
|
|
public static function fromNormalized(string $value): self
|
|
{
|
|
// Trim espacios
|
|
$normalized = trim($value);
|
|
|
|
// Convertir a minúsculas
|
|
$normalized = strtolower($normalized);
|
|
|
|
// Reemplazar espacios y guiones por guiones bajos
|
|
$normalized = str_replace([' ', '-'], '_', $normalized);
|
|
|
|
// Eliminar caracteres no permitidos
|
|
$normalized = preg_replace('/[^a-z0-9_]/', '', $normalized);
|
|
|
|
// Eliminar guiones bajos duplicados
|
|
$normalized = preg_replace('/_+/', '_', $normalized);
|
|
|
|
// Eliminar guiones bajos al inicio/final
|
|
$normalized = trim($normalized, '_');
|
|
|
|
return new self($normalized);
|
|
}
|
|
}
|