validate(); } /** * Obtener mensaje de texto * * @return string */ public function messageText(): string { return $this->messageText; } /** * Obtener texto del CTA * * @return string|null */ public function ctaText(): ?string { return $this->ctaText; } /** * Obtener URL del CTA * * @return string|null */ public function ctaUrl(): ?string { return $this->ctaUrl; } /** * Obtener título * * @return string|null */ public function title(): ?string { return $this->title; } /** * Verificar si tiene mensaje de texto * * @return bool */ public function hasMessage(): bool { return !empty($this->messageText); } /** * Verificar si tiene CTA * * @return bool */ public function hasCTA(): bool { return !empty($this->ctaText) && !empty($this->ctaUrl); } /** * Verificar si tiene título * * @return bool */ public function hasTitle(): bool { return !empty($this->title); } /** * Verificar si está completamente vacío * * @return bool */ public function isEmpty(): bool { return empty($this->messageText) && empty($this->ctaText) && empty($this->ctaUrl) && empty($this->title); } /** * Convertir a array * * @return array */ public function toArray(): array { return array_filter([ 'message_text' => $this->messageText, 'cta_text' => $this->ctaText, 'cta_url' => $this->ctaUrl, 'title' => $this->title ], fn($value) => $value !== null && $value !== ''); } /** * Validar reglas de negocio * * @throws InvalidComponentException * @return void */ private function validate(): void { // Regla 1: Si existe CTA URL debe existir CTA text if (!empty($this->ctaUrl) && empty($this->ctaText)) { throw new InvalidComponentException('CTA URL requires CTA text'); } // Regla 2: Si existe CTA text debe existir CTA URL if (!empty($this->ctaText) && empty($this->ctaUrl)) { throw new InvalidComponentException('CTA text requires CTA URL'); } // Regla 3: CTA URL debe ser URL válida if (!empty($this->ctaUrl) && !$this->isValidUrl($this->ctaUrl)) { throw new InvalidComponentException( sprintf('Invalid CTA URL format: %s', $this->ctaUrl) ); } } /** * Validar si una string es URL válida * * @param string $url * @return bool */ private function isValidUrl(string $url): bool { // Debe comenzar con http:// o https:// if (!preg_match('/^https?:\/\//i', $url)) { return false; } // Usar filter_var para validación completa return filter_var($url, FILTER_VALIDATE_URL) !== false; } /** * Factory: Contenido vacío * * @return self */ public static function empty(): self { return new self(); } /** * Factory: Solo mensaje * * @param string $message * @return self */ public static function messageOnly(string $message): self { return new self(messageText: $message); } /** * Factory: Mensaje con CTA * * @param string $message * @param string $ctaText * @param string $ctaUrl * @return self */ public static function withCTA(string $message, string $ctaText, string $ctaUrl): self { return new self( messageText: $message, ctaText: $ctaText, ctaUrl: $ctaUrl ); } /** * Crear desde array * * @param array $data * @return self */ public static function fromArray(array $data): self { return new self( messageText: $data['message_text'] ?? '', ctaText: $data['cta_text'] ?? null, ctaUrl: $data['cta_url'] ?? null, title: $data['title'] ?? null ); } /** * Comparar con otro ComponentContent * * @param ComponentContent $other * @return bool */ public function equals(ComponentContent $other): bool { return $this->messageText === $other->messageText && $this->ctaText === $other->ctaText && $this->ctaUrl === $other->ctaUrl && $this->title === $other->title; } }