Files
roi-theme/Shared/Domain/Entities/Component.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

336 lines
8.7 KiB
PHP

<?php
declare(strict_types=1);
namespace ROITheme\Shared\Domain\Entities;
use ROITheme\Shared\Domain\ValueObjects\ComponentName;
use ROITheme\Shared\Domain\ValueObjects\ComponentConfiguration;
use ROITheme\Shared\Domain\ValueObjects\ComponentVisibility;
use ROITheme\Shared\Domain\Exceptions\InvalidComponentException;
/**
* Component - Entidad del Dominio
*
* RESPONSABILIDAD: Representar un componente del tema con toda su lógica de negocio
*
* INVARIANTES (Reglas que SIEMPRE deben cumplirse):
* 1. Un componente siempre tiene un nombre válido
* 2. Un componente siempre tiene configuración (puede estar vacía)
* 3. Si tiene CTA URL debe tener CTA text (validado en ComponentConfiguration)
* 4. Los colores siempre están en formato hexadecimal válido
* 5. El timestamp de updated_at es siempre >= created_at
*
* ENTIDAD vs VALUE OBJECT:
* - Component es ENTIDAD porque tiene identidad (puede cambiar configuración pero sigue siendo el mismo componente)
* - ComponentName es VALUE OBJECT (dos nombres iguales son indistinguibles)
* - ComponentConfiguration es VALUE OBJECT (inmutable)
*
* USO:
* ```php
* $component = new Component(
* ComponentName::fromString('top_bar'),
* ComponentConfiguration::fromFlat([
* 'enabled' => true,
* 'message_text' => 'Welcome!'
* ]),
* ComponentVisibility::allDevices()
* );
*
* // Actualizar configuración (inmutabilidad)
* $updated = $component->updateConfiguration(
* $component->configuration()->withValue('content', 'message_text', 'Hello!')
* );
* ```
*
* @package ROITheme\Shared\Domain\Entities
*/
final class Component
{
/**
* @var ComponentName Nombre del componente (inmutable)
*/
private ComponentName $name;
/**
* @var ComponentConfiguration Configuración del componente
*/
private ComponentConfiguration $configuration;
/**
* @var ComponentVisibility Visibilidad del componente
*/
private ComponentVisibility $visibility;
/**
* @var bool Componente habilitado
*/
private bool $isEnabled;
/**
* @var string Versión del schema
*/
private string $schemaVersion;
/**
* @var \DateTimeImmutable Fecha de creación
*/
private \DateTimeImmutable $createdAt;
/**
* @var \DateTimeImmutable Fecha de última actualización
*/
private \DateTimeImmutable $updatedAt;
/**
* Constructor
*
* @param ComponentName $name
* @param ComponentConfiguration $configuration
* @param ComponentVisibility $visibility
* @param bool $isEnabled
* @param string $schemaVersion
* @param \DateTimeImmutable|null $createdAt
* @param \DateTimeImmutable|null $updatedAt
* @throws InvalidComponentException Si se violan invariantes
*/
public function __construct(
ComponentName $name,
ComponentConfiguration $configuration,
ComponentVisibility $visibility,
bool $isEnabled = true,
string $schemaVersion = '1.0.0',
?\DateTimeImmutable $createdAt = null,
?\DateTimeImmutable $updatedAt = null
) {
$this->name = $name;
$this->configuration = $configuration;
$this->visibility = $visibility;
$this->isEnabled = $isEnabled;
$this->schemaVersion = $schemaVersion;
$this->createdAt = $createdAt ?? new \DateTimeImmutable();
$this->updatedAt = $updatedAt ?? new \DateTimeImmutable();
$this->validateInvariants();
}
/**
* Obtener nombre del componente
*
* @return ComponentName
*/
public function name(): ComponentName
{
return $this->name;
}
/**
* Obtener configuración del componente
*
* @return ComponentConfiguration
*/
public function configuration(): ComponentConfiguration
{
return $this->configuration;
}
/**
* Obtener visibilidad del componente
*
* @return ComponentVisibility
*/
public function visibility(): ComponentVisibility
{
return $this->visibility;
}
/**
* Verificar si el componente está habilitado
*
* @return bool
*/
public function isEnabled(): bool
{
return $this->isEnabled;
}
/**
* Obtener versión del schema
*
* @return string
*/
public function schemaVersion(): string
{
return $this->schemaVersion;
}
/**
* Obtener fecha de creación
*
* @return \DateTimeImmutable
*/
public function createdAt(): \DateTimeImmutable
{
return $this->createdAt;
}
/**
* Obtener fecha de última actualización
*
* @return \DateTimeImmutable
*/
public function updatedAt(): \DateTimeImmutable
{
return $this->updatedAt;
}
/**
* Crear nuevo componente con configuración actualizada
* (Inmutabilidad: retorna nueva instancia)
*
* @param ComponentConfiguration $configuration Nueva configuración
* @return self Nueva instancia
*/
public function updateConfiguration(ComponentConfiguration $configuration): self
{
return new self(
$this->name,
$configuration,
$this->visibility,
$this->isEnabled,
$this->schemaVersion,
$this->createdAt,
new \DateTimeImmutable()
);
}
/**
* Crear nuevo componente con visibilidad actualizada
* (Inmutabilidad: retorna nueva instancia)
*
* @param ComponentVisibility $visibility Nueva visibilidad
* @return self Nueva instancia
*/
public function updateVisibility(ComponentVisibility $visibility): self
{
return new self(
$this->name,
$this->configuration,
$visibility,
$this->isEnabled,
$this->schemaVersion,
$this->createdAt,
new \DateTimeImmutable()
);
}
/**
* Crear nuevo componente habilitado
* (Inmutabilidad: retorna nueva instancia)
*
* @return self Nueva instancia con isEnabled=true
*/
public function enable(): self
{
return new self(
$this->name,
$this->configuration,
$this->visibility,
true,
$this->schemaVersion,
$this->createdAt,
new \DateTimeImmutable()
);
}
/**
* Crear nuevo componente deshabilitado
* (Inmutabilidad: retorna nueva instancia)
*
* @return self Nueva instancia con isEnabled=false
*/
public function disable(): self
{
return new self(
$this->name,
$this->configuration,
$this->visibility,
false,
$this->schemaVersion,
$this->createdAt,
new \DateTimeImmutable()
);
}
/**
* Comparar con otro componente
* (Dos componentes son iguales si tienen el mismo nombre)
*
* @param Component $other Otro componente
* @return bool True si son el mismo componente
*/
public function equals(Component $other): bool
{
return $this->name->equals($other->name);
}
/**
* Obtener datos del componente para renderizado
* Retorna la configuración completa en formato array
*
* @return array
*/
public function getData(): array
{
return $this->configuration->all();
}
/**
* Convertir a array para serialización
*
* @return array
*/
public function toArray(): array
{
return [
'name' => $this->name->value(),
'configuration' => $this->configuration->all(),
'visibility' => $this->visibility->toArray(),
'is_enabled' => $this->isEnabled,
'schema_version' => $this->schemaVersion,
'created_at' => $this->createdAt->format('Y-m-d H:i:s'),
'updated_at' => $this->updatedAt->format('Y-m-d H:i:s')
];
}
/**
* Convertir a string para debugging
*
* @return string
*/
public function __toString(): string
{
return sprintf(
'Component(%s, enabled=%s, schema=%s)',
$this->name->value(),
$this->isEnabled ? 'true' : 'false',
$this->schemaVersion
);
}
/**
* Validar invariantes del componente
*
* @throws InvalidComponentException Si se viola algún invariante
* @return void
*/
private function validateInvariants(): void
{
// Invariante: updated_at >= created_at
if ($this->updatedAt < $this->createdAt) {
throw new InvalidComponentException(
'Updated timestamp cannot be before created timestamp'
);
}
}
}