* SPDX-License-Identifier: AGPL-3.0-or-later */ namespace KTXF\Mail\Object; use DateTimeImmutable; use DateTimeInterface; /** * Abstract Message Properties Mutable Class * * Provides common implementation for mutable message properties * * @since 2025.05.01 */ abstract class MessagePropertiesMutableAbstract extends MessagePropertiesBaseAbstract implements MessagePropertiesMutableInterface { protected string $type = 'mail.message'; /** * @param array $values * * @return array> */ protected function normalizeAddresses(array $values): array { return array_map( static fn(AddressInterface $value): array => $value->toArray(), $values, ); } protected function normalizeDate(?DateTimeImmutable $value): ?string { return $value?->format(DATE_ATOM); } /** * @param array $values * * @return array> */ protected function normalizeParts(array $values): array { return array_map( static fn(MessagePartInterface $value): array => $value->jsonSerialize(), $values, ); } protected function buildBodyPartFromContent(?string $textPlain, ?string $textHtml): ?MessagePart { $hasTextPlain = is_string($textPlain) && $textPlain !== ''; $hasTextHtml = is_string($textHtml) && $textHtml !== ''; if (!$hasTextPlain && !$hasTextHtml) { return null; } if ($hasTextPlain && $hasTextHtml) { return MessagePart::fromArray([ 'partId' => 'body', 'type' => 'multipart/alternative', 'subParts' => [ [ 'partId' => 'body.text', 'type' => 'text/plain', 'charset' => 'utf-8', 'content' => $textPlain, 'disposition' => 'inline', ], [ 'partId' => 'body.html', 'type' => 'text/html', 'charset' => 'utf-8', 'content' => $textHtml, 'disposition' => 'inline', ], ], ]); } return MessagePart::fromArray([ 'partId' => 'body', 'type' => $hasTextHtml ? 'text/html' : 'text/plain', 'charset' => 'utf-8', 'content' => $hasTextHtml ? $textHtml : $textPlain, 'disposition' => 'inline', ]); } protected function updateBodyContent(string $type, ?string $value): static { $currentPlain = $this->getBodyTextPlain(); $currentHtml = $this->getBodyTextHtml(); if ($type === 'text/plain') { $currentPlain = $value; } else { $currentHtml = $value; } $this->data[static::PROPERTY_BODY] = $this->buildBodyPartFromContent($currentPlain, $currentHtml)?->jsonSerialize(); return $this; } /** * @inheritDoc */ public function jsonDeserialize(array|string $data): static { if (is_string($data)) { $data = json_decode($data, true); } // Merge deserialized data into internal storage foreach ($data as $key => $value) { if (!in_array($key, ['collection', 'identifier', 'signature', 'created', 'modified'])) { $this->data[$key] = $value; } } return $this; } /** * @inheritDoc */ public function setSize(?int $value): static { $this->data[static::PROPERTY_SIZE] = $value; return $this; } /** * @inheritDoc */ public function setHeaders(array $value): static { $this->data[static::PROPERTY_HEADERS] = $value; return $this; } /** * @inheritDoc */ public function setHeader(string $name, string|array $value): static { $this->data[static::PROPERTY_HEADERS][$name] = $value; return $this; } /** * @inheritDoc */ public function setUrid(?string $value): static { $this->data[static::PROPERTY_URID] = $value; return $this; } /** * @inheritDoc */ public function setInReplyTo(?string $value): static { $this->data[static::PROPERTY_IN_REPLY_TO] = $value; return $this; } /** * @inheritDoc */ public function setReferences(string ...$value): static { $this->data[static::PROPERTY_REFERENCES] = $value; return $this; } /** * @inheritDoc */ public function setReceived(?DateTimeInterface $value): static { $this->data[static::PROPERTY_RECEIVED] = $this->normalizeDate($value); return $this; } /** * @inheritDoc */ public function setSent(?DateTimeInterface $value): static { $this->data[static::PROPERTY_SENT] = $this->normalizeDate($value); return $this; } /** * @inheritDoc */ public function setSender(?AddressInterface $value): static { $this->data[static::PROPERTY_SENDER] = $value?->toArray(); return $this; } /** * @inheritDoc */ public function setFrom(AddressInterface $value): static { $this->data[static::PROPERTY_FROM] = $value->toArray(); return $this; } /** * @inheritDoc */ public function setReplyTo(AddressInterface ...$value): static { $this->data[static::PROPERTY_REPLY_TO] = $this->normalizeAddresses($value); return $this; } /** * @inheritDoc */ public function setTo(AddressInterface ...$value): static { $this->data[static::PROPERTY_TO] = $this->normalizeAddresses($value); return $this; } /** * @inheritDoc */ public function setCc(AddressInterface ...$value): static { $this->data[static::PROPERTY_CC] = $this->normalizeAddresses($value); return $this; } /** * @inheritDoc */ public function setBcc(AddressInterface ...$value): static { $this->data[static::PROPERTY_BCC] = $this->normalizeAddresses($value); return $this; } /** * @inheritDoc */ public function setSubject(string $value): static { $this->data[static::PROPERTY_SUBJECT] = $value; return $this; } /** * @inheritDoc */ public function setBody(?MessagePartInterface $value): static { $this->data[static::PROPERTY_BODY] = $value?->jsonSerialize(); return $this; } /** * @inheritDoc */ public function setBodyTextPlain(?string $value): static { return $this->updateBodyContent('text/plain', $value); } /** * @inheritDoc */ public function setBodyTextHtml(?string $value): static { return $this->updateBodyContent('text/html', $value); } /** * @inheritDoc */ public function setAttachments(\KTXF\Mail\Object\MessagePartInterface ...$value): static { $this->data[static::PROPERTY_ATTACHMENTS] = $this->normalizeParts($value); return $this; } /** * @inheritDoc */ public function addAttachment(\KTXF\Mail\Object\MessagePartInterface $value): static { $this->data[static::PROPERTY_ATTACHMENTS][] = $value->jsonSerialize(); return $this; } /** * Sets message flags * * @since 2025.05.01 * * @param array $value * * @return static */ public function setFlags(array $value): static { if (!isset($this->data[static::PROPERTY_FLAGS])) { $this->data[static::PROPERTY_FLAGS] = [ 'read' => false, 'starred' => false, 'important' => false, 'answered' => false, 'forwarded' => false, 'draft' => false, 'deleted' => false, 'flagged' => false, ]; } $this->data[static::PROPERTY_FLAGS] = array_merge($this->data[static::PROPERTY_FLAGS], $value); return $this; } /** * @inheritDoc */ public function setFlag(string $name, bool $value): static { if (!isset($this->data[static::PROPERTY_FLAGS])) { $this->data[static::PROPERTY_FLAGS] = [ 'read' => false, 'starred' => false, 'important' => false, 'answered' => false, 'forwarded' => false, 'draft' => false, 'deleted' => false, 'flagged' => false, ]; } if (array_key_exists($name, $this->data[static::PROPERTY_FLAGS])) { $this->data[static::PROPERTY_FLAGS][$name] = $value; } return $this; } }