refactor: mail interfaces
All checks were successful
Build Test / build (pull_request) Successful in 12s
JS Unit Tests / test (pull_request) Successful in 11s
PHP Unit Tests / test (pull_request) Successful in 39s

Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
2026-05-14 22:54:51 -04:00
parent d6005246dc
commit f3c882454d
24 changed files with 583 additions and 962 deletions

View File

@@ -9,6 +9,7 @@ declare(strict_types=1);
namespace KTXF\Mail\Collection; namespace KTXF\Mail\Collection;
use KTXF\Resource\Identifier\CollectionIdentifier;
use KTXF\Resource\Provider\Node\NodeBaseAbstract; use KTXF\Resource\Provider\Node\NodeBaseAbstract;
/** /**
@@ -20,8 +21,13 @@ use KTXF\Resource\Provider\Node\NodeBaseAbstract;
*/ */
abstract class CollectionBase extends NodeBaseAbstract implements CollectionBaseInterface { abstract class CollectionBase extends NodeBaseAbstract implements CollectionBaseInterface {
protected string $type = 'mail.collection';
protected CollectionPropertiesBaseAbstract $properties; protected CollectionPropertiesBaseAbstract $properties;
protected function nodeIdentifier(): CollectionIdentifier {
return new CollectionIdentifier($this->data[static::PROPERTY_PROVIDER], $this->data[static::PROPERTY_SERVICE], (string) $this->data[static::PROPERTY_IDENTIFIER]);
}
/** /**
* @inheritDoc * @inheritDoc
*/ */

View File

@@ -9,6 +9,7 @@ declare(strict_types=1);
namespace KTXF\Mail\Collection; namespace KTXF\Mail\Collection;
use KTXF\Resource\Identifier\CollectionIdentifier;
use KTXF\Resource\Provider\Node\NodeMutableAbstract; use KTXF\Resource\Provider\Node\NodeMutableAbstract;
use KTXF\Resource\Provider\Node\NodePropertiesMutableInterface; use KTXF\Resource\Provider\Node\NodePropertiesMutableInterface;
@@ -23,6 +24,10 @@ abstract class CollectionMutableAbstract extends NodeMutableAbstract implements
protected CollectionPropertiesMutableAbstract $properties; protected CollectionPropertiesMutableAbstract $properties;
protected function nodeIdentifier(): CollectionIdentifier {
return new CollectionIdentifier($this->data[static::PROPERTY_PROVIDER], $this->data[static::PROPERTY_SERVICE], $this->data[static::PROPERTY_IDENTIFIER]);
}
/** /**
* @inheritDoc * @inheritDoc
*/ */

View File

@@ -20,49 +20,47 @@ use KTXF\Resource\Provider\Node\NodePropertiesBaseAbstract;
*/ */
abstract class CollectionPropertiesBaseAbstract extends NodePropertiesBaseAbstract implements CollectionPropertiesBaseInterface { abstract class CollectionPropertiesBaseAbstract extends NodePropertiesBaseAbstract implements CollectionPropertiesBaseInterface {
public const JSON_TYPE = CollectionPropertiesBaseInterface::JSON_TYPE;
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function total(): int { public function total(): int {
return $this->data['total'] ?? 0; return $this->data[static::PROPERTY_TOTAL] ?? 0;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function unread(): int { public function unread(): int {
return $this->data['unread'] ?? 0; return $this->data[static::PROPERTY_UNREAD] ?? 0;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getLabel(): string { public function getLabel(): string {
return $this->data['label'] ?? ''; return $this->data[static::PROPERTY_LABEL] ?? '';
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getRole(): CollectionRoles { public function getRole(): CollectionRoles {
return isset($this->data['role']) return isset($this->data[static::PROPERTY_ROLE])
? ($this->data['role'] instanceof CollectionRoles ? $this->data['role'] : CollectionRoles::from($this->data['role'])) ? ($this->data[static::PROPERTY_ROLE] instanceof CollectionRoles ? $this->data[static::PROPERTY_ROLE] : CollectionRoles::from($this->data[static::PROPERTY_ROLE]))
: CollectionRoles::Custom; : CollectionRoles::None;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getRank(): int { public function getRank(): int {
return $this->data['rank'] ?? 0; return $this->data[static::PROPERTY_RANK] ?? 0;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getSubscription(): bool { public function getSubscription(): bool {
return $this->data['subscribed'] ?? false; return $this->data[static::PROPERTY_SUBSCRIPTION] ?? false;
} }
} }

View File

@@ -13,13 +13,12 @@ use KTXF\Resource\Provider\Node\NodePropertiesBaseInterface;
interface CollectionPropertiesBaseInterface extends NodePropertiesBaseInterface { interface CollectionPropertiesBaseInterface extends NodePropertiesBaseInterface {
public const JSON_TYPE = 'mail.collection'; public const PROPERTY_TOTAL = 'total';
public const JSON_PROPERTY_TOTAL = 'total'; public const PROPERTY_UNREAD = 'unread';
public const JSON_PROPERTY_UNREAD = 'unread'; public const PROPERTY_LABEL = 'label';
public const JSON_PROPERTY_LABEL = 'label'; public const PROPERTY_ROLE = 'role';
public const JSON_PROPERTY_ROLE = 'role'; public const PROPERTY_RANK = 'rank';
public const JSON_PROPERTY_RANK = 'rank'; public const PROPERTY_SUBSCRIPTION = 'subscription';
public const JSON_PROPERTY_SUBSCRIPTION = 'subscription';
public function total(): int; public function total(): int;

View File

@@ -16,8 +16,6 @@ use KTXF\Resource\Provider\Node\NodePropertiesMutableAbstract;
*/ */
abstract class CollectionPropertiesMutableAbstract extends CollectionPropertiesBaseAbstract implements CollectionPropertiesMutableInterface { abstract class CollectionPropertiesMutableAbstract extends CollectionPropertiesBaseAbstract implements CollectionPropertiesMutableInterface {
public const JSON_TYPE = CollectionPropertiesBaseInterface::JSON_TYPE;
/** /**
* @inheritDoc * @inheritDoc
*/ */
@@ -35,7 +33,7 @@ abstract class CollectionPropertiesMutableAbstract extends CollectionPropertiesB
* @inheritDoc * @inheritDoc
*/ */
public function setLabel(string $value): static { public function setLabel(string $value): static {
$this->data['label'] = $value; $this->data[self::PROPERTY_LABEL] = $value;
return $this; return $this;
} }
@@ -43,7 +41,7 @@ abstract class CollectionPropertiesMutableAbstract extends CollectionPropertiesB
* @inheritDoc * @inheritDoc
*/ */
public function setRole(CollectionRoles $value): static { public function setRole(CollectionRoles $value): static {
$this->data['role'] = $value; $this->data[self::PROPERTY_ROLE] = $value;
return $this; return $this;
} }
@@ -51,7 +49,7 @@ abstract class CollectionPropertiesMutableAbstract extends CollectionPropertiesB
* @inheritDoc * @inheritDoc
*/ */
public function setRank(int $value): static { public function setRank(int $value): static {
$this->data['rank'] = $value; $this->data[self::PROPERTY_RANK] = $value;
return $this; return $this;
} }
@@ -59,7 +57,7 @@ abstract class CollectionPropertiesMutableAbstract extends CollectionPropertiesB
* @inheritDoc * @inheritDoc
*/ */
public function setSubscription(bool $value): static { public function setSubscription(bool $value): static {
$this->data['subscription'] = $value; $this->data[self::PROPERTY_SUBSCRIPTION] = $value;
return $this; return $this;
} }
} }

View File

@@ -13,8 +13,6 @@ use KTXF\Resource\Provider\Node\NodePropertiesMutableInterface;
interface CollectionPropertiesMutableInterface extends CollectionPropertiesBaseInterface, NodePropertiesMutableInterface { interface CollectionPropertiesMutableInterface extends CollectionPropertiesBaseInterface, NodePropertiesMutableInterface {
public const JSON_TYPE = CollectionPropertiesBaseInterface::JSON_TYPE;
public function setLabel(string $value); public function setLabel(string $value);
public function setRole(CollectionRoles $value): static; public function setRole(CollectionRoles $value): static;

View File

@@ -10,6 +10,7 @@ declare(strict_types=1);
namespace KTXF\Mail\Entity; namespace KTXF\Mail\Entity;
use KTXF\Mail\Object\MessagePropertiesBaseInterface; use KTXF\Mail\Object\MessagePropertiesBaseInterface;
use KTXF\Resource\Identifier\EntityIdentifier;
use KTXF\Resource\Provider\Node\NodeBaseAbstract; use KTXF\Resource\Provider\Node\NodeBaseAbstract;
/** /**
@@ -21,8 +22,13 @@ use KTXF\Resource\Provider\Node\NodeBaseAbstract;
*/ */
abstract class EntityBaseAbstract extends NodeBaseAbstract implements EntityBaseInterface { abstract class EntityBaseAbstract extends NodeBaseAbstract implements EntityBaseInterface {
protected string $type = 'mail.entity';
protected MessagePropertiesBaseInterface $properties; protected MessagePropertiesBaseInterface $properties;
protected function nodeIdentifier(): EntityIdentifier {
return new EntityIdentifier($this->data[static::PROPERTY_PROVIDER], $this->data[static::PROPERTY_SERVICE], $this->data[static::PROPERTY_COLLECTION], $this->data[static::PROPERTY_IDENTIFIER]);
}
/** /**
* @inheritDoc * @inheritDoc
*/ */

View File

@@ -15,8 +15,6 @@ use KTXF\Resource\Provider\Node\NodeBaseInterface;
interface EntityBaseInterface extends NodeBaseInterface { interface EntityBaseInterface extends NodeBaseInterface {
public const JSON_TYPE = 'mail.entity';
/** /**
* Gets the entity properties * Gets the entity properties
* *

View File

@@ -10,6 +10,7 @@ declare(strict_types=1);
namespace KTXF\Mail\Entity; namespace KTXF\Mail\Entity;
use KTXF\Mail\Object\MessagePropertiesMutableInterface; use KTXF\Mail\Object\MessagePropertiesMutableInterface;
use KTXF\Resource\Identifier\EntityIdentifier;
use KTXF\Resource\Provider\Node\NodeMutableAbstract; use KTXF\Resource\Provider\Node\NodeMutableAbstract;
use KTXF\Resource\Provider\Node\NodePropertiesMutableInterface; use KTXF\Resource\Provider\Node\NodePropertiesMutableInterface;
@@ -22,10 +23,13 @@ use KTXF\Resource\Provider\Node\NodePropertiesMutableInterface;
*/ */
abstract class EntityMutableAbstract extends NodeMutableAbstract implements EntityMutableInterface { abstract class EntityMutableAbstract extends NodeMutableAbstract implements EntityMutableInterface {
public const JSON_TYPE = EntityMutableInterface::JSON_TYPE; protected string $type = 'mail.entity';
protected MessagePropertiesMutableInterface $properties; protected MessagePropertiesMutableInterface $properties;
protected function nodeIdentifier(): EntityIdentifier {
return new EntityIdentifier($this->data[static::PROPERTY_PROVIDER], $this->data[static::PROPERTY_SERVICE], (string) $this->data[static::PROPERTY_COLLECTION], (string) $this->data[static::PROPERTY_IDENTIFIER]);
}
/** /**
* @inheritDoc * @inheritDoc
*/ */

View File

@@ -17,8 +17,6 @@ use KTXF\Resource\Provider\Node\NodeMutableInterface;
*/ */
interface EntityMutableInterface extends EntityBaseInterface, NodeMutableInterface { interface EntityMutableInterface extends EntityBaseInterface, NodeMutableInterface {
public const JSON_TYPE = EntityBaseInterface::JSON_TYPE;
/** /**
* Gets the entity properties (mutable) * Gets the entity properties (mutable)
* *

View File

@@ -21,188 +21,161 @@ use KTXF\Resource\Provider\Node\NodePropertiesBaseAbstract;
*/ */
abstract class MessagePropertiesBaseAbstract extends NodePropertiesBaseAbstract implements MessagePropertiesBaseInterface { abstract class MessagePropertiesBaseAbstract extends NodePropertiesBaseAbstract implements MessagePropertiesBaseInterface {
public const JSON_TYPE = MessagePropertiesBaseInterface::JSON_TYPE; protected string $type = 'mail.message';
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getHeaders(): array { public function jsonSerialize(): array {
return $this->data['headers'] ?? []; return $this->data;
}
/**
* @inheritDoc
*/
public function getHeader(string $name): string|array|null {
return $this->data['headers'][$name] ?? null;
}
/**
* @inheritDoc
*/
public function getUrid(): ?string {
return $this->data['urid'] ?? null;
}
/**
* @inheritDoc
*/
public function getCreated(): ?DateTimeImmutable {
return $this->data['created'] ?? null;
}
/**
* @inheritDoc
*/
public function getModified(): ?DateTimeImmutable {
return $this->data['modified'] ?? null;
}
/**
* @inheritDoc
*/
public function getDate(): ?DateTimeImmutable {
return $this->data['date'] ?? null;
}
/**
* @inheritDoc
*/
public function getReceived(): ?DateTimeImmutable {
return $this->data['received'] ?? null;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getSize(): ?int { public function getSize(): ?int {
return $this->data['size'] ?? null; return $this->data[static::PROPERTY_SIZE] ?? null;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getSender(): ?AddressInterface { public function getHeaders(): array {
return $this->data['sender'] ?? null; return $this->data[static::PROPERTY_HEADERS] ?? [];
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getFrom(): ?AddressInterface { public function getHeader(string $name): string|array|null {
return $this->data['from'] ?? null; return $this->data[static::PROPERTY_HEADERS][$name] ?? null;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getReplyTo(): array { public function getUrid(): ?string {
return $this->data['replyTo'] ?? []; return $this->data[static::PROPERTY_URID] ?? null;
}
/**
* @inheritDoc
*/
public function getTo(): array {
return $this->data['to'] ?? [];
}
/**
* @inheritDoc
*/
public function getCc(): array {
return $this->data['cc'] ?? [];
}
/**
* @inheritDoc
*/
public function getBcc(): array {
return $this->data['bcc'] ?? [];
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getInReplyTo(): ?string { public function getInReplyTo(): ?string {
return $this->data['inReplyTo'] ?? null; return $this->data[static::PROPERTY_IN_REPLY_TO] ?? null;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getReferences(): array { public function getReferences(): array {
return $this->data['references'] ?? []; return $this->data[static::PROPERTY_REFERENCES] ?? [];
}
/**
* @inheritDoc
*/
public function getReceived(): ?DateTimeImmutable {
return $this->data[static::PROPERTY_RECEIVED] ?? null;
}
/**
* @inheritDoc
*/
public function getSent(): ?DateTimeImmutable {
return $this->data[static::PROPERTY_SENT] ?? null;
}
/**
* @inheritDoc
*/
public function getSender(): ?AddressInterface {
return $this->data[static::PROPERTY_SENDER] ?? null;
}
/**
* @inheritDoc
*/
public function getFrom(): ?AddressInterface {
return $this->data[static::PROPERTY_FROM] ?? null;
}
/**
* @inheritDoc
*/
public function getReplyTo(): array {
return $this->data[static::PROPERTY_REPLY_TO] ?? [];
}
/**
* @inheritDoc
*/
public function getTo(): array {
return $this->data[static::PROPERTY_TO] ?? [];
}
/**
* @inheritDoc
*/
public function getCc(): array {
return $this->data[static::PROPERTY_CC] ?? [];
}
/**
* @inheritDoc
*/
public function getBcc(): array {
return $this->data[static::PROPERTY_BCC] ?? [];
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getSubject(): string { public function getSubject(): string {
return $this->data['subject'] ?? ''; return $this->data[static::PROPERTY_SUBJECT] ?? '';
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getSnippet(): ?string { public function getBody(): ?MessagePartInterface {
return $this->data['snippet'] ?? null; return $this->data[static::PROPERTY_BODY] ?? null;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getBodyText(): ?string { public function hasBody(): bool {
return $this->data['bodyText'] ?? null; return ($this->data[static::PROPERTY_BODY_TEXT_PLAIN] !== null && $this->data[static::PROPERTY_BODY_TEXT_PLAIN] !== '')
|| ($this->data[static::PROPERTY_BODY_TEXT_HTML] !== null && $this->data[static::PROPERTY_BODY_TEXT_HTML] !== '');
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getBodyTextCharset(): ?string { public function getBodyTextPlain(): ?string {
return $this->data['bodyTextCharset'] ?? null; return $this->data[static::PROPERTY_BODY_TEXT_PLAIN] ?? null;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getBodyTextSize(): ?int { public function getBodyTextHtml(): ?string {
return $this->data['bodyTextSize'] ?? null; return $this->data[static::PROPERTY_BODY_TEXT_HTML] ?? null;
}
/**
* @inheritDoc
*/
public function getBodyHtml(): ?string {
return $this->data['bodyHtml'] ?? null;
}
/**
* @inheritDoc
*/
public function getBodyHtmlCharset(): ?string {
return $this->data['bodyHtmlCharset'] ?? null;
}
/**
* @inheritDoc
*/
public function getBodyHtmlSize(): ?int {
return $this->data['bodyHtmlSize'] ?? null;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getAttachments(): array { public function getAttachments(): array {
return $this->data['attachments'] ?? []; return $this->data[static::PROPERTY_ATTACHMENTS] ?? [];
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getFlags(): array { public function getFlags(): array {
return $this->data['flags'] ?? [ return $this->data[static::PROPERTY_FLAGS] ?? [
'read' => false, 'read' => false,
'starred' => false, 'starred' => false,
'important' => false, 'important' => false,
@@ -218,179 +191,7 @@ abstract class MessagePropertiesBaseAbstract extends NodePropertiesBaseAbstract
* @inheritDoc * @inheritDoc
*/ */
public function getFlag(string $name): bool { public function getFlag(string $name): bool {
return $this->data['flags'][$name] ?? false; return $this->data[static::PROPERTY_FLAGS][$name] ?? false;
} }
/**
* Gets message labels
*
* @since 2025.05.01
*
* @return array<int, string>
*/
public function getLabels(): array {
return $this->data['labels'] ?? [];
}
/**
* Gets message tags
*
* @since 2025.05.01
*
* @return array<int, string>
*/
public function getTags(): array {
return $this->data['tags'] ?? [];
}
/**
* Gets message priority
*
* @since 2025.05.01
*
* @return string
*/
public function getPriority(): string {
return $this->data['priority'] ?? 'normal';
}
/**
* Gets message sensitivity
*
* @since 2025.05.01
*
* @return string
*/
public function getSensitivity(): string {
return $this->data['sensitivity'] ?? 'normal';
}
/**
* Gets encryption information
*
* @since 2025.05.01
*
* @return array{method: string|null, signed: bool, encrypted: bool}
*/
public function getEncryption(): array {
return $this->data['encryption'] ?? [
'method' => null,
'signed' => false,
'encrypted' => false,
];
}
/**
* Checks if delivery receipt is requested
*
* @since 2025.05.01
*
* @return bool
*/
public function isDeliveryReceipt(): bool {
return $this->data['deliveryReceipt'] ?? false;
}
/**
* Checks if read receipt is requested
*
* @since 2025.05.01
*
* @return bool
*/
public function isReadReceipt(): bool {
return $this->data['readReceipt'] ?? false;
}
/**
* @inheritDoc
*/
public function hasRecipients(): bool {
return !empty($this->data['to']) || !empty($this->data['cc']) || !empty($this->data['bcc']);
}
/**
* @inheritDoc
*/
public function hasBody(): bool {
return ($this->data['bodyText'] !== null && $this->data['bodyText'] !== '')
|| ($this->data['bodyHtml'] !== null && $this->data['bodyHtml'] !== '');
}
/**
* @inheritDoc
*/
public function getBody(): ?MessagePartInterface {
return $this->data['body'] ?? null;
}
/**
* @inheritDoc
*/
public function jsonSerialize(): array {
$data = [
self::JSON_PROPERTY_TYPE => self::JSON_TYPE,
self::JSON_PROPERTY_SCHEMA => $this->data['schema'] ?? 1,
];
if (!empty($this->data['headers'])) {
$data[self::JSON_PROPERTY_HEADERS] = $this->data['headers'];
}
if (isset($this->data['urid']) && $this->data['urid'] !== null) {
$data[self::JSON_PROPERTY_URID] = $this->data['urid'];
}
if (isset($this->data['date']) && $this->data['date'] !== null) {
$data[self::JSON_PROPERTY_DATE] = $this->data['date'] instanceof DateTimeImmutable
? $this->data['date']->format('c')
: $this->data['date'];
}
if (isset($this->data['received']) && $this->data['received'] !== null) {
$data[self::JSON_PROPERTY_RECEIVED] = $this->data['received'] instanceof DateTimeImmutable
? $this->data['received']->format('c')
: $this->data['received'];
}
if (isset($this->data['size']) && $this->data['size'] !== null) {
$data[self::JSON_PROPERTY_SIZE] = $this->data['size'];
}
if (isset($this->data['sender']) && $this->data['sender'] !== null) {
$data[self::JSON_PROPERTY_SENDER] = $this->data['sender'];
}
if (isset($this->data['from']) && $this->data['from'] !== null) {
$data[self::JSON_PROPERTY_FROM] = $this->data['from'];
}
if (!empty($this->data['replyTo'])) {
$data[self::JSON_PROPERTY_REPLY_TO] = $this->data['replyTo'];
}
if (!empty($this->data['to'])) {
$data[self::JSON_PROPERTY_TO] = $this->data['to'];
}
if (!empty($this->data['cc'])) {
$data[self::JSON_PROPERTY_CC] = $this->data['cc'];
}
if (!empty($this->data['bcc'])) {
$data[self::JSON_PROPERTY_BCC] = $this->data['bcc'];
}
if (isset($this->data['inReplyTo']) && $this->data['inReplyTo'] !== null) {
$data[self::JSON_PROPERTY_IN_REPLY_TO] = $this->data['inReplyTo'];
}
if (!empty($this->data['references'])) {
$data[self::JSON_PROPERTY_REFERENCES] = $this->data['references'];
}
if (isset($this->data['snippet']) && $this->data['snippet'] !== null) {
$data[self::JSON_PROPERTY_SNIPPET] = $this->data['snippet'];
}
if (!empty($this->data['attachments'])) {
$data[self::JSON_PROPERTY_ATTACHMENTS] = $this->data['attachments'];
}
if (!empty($this->data['flags'])) {
$data[self::JSON_PROPERTY_FLAGS] = $this->data['flags'];
}
$data[self::JSON_PROPERTY_SUBJECT] = $this->data['subject'] ?? null;
$data[self::JSON_PROPERTY_BODY] = $this->data['body'] ?? null;
return $data;
}
} }

View File

@@ -19,26 +19,35 @@ use KTXF\Resource\Provider\Node\NodePropertiesBaseInterface;
*/ */
interface MessagePropertiesBaseInterface extends NodePropertiesBaseInterface { interface MessagePropertiesBaseInterface extends NodePropertiesBaseInterface {
public const JSON_TYPE = 'mail.message'; public const PROPERTY_SIZE = 'size';
public const JSON_PROPERTY_HEADERS = 'headers'; public const PROPERTY_HEADERS = 'headers';
public const JSON_PROPERTY_URID = 'urid'; public const PROPERTY_URID = 'urid'; // mime message ID or similar unique identifier
public const JSON_PROPERTY_DATE = 'date'; public const PROPERTY_IN_REPLY_TO = 'inReplyTo';
public const JSON_PROPERTY_RECEIVED = 'received'; public const PROPERTY_REFERENCES = 'references';
public const JSON_PROPERTY_SIZE = 'size'; public const PROPERTY_RECEIVED = 'received';
public const JSON_PROPERTY_SENDER = 'sender'; public const PROPERTY_SENT = 'sent';
public const JSON_PROPERTY_FROM = 'from'; public const PROPERTY_SENDER = 'sender';
public const JSON_PROPERTY_REPLY_TO = 'replyTo'; public const PROPERTY_REPLY_TO = 'replyTo';
public const JSON_PROPERTY_TO = 'to'; public const PROPERTY_FROM = 'from';
public const JSON_PROPERTY_CC = 'cc'; public const PROPERTY_TO = 'to';
public const JSON_PROPERTY_BCC = 'bcc'; public const PROPERTY_CC = 'cc';
public const JSON_PROPERTY_IN_REPLY_TO = 'inReplyTo'; public const PROPERTY_BCC = 'bcc';
public const JSON_PROPERTY_REFERENCES = 'references'; public const PROPERTY_SUBJECT = 'subject';
public const JSON_PROPERTY_SUBJECT = 'subject'; public const PROPERTY_BODY = 'body';
public const JSON_PROPERTY_SNIPPET = 'snippet'; public const PROPERTY_BODY_TEXT_PLAIN = 'bodyTextPlain';
public const JSON_PROPERTY_BODY = 'body'; public const PROPERTY_BODY_TEXT_HTML = 'bodyTextHtml';
public const JSON_PROPERTY_ATTACHMENTS = 'attachments'; public const PROPERTY_ATTACHMENTS = 'attachments';
public const JSON_PROPERTY_FLAGS = 'flags'; public const PROPERTY_FLAGS = 'flags';
public const JSON_PROPERTY_TAGS = 'tags'; public const PROPERTY_TAGS = 'tags';
/**
* Gets the message size in bytes
*
* @since 2025.05.01
*
* @return int|null
*/
public function getSize(): ?int;
/** /**
* Gets custom headers * Gets custom headers
@@ -70,13 +79,22 @@ interface MessagePropertiesBaseInterface extends NodePropertiesBaseInterface {
public function getUrid(): ?string; public function getUrid(): ?string;
/** /**
* Gets the message date * Gets the message ID this is replying to
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @return DateTimeImmutable|null * @return string|null
*/ */
public function getDate(): ?DateTimeImmutable; public function getInReplyTo(): ?string;
/**
* Gets the references (message IDs in thread)
*
* @since 2025.05.01
*
* @return array<int,string>
*/
public function getReferences(): array;
/** /**
* Gets the received date * Gets the received date
@@ -88,13 +106,13 @@ interface MessagePropertiesBaseInterface extends NodePropertiesBaseInterface {
public function getReceived(): ?DateTimeImmutable; public function getReceived(): ?DateTimeImmutable;
/** /**
* Gets the message size in bytes * Gets the sent date
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @return int|null * @return DateTimeImmutable|null
*/ */
public function getSize(): ?int; public function getSent(): ?DateTimeImmutable;
/** /**
* Gets the sender address (actual sender, may differ from From) * Gets the sender address (actual sender, may differ from From)
@@ -149,24 +167,6 @@ interface MessagePropertiesBaseInterface extends NodePropertiesBaseInterface {
*/ */
public function getBcc(): array; public function getBcc(): array;
/**
* Gets the message ID this is replying to
*
* @since 2025.05.01
*
* @return string|null
*/
public function getInReplyTo(): ?string;
/**
* Gets the references (message IDs in thread)
*
* @since 2025.05.01
*
* @return array<int,string>
*/
public function getReferences(): array;
/** /**
* Gets the message subject * Gets the message subject
* *
@@ -176,24 +176,6 @@ interface MessagePropertiesBaseInterface extends NodePropertiesBaseInterface {
*/ */
public function getSubject(): string; public function getSubject(): string;
/**
* Gets the message snippet/preview
*
* @since 2025.05.01
*
* @return string|null
*/
public function getSnippet(): ?string;
/**
* Checks if the message has any body content
*
* @since 2025.05.01
*
* @return bool True if text or HTML body is set
*/
public function hasBody(): bool;
/** /**
* Gets the message body structure * Gets the message body structure
* *
@@ -203,6 +185,15 @@ interface MessagePropertiesBaseInterface extends NodePropertiesBaseInterface {
*/ */
public function getBody(): ?MessagePartInterface; public function getBody(): ?MessagePartInterface;
/**
* Checks if the message has any body content
*
* @since 2025.05.01
*
* @return bool True if text or HTML body is set
*/
public function hasBody(): bool;
/** /**
* Gets the plain text body content * Gets the plain text body content
* *
@@ -210,7 +201,7 @@ interface MessagePropertiesBaseInterface extends NodePropertiesBaseInterface {
* *
* @return string|null * @return string|null
*/ */
public function getBodyText(): ?string; public function getBodyTextPlain(): ?string;
/** /**
* Gets the HTML body content * Gets the HTML body content
@@ -219,7 +210,7 @@ interface MessagePropertiesBaseInterface extends NodePropertiesBaseInterface {
* *
* @return string|null * @return string|null
*/ */
public function getBodyHtml(): ?string; public function getBodyTextHtml(): ?string;
/** /**
* Gets the attachments * Gets the attachments

View File

@@ -19,422 +19,9 @@ use DateTimeImmutable;
* @since 2025.05.01 * @since 2025.05.01
*/ */
abstract class MessagePropertiesMutableAbstract extends MessagePropertiesBaseAbstract implements MessagePropertiesMutableInterface { abstract class MessagePropertiesMutableAbstract extends MessagePropertiesBaseAbstract implements MessagePropertiesMutableInterface {
public const JSON_TYPE = MessagePropertiesBaseInterface::JSON_TYPE;
/** protected string $type = 'mail.message';
* @inheritDoc
*/
public function setHeaders(array $value): static {
$this->data['headers'] = $value;
return $this;
}
/**
* @inheritDoc
*/
public function setHeader(string $name, string|array $value): static {
$this->data['headers'][$name] = $value;
return $this;
}
/**
* @inheritDoc
*/
public function setUrid(?string $value): static {
$this->data['urid'] = $value;
return $this;
}
/**
* @inheritDoc
*/
public function setCreated(DateTimeImmutable $value): static {
$this->data['created'] = $value;
return $this;
}
/**
* @inheritDoc
*/
public function setModified(DateTimeImmutable $value): static {
$this->data['modified'] = $value;
return $this;
}
/**
* @inheritDoc
*/
public function setDate(DateTimeImmutable $value): static {
$this->data['date'] = $value;
return $this;
}
/**
* @inheritDoc
*/
public function setReceived(?DateTimeImmutable $value): static {
$this->data['received'] = $value;
return $this;
}
/**
* @inheritDoc
*/
public function setSize(?int $value): static {
$this->data['size'] = $value;
return $this;
}
/**
* @inheritDoc
*/
public function setSender(?AddressInterface $value): static {
$this->data['sender'] = $value;
return $this;
}
/**
* @inheritDoc
*/
public function setFrom(AddressInterface $value): static {
$this->data['from'] = $value;
return $this;
}
/**
* @inheritDoc
*/
public function setReplyTo(AddressInterface ...$value): static {
$this->data['replyTo'] = $value;
return $this;
}
/**
* @inheritDoc
*/
public function setTo(AddressInterface ...$value): static {
$this->data['to'] = $value;
return $this;
}
/**
* @inheritDoc
*/
public function setCc(AddressInterface ...$value): static {
$this->data['cc'] = $value;
return $this;
}
/**
* @inheritDoc
*/
public function setBcc(AddressInterface ...$value): static {
$this->data['bcc'] = $value;
return $this;
}
/**
* @inheritDoc
*/
public function setInReplyTo(?string $value): static {
$this->data['inReplyTo'] = $value;
return $this;
}
/**
* @inheritDoc
*/
public function setReferences(string ...$value): static {
$this->data['references'] = $value;
return $this;
}
/**
* @inheritDoc
*/
public function setSubject(string $value): static {
$this->data['subject'] = $value;
return $this;
}
/**
* @inheritDoc
*/
public function setSnippet(?string $value): static {
$this->data['snippet'] = $value;
return $this;
}
/**
* @inheritDoc
*/
public function setBodyText(?string $value): static {
$this->data['bodyText'] = $value;
return $this;
}
/**
* Sets the plain text body charset
*
* @since 2025.05.01
*
* @param string $value
*
* @return static
*/
public function setBodyTextCharset(string $value): static {
$this->data['bodyTextCharset'] = $value;
return $this;
}
/**
* Sets the plain text body size
*
* @since 2025.05.01
*
* @param int $value
*
* @return static
*/
public function setBodyTextSize(int $value): static {
$this->data['bodyTextSize'] = $value;
return $this;
}
/**
* @inheritDoc
*/
public function setBodyHtml(?string $value): static {
$this->data['bodyHtml'] = $value;
return $this;
}
/**
* Sets the HTML body charset
*
* @since 2025.05.01
*
* @param string $value
*
* @return static
*/
public function setBodyHtmlCharset(string $value): static {
$this->data['bodyHtmlCharset'] = $value;
return $this;
}
/**
* Sets the HTML body size
*
* @since 2025.05.01
*
* @param int $value
*
* @return static
*/
public function setBodyHtmlSize(int $value): static {
$this->data['bodyHtmlSize'] = $value;
return $this;
}
/**
* @inheritDoc
*/
public function setAttachments(AttachmentInterface ...$value): static {
$this->data['attachments'] = $value;
return $this;
}
/**
* @inheritDoc
*/
public function addAttachment(AttachmentInterface $value): static {
$this->data['attachments'][] = $value;
return $this;
}
/**
* Sets message flags
*
* @since 2025.05.01
*
* @param array $value
*
* @return static
*/
public function setFlags(array $value): static {
if (!isset($this->data['flags'])) {
$this->data['flags'] = [
'read' => false,
'starred' => false,
'important' => false,
'answered' => false,
'forwarded' => false,
'draft' => false,
'deleted' => false,
'flagged' => false,
];
}
$this->data['flags'] = array_merge($this->data['flags'], $value);
return $this;
}
/**
* @inheritDoc
*/
public function setFlag(string $name, bool $value): static {
if (!isset($this->data['flags'])) {
$this->data['flags'] = [
'read' => false,
'starred' => false,
'important' => false,
'answered' => false,
'forwarded' => false,
'draft' => false,
'deleted' => false,
'flagged' => false,
];
}
if (array_key_exists($name, $this->data['flags'])) {
$this->data['flags'][$name] = $value;
}
return $this;
}
/**
* Sets message labels
*
* @since 2025.05.01
*
* @param string ...$value
*
* @return static
*/
public function setLabels(string ...$value): static {
$this->data['labels'] = $value;
return $this;
}
/**
* Adds a message label
*
* @since 2025.05.01
*
* @param string $value
*
* @return static
*/
public function addLabel(string $value): static {
$this->data['labels'][] = $value;
return $this;
}
/**
* Sets message tags
*
* @since 2025.05.01
*
* @param string ...$value
*
* @return static
*/
public function setTags(string ...$value): static {
$this->data['tags'] = $value;
return $this;
}
/**
* Adds a message tag
*
* @since 2025.05.01
*
* @param string $value
*
* @return static
*/
public function addTag(string $value): static {
$this->data['tags'][] = $value;
return $this;
}
/**
* Sets message priority
*
* @since 2025.05.01
*
* @param string $value
*
* @return static
*/
public function setPriority(string $value): static {
$this->data['priority'] = $value;
return $this;
}
/**
* Sets message sensitivity
*
* @since 2025.05.01
*
* @param string $value
*
* @return static
*/
public function setSensitivity(string $value): static {
$this->data['sensitivity'] = $value;
return $this;
}
/**
* Sets encryption information
*
* @since 2025.05.01
*
* @param array $value
*
* @return static
*/
public function setEncryption(array $value): static {
if (!isset($this->data['encryption'])) {
$this->data['encryption'] = [
'method' => null,
'signed' => false,
'encrypted' => false,
];
}
$this->data['encryption'] = array_merge($this->data['encryption'], $value);
return $this;
}
/**
* Sets delivery receipt flag
*
* @since 2025.05.01
*
* @param bool $value
*
* @return static
*/
public function setDeliveryReceipt(bool $value): static {
$this->data['deliveryReceipt'] = $value;
return $this;
}
/**
* Sets read receipt flag
*
* @since 2025.05.01
*
* @param bool $value
*
* @return static
*/
public function setReadReceipt(bool $value): static {
$this->data['readReceipt'] = $value;
return $this;
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
@@ -452,4 +39,213 @@ abstract class MessagePropertiesMutableAbstract extends MessagePropertiesBaseAbs
return $this; 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(?DateTimeImmutable $value): static {
$this->data[static::PROPERTY_RECEIVED] = $value;
return $this;
}
/**
* @inheritDoc
*/
public function setSent(DateTimeImmutable $value): static {
$this->data[static::PROPERTY_SENT] = $value;
return $this;
}
/**
* @inheritDoc
*/
public function setSender(?AddressInterface $value): static {
$this->data[static::PROPERTY_SENDER] = $value;
return $this;
}
/**
* @inheritDoc
*/
public function setFrom(AddressInterface $value): static {
$this->data[static::PROPERTY_FROM] = $value;
return $this;
}
/**
* @inheritDoc
*/
public function setReplyTo(AddressInterface ...$value): static {
$this->data[static::PROPERTY_REPLY_TO] = $value;
return $this;
}
/**
* @inheritDoc
*/
public function setTo(AddressInterface ...$value): static {
$this->data[static::PROPERTY_TO] = $value;
return $this;
}
/**
* @inheritDoc
*/
public function setCc(AddressInterface ...$value): static {
$this->data[static::PROPERTY_CC] = $value;
return $this;
}
/**
* @inheritDoc
*/
public function setBcc(AddressInterface ...$value): static {
$this->data[static::PROPERTY_BCC] = $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;
return $this;
}
/**
* @inheritDoc
*/
public function setBodyTextPlain(?string $value): static {
$this->data[static::PROPERTY_BODY_TEXT_PLAIN] = $value;
return $this;
}
/**
* @inheritDoc
*/
public function setBodyTextHtml(?string $value): static {
$this->data[static::PROPERTY_BODY_TEXT_HTML] = $value;
return $this;
}
/**
* @inheritDoc
*/
public function setAttachments(AttachmentInterface ...$value): static {
$this->data[static::PROPERTY_ATTACHMENTS] = $value;
return $this;
}
/**
* @inheritDoc
*/
public function addAttachment(AttachmentInterface $value): static {
$this->data[static::PROPERTY_ATTACHMENTS][] = $value;
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;
}
} }

View File

@@ -18,9 +18,18 @@ use KTXF\Resource\Provider\Node\NodePropertiesMutableInterface;
* @since 2025.05.01 * @since 2025.05.01
*/ */
interface MessagePropertiesMutableInterface extends MessagePropertiesBaseInterface, NodePropertiesMutableInterface { interface MessagePropertiesMutableInterface extends MessagePropertiesBaseInterface, NodePropertiesMutableInterface {
public const JSON_TYPE = MessagePropertiesBaseInterface::JSON_TYPE;
/**
* Sets the message size in bytes
*
* @since 2025.05.01
*
* @param int|null $value
*
* @return self
*/
public function setSize(?int $value): static;
/** /**
* Sets custom headers * Sets custom headers
* *
@@ -56,15 +65,26 @@ interface MessagePropertiesMutableInterface extends MessagePropertiesBaseInterfa
public function setUrid(?string $value): static; public function setUrid(?string $value): static;
/** /**
* Sets the message date * Sets the message ID this is replying to
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @param DateTimeImmutable $value * @param string|null $value
* *
* @return self * @return self
*/ */
public function setDate(DateTimeImmutable $value): static; public function setInReplyTo(?string $value): static;
/**
* Sets the references (message IDs in thread)
*
* @since 2025.05.01
*
* @param string ...$value
*
* @return self
*/
public function setReferences(string ...$value): static;
/** /**
* Sets the received date * Sets the received date
@@ -77,16 +97,16 @@ interface MessagePropertiesMutableInterface extends MessagePropertiesBaseInterfa
*/ */
public function setReceived(?DateTimeImmutable $value): static; public function setReceived(?DateTimeImmutable $value): static;
/** /**
* Sets the message size in bytes * Sets the message date
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @param int|null $value * @param DateTimeImmutable $value
* *
* @return self * @return self
*/ */
public function setSize(?int $value): static; public function setSent(DateTimeImmutable $value): static;
/** /**
* Sets the sender address (actual sender, may differ from From) * Sets the sender address (actual sender, may differ from From)
@@ -154,28 +174,6 @@ interface MessagePropertiesMutableInterface extends MessagePropertiesBaseInterfa
*/ */
public function setBcc(AddressInterface ...$value): static; public function setBcc(AddressInterface ...$value): static;
/**
* Sets the message ID this is replying to
*
* @since 2025.05.01
*
* @param string|null $value
*
* @return self
*/
public function setInReplyTo(?string $value): static;
/**
* Sets the references (message IDs in thread)
*
* @since 2025.05.01
*
* @param string ...$value
*
* @return self
*/
public function setReferences(string ...$value): static;
/** /**
* Sets the message subject * Sets the message subject
* *
@@ -188,15 +186,15 @@ interface MessagePropertiesMutableInterface extends MessagePropertiesBaseInterfa
public function setSubject(string $value): static; public function setSubject(string $value): static;
/** /**
* Sets the message snippet/preview * Sets the message body
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @param string|null $value * @param MessagePartInterface|null $value
* *
* @return self * @return self
*/ */
public function setSnippet(?string $value): static; public function setBody(?MessagePartInterface $value): static;
/** /**
* Sets the plain text body content * Sets the plain text body content
@@ -207,7 +205,7 @@ interface MessagePropertiesMutableInterface extends MessagePropertiesBaseInterfa
* *
* @return self * @return self
*/ */
public function setBodyText(?string $value): static; public function setBodyTextPlain(?string $value): static;
/** /**
* Sets the HTML body content * Sets the HTML body content
@@ -218,7 +216,7 @@ interface MessagePropertiesMutableInterface extends MessagePropertiesBaseInterfa
* *
* @return self * @return self
*/ */
public function setBodyHtml(?string $value): static; public function setBodyTextHtml(?string $value): static;
/** /**
* Sets the attachments * Sets the attachments
@@ -241,15 +239,28 @@ interface MessagePropertiesMutableInterface extends MessagePropertiesBaseInterfa
* @return self * @return self
*/ */
public function addAttachment(AttachmentInterface $value): static; public function addAttachment(AttachmentInterface $value): static;
/** /**
* Sets message tags * Sets message flags
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @param array{read: bool, starred: bool, important: bool, answered: bool, forwarded: bool, draft: bool, deleted: bool, flagged: bool} $value * @param array $value
* *
* @return self * @return self
*/ */
public function setFlags(array $value): static;
/**
* Sets message flags
*
* @since 2025.05.01
*
* @param string $label
* @param bool $value
*
* @return self
*/
public function setFlag(string $label, bool $value): static; public function setFlag(string $label, bool $value): static;
} }

View File

@@ -26,7 +26,7 @@ use KTXF\Resource\Provider\ResourceServiceLocationInterface;
* *
* @since 2025.05.01 * @since 2025.05.01
*/ */
interface ProviderServiceDiscoverInterface extends ProviderBaseInterface { interface ProviderServiceDiscoverInterface {
/** /**
* Attempts to discover service configuration using provider-specific methods. * Attempts to discover service configuration using provider-specific methods.

View File

@@ -25,9 +25,7 @@ use KTXF\Resource\Provider\ResourceProviderServiceMutateInterface;
* @method string serviceModify(string $tenantId, ?string $userId, ServiceMutableInterface $service) Modify a mail service configuration * @method string serviceModify(string $tenantId, ?string $userId, ServiceMutableInterface $service) Modify a mail service configuration
* @method bool serviceDestroy(string $tenantId, ?string $userId, ServiceMutableInterface $service) Delete a mail service configuration * @method bool serviceDestroy(string $tenantId, ?string $userId, ServiceMutableInterface $service) Delete a mail service configuration
*/ */
interface ProviderServiceMutateInterface extends ProviderBaseInterface, ResourceProviderServiceMutateInterface { interface ProviderServiceMutateInterface extends ResourceProviderServiceMutateInterface {
public const JSON_TYPE = ProviderBaseInterface::JSON_TYPE;
// Methods inherited from ResourceProviderServiceMutateInterface // Methods inherited from ResourceProviderServiceMutateInterface
// Implementations should return/accept ServiceMutableInterface instances // Implementations should return/accept ServiceMutableInterface instances

View File

@@ -10,6 +10,7 @@ declare(strict_types=1);
namespace KTXF\Mail\Provider; namespace KTXF\Mail\Provider;
use KTXF\Mail\Service\ServiceBaseInterface; use KTXF\Mail\Service\ServiceBaseInterface;
use KTXF\Mail\Service\ServiceMutableInterface;
/** /**
* Mail Provider Service Test Interface * Mail Provider Service Test Interface
@@ -25,7 +26,7 @@ use KTXF\Mail\Service\ServiceBaseInterface;
* *
* @since 2025.05.01 * @since 2025.05.01
*/ */
interface ProviderServiceTestInterface extends ProviderBaseInterface { interface ProviderServiceTestInterface {
/** /**
* Test a service connection * Test a service connection
@@ -39,7 +40,7 @@ interface ProviderServiceTestInterface extends ProviderBaseInterface {
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @param ServiceBaseInterface $service Service to test (can be fresh/unsaved or existing) * @param ServiceBaseInterface|ServiceMutableInterface $service Service to test (can be fresh/unsaved or existing)
* @param array $options Provider-specific test options: * @param array $options Provider-specific test options:
* - 'timeout' => int (seconds, default: 10) * - 'timeout' => int (seconds, default: 10)
* - 'verify_ssl' => bool (default: true) * - 'verify_ssl' => bool (default: true)
@@ -72,6 +73,6 @@ interface ProviderServiceTestInterface extends ProviderBaseInterface {
* ] * ]
* ] * ]
*/ */
public function serviceTest(ServiceBaseInterface $service, array $options = []): array; public function serviceTest(ServiceBaseInterface|ServiceMutableInterface $service, array $options = []): array;
} }

View File

@@ -11,6 +11,8 @@ namespace KTXF\Mail\Service;
use KTXF\Mail\Collection\CollectionBaseInterface; use KTXF\Mail\Collection\CollectionBaseInterface;
use KTXF\Mail\Collection\CollectionMutableInterface; use KTXF\Mail\Collection\CollectionMutableInterface;
use KTXF\Mail\Collection\CollectionPropertiesBaseInterface;
use KTXF\Resource\Identifier\CollectionIdentifier;
/** /**
* Mail Service Collection Mutable Interface * Mail Service Collection Mutable Interface
@@ -41,48 +43,48 @@ interface ServiceCollectionMutableInterface {
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @param string|int|null $location Parent collection ID (null for root) * @param CollectionIdentifier $target Target collection identifier (parent)
* @param CollectionMutableInterface $collection Collection to create * @param CollectionPropertiesBaseInterface $properties Collection properties
* @param array $options Protocol-specific options * @param array $options Protocol-specific options
* *
* @return CollectionBaseInterface Created collection with assigned ID * @return CollectionBaseInterface Created collection with assigned ID
*/ */
public function collectionCreate(string|int|null $location, CollectionMutableInterface $collection, array $options = []): CollectionBaseInterface; public function collectionCreate(CollectionIdentifier|null $target, CollectionPropertiesBaseInterface $properties, array $options = []): CollectionBaseInterface;
/** /**
* Updates an existing collection * Updates an existing collection
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @param string|int $identifier Collection ID * @param CollectionIdentifier $target Target collection identifier
* @param CollectionMutableInterface $collection Updated collection data * @param CollectionPropertiesBaseInterface $properties Updated collection data
* *
* @return CollectionBaseInterface Updated collection * @return CollectionBaseInterface Updated collection
*/ */
public function collectionUpdate(string|int $identifier, CollectionMutableInterface $collection): CollectionBaseInterface; public function collectionUpdate(CollectionIdentifier $target, CollectionPropertiesBaseInterface $properties): CollectionBaseInterface;
/** /**
* Deletes a collection * Deletes a collection
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @param string|int $identifier Collection ID * @param CollectionIdentifier $target Target collection identifier
* @param bool $force Force deletion even if not empty * @param bool $force Force deletion even if not empty
* *
* @return CollectionBaseInterface|true Collection object on soft delete, true on hard delete * @return CollectionBaseInterface|true Collection object on soft delete, true on hard delete
*/ */
public function collectionDelete(string|int $identifier, bool $force = false): CollectionBaseInterface | true; public function collectionDelete(CollectionIdentifier $target, bool $force = false): CollectionBaseInterface | true;
/** /**
* Moves a collection to a new parent * Moves a collection to a new parent
* *
* @since 2025.05.01 * @since 2025.05.01
* *
* @param string|int $identifier Collection ID * @param CollectionIdentifier $source Source collection identifier
* @param string|int|null $targetLocation New parent ID (null for root) * @param CollectionIdentifier $target Target collection identifier
* *
* @return CollectionBaseInterface Moved collection * @return CollectionBaseInterface Moved collection
*/ */
public function collectionMove(string|int $identifier, string|int|null $targetLocation): CollectionBaseInterface; public function collectionMove(CollectionIdentifier $target, CollectionIdentifier $source): CollectionBaseInterface;
} }

View File

@@ -10,6 +10,11 @@ declare(strict_types=1);
namespace KTXF\Resource\Provider\Node; namespace KTXF\Resource\Provider\Node;
use DateTimeImmutable; use DateTimeImmutable;
use KTXF\Resource\Identifier\CollectionIdentifier;
use KTXF\Resource\Identifier\CollectionIdentifierInterface;
use KTXF\Resource\Identifier\EntityIdentifierInterface;
use KTXF\Resource\Identifier\ResourceIdentifier;
use KTXF\Resource\Identifier\ServiceIdentifier;
/** /**
* Abstract Node Base Class * Abstract Node Base Class
@@ -23,6 +28,7 @@ abstract class NodeBaseAbstract implements NodeBaseInterface {
/** /**
* Internal data storage * Internal data storage
*/ */
protected string $type = 'resource.node';
protected array $data = []; protected array $data = [];
public function __construct( public function __construct(
@@ -30,87 +36,96 @@ abstract class NodeBaseAbstract implements NodeBaseInterface {
protected readonly string|int $service, protected readonly string|int $service,
) { ) {
$this->data = [ $this->data = [
static::JSON_PROPERTY_PROVIDER => $this->provider, static::PROPERTY_TYPE => $this->type,
static::JSON_PROPERTY_SERVICE => $this->service, static::PROPERTY_PROVIDER => $this->provider,
static::JSON_PROPERTY_COLLECTION => null, static::PROPERTY_SERVICE => $this->service,
static::JSON_PROPERTY_IDENTIFIER => null, static::PROPERTY_COLLECTION => null,
static::JSON_PROPERTY_SIGNATURE => null, static::PROPERTY_IDENTIFIER => null,
static::JSON_PROPERTY_CREATED => null, static::PROPERTY_SIGNATURE => null,
static::JSON_PROPERTY_MODIFIED => null, static::PROPERTY_CREATED => null,
static::PROPERTY_MODIFIED => null,
]; ];
} }
/**
* @inheritDoc
*/
public function type(): string {
return static::RESOURCE_TYPE;
}
/**
* @inheritDoc
*/
public function provider(): string {
return $this->data[static::JSON_PROPERTY_PROVIDER];
}
/**
* @inheritDoc
*/
public function service(): string|int {
return $this->data[static::JSON_PROPERTY_SERVICE];
}
/**
* @inheritDoc
*/
public function collection(): string|int|null {
return $this->data[static::JSON_PROPERTY_COLLECTION] ?? null;
}
/**
* @inheritDoc
*/
public function identifier(): string|int|null {
return $this->data[static::JSON_PROPERTY_IDENTIFIER] ?? null;
}
/**
* @inheritDoc
*/
public function signature(): string|null {
return isset($this->data[static::JSON_PROPERTY_SIGNATURE])
? (string)$this->data[static::JSON_PROPERTY_SIGNATURE]
: null;
}
/**
* @inheritDoc
*/
public function created(): DateTimeImmutable|null {
return isset($this->data[static::JSON_PROPERTY_CREATED])
? new DateTimeImmutable($this->data[static::JSON_PROPERTY_CREATED])
: null;
}
/**
* @inheritDoc
*/
public function modified(): DateTimeImmutable|null {
return isset($this->data[static::JSON_PROPERTY_MODIFIED])
? new DateTimeImmutable($this->data[static::JSON_PROPERTY_MODIFIED])
: null;
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function jsonSerialize(): array { public function jsonSerialize(): array {
$data = $this->data; $data = $this->data;
$data[static::JSON_PROPERTY_PROPERTIES] = $this->getProperties()->jsonSerialize(); $data['provider'] = new ResourceIdentifier($this->data[static::PROPERTY_PROVIDER]);
$data['service'] = new ServiceIdentifier($this->data[static::PROPERTY_PROVIDER], $this->data[static::PROPERTY_SERVICE]);
$data['collection'] = isset($this->data[static::PROPERTY_COLLECTION])
? new CollectionIdentifier($this->data[static::PROPERTY_PROVIDER], $this->data[static::PROPERTY_SERVICE], $this->data[static::PROPERTY_COLLECTION])
: null;
$data['identifier'] = $this->nodeIdentifier();
$data[static::PROPERTY_PROPERTIES] = $this->getProperties()->jsonSerialize();
return $data; return $data;
} }
abstract protected function nodeIdentifier(): CollectionIdentifierInterface|EntityIdentifierInterface|null;
/**
* @inheritDoc
*/
public function type(): string {
return $this->data[static::PROPERTY_TYPE];
}
/**
* @inheritDoc
*/
public function provider(): string {
return $this->data[static::PROPERTY_PROVIDER];
}
/**
* @inheritDoc
*/
public function service(): string|int {
return $this->data[static::PROPERTY_SERVICE];
}
/**
* @inheritDoc
*/
public function collection(): string|int|null {
return $this->data[static::PROPERTY_COLLECTION] ?? null;
}
/**
* @inheritDoc
*/
public function identifier(): string|int|null {
return $this->data[static::PROPERTY_IDENTIFIER] ?? null;
}
/**
* @inheritDoc
*/
public function signature(): string|null {
return isset($this->data[static::PROPERTY_SIGNATURE])
? (string)$this->data[static::PROPERTY_SIGNATURE]
: null;
}
/**
* @inheritDoc
*/
public function created(): DateTimeImmutable|null {
return isset($this->data[static::PROPERTY_CREATED])
? new DateTimeImmutable($this->data[static::PROPERTY_CREATED])
: null;
}
/**
* @inheritDoc
*/
public function modified(): DateTimeImmutable|null {
return isset($this->data[static::PROPERTY_MODIFIED])
? new DateTimeImmutable($this->data[static::PROPERTY_MODIFIED])
: null;
}
/** /**
* @inheritDoc * @inheritDoc
*/ */

View File

@@ -19,15 +19,15 @@ use KTXF\Json\JsonSerializable;
*/ */
interface NodeBaseInterface extends JsonSerializable { interface NodeBaseInterface extends JsonSerializable {
public const RESOURCE_TYPE = 'resource.node'; public const PROPERTY_TYPE = 'resource.node';
public const JSON_PROPERTY_PROVIDER = 'provider'; public const PROPERTY_PROVIDER = 'provider';
public const JSON_PROPERTY_SERVICE = 'service'; public const PROPERTY_SERVICE = 'service';
public const JSON_PROPERTY_COLLECTION = 'collection'; public const PROPERTY_COLLECTION = 'collection';
public const JSON_PROPERTY_IDENTIFIER = 'identifier'; public const PROPERTY_IDENTIFIER = 'identifier';
public const JSON_PROPERTY_SIGNATURE = 'signature'; public const PROPERTY_SIGNATURE = 'signature';
public const JSON_PROPERTY_CREATED = 'created'; public const PROPERTY_CREATED = 'created';
public const JSON_PROPERTY_MODIFIED = 'modified'; public const PROPERTY_MODIFIED = 'modified';
public const JSON_PROPERTY_PROPERTIES = 'properties'; public const PROPERTY_PROPERTIES = 'properties';
/** /**
* Node type * Node type

View File

@@ -28,56 +28,56 @@ abstract class NodeMutableAbstract extends NodeBaseAbstract implements NodeMutab
$this->data = []; $this->data = [];
if (isset($data[static::JSON_PROPERTY_COLLECTION])) { if (isset($data[static::PROPERTY_COLLECTION])) {
if (!is_string($data[static::JSON_PROPERTY_COLLECTION]) && !is_int($data[static::JSON_PROPERTY_COLLECTION])) { if (!is_string($data[static::PROPERTY_COLLECTION]) && !is_int($data[static::PROPERTY_COLLECTION])) {
throw new \InvalidArgumentException("Collection must be a string or integer"); throw new \InvalidArgumentException("Collection must be a string or integer");
} }
$this->data[static::JSON_PROPERTY_COLLECTION] = $data[static::JSON_PROPERTY_COLLECTION]; $this->data[static::PROPERTY_COLLECTION] = $data[static::PROPERTY_COLLECTION];
} else { } else {
$this->data[static::JSON_PROPERTY_COLLECTION] = null; $this->data[static::PROPERTY_COLLECTION] = null;
} }
if (isset($data[static::JSON_PROPERTY_IDENTIFIER])) { if (isset($data[static::PROPERTY_IDENTIFIER])) {
if (!is_string($data[static::JSON_PROPERTY_IDENTIFIER]) && !is_int($data[static::JSON_PROPERTY_IDENTIFIER])) { if (!is_string($data[static::PROPERTY_IDENTIFIER]) && !is_int($data[static::PROPERTY_IDENTIFIER])) {
throw new \InvalidArgumentException("Identifier must be a string or integer"); throw new \InvalidArgumentException("Identifier must be a string or integer");
} }
$this->data[static::JSON_PROPERTY_IDENTIFIER] = $data[static::JSON_PROPERTY_IDENTIFIER]; $this->data[static::PROPERTY_IDENTIFIER] = $data[static::PROPERTY_IDENTIFIER];
} else { } else {
$this->data[static::JSON_PROPERTY_IDENTIFIER] = null; $this->data[static::PROPERTY_IDENTIFIER] = null;
} }
if (isset($data[static::JSON_PROPERTY_SIGNATURE])) { if (isset($data[static::PROPERTY_SIGNATURE])) {
if (!is_string($data[static::JSON_PROPERTY_SIGNATURE]) && !is_int($data[static::JSON_PROPERTY_SIGNATURE])) { if (!is_string($data[static::PROPERTY_SIGNATURE]) && !is_int($data[static::PROPERTY_SIGNATURE])) {
throw new \InvalidArgumentException("Signature must be a string or integer"); throw new \InvalidArgumentException("Signature must be a string or integer");
} }
$this->data[static::JSON_PROPERTY_SIGNATURE] = $data[static::JSON_PROPERTY_SIGNATURE]; $this->data[static::PROPERTY_SIGNATURE] = $data[static::PROPERTY_SIGNATURE];
} else { } else {
$this->data[static::JSON_PROPERTY_SIGNATURE] = null; $this->data[static::PROPERTY_SIGNATURE] = null;
} }
if (isset($data[static::JSON_PROPERTY_CREATED])) { if (isset($data[static::PROPERTY_CREATED])) {
if (!is_string($data[static::JSON_PROPERTY_CREATED])) { if (!is_string($data[static::PROPERTY_CREATED])) {
throw new \InvalidArgumentException("Created date must be a string in ISO 8601 format"); throw new \InvalidArgumentException("Created date must be a string in ISO 8601 format");
} }
$this->data[static::JSON_PROPERTY_CREATED] = $data[static::JSON_PROPERTY_CREATED]; $this->data[static::PROPERTY_CREATED] = $data[static::PROPERTY_CREATED];
} else { } else {
$this->data[static::JSON_PROPERTY_CREATED] = null; $this->data[static::PROPERTY_CREATED] = null;
} }
if (isset($data[static::JSON_PROPERTY_MODIFIED])) { if (isset($data[static::PROPERTY_MODIFIED])) {
if (!is_string($data[static::JSON_PROPERTY_MODIFIED])) { if (!is_string($data[static::PROPERTY_MODIFIED])) {
throw new \InvalidArgumentException("Modified date must be a string in ISO 8601 format"); throw new \InvalidArgumentException("Modified date must be a string in ISO 8601 format");
} }
$this->data[static::JSON_PROPERTY_MODIFIED] = $data[static::JSON_PROPERTY_MODIFIED]; $this->data[static::PROPERTY_MODIFIED] = $data[static::PROPERTY_MODIFIED];
} else { } else {
$this->data[static::JSON_PROPERTY_MODIFIED] = null; $this->data[static::PROPERTY_MODIFIED] = null;
} }
if (isset($data[static::JSON_PROPERTY_PROPERTIES])) { if (isset($data[static::PROPERTY_PROPERTIES])) {
if (!is_array($data[static::JSON_PROPERTY_PROPERTIES])) { if (!is_array($data[static::PROPERTY_PROPERTIES])) {
throw new \InvalidArgumentException("Properties must be an array"); throw new \InvalidArgumentException("Properties must be an array");
} }
$this->getProperties()->jsonDeserialize($data[static::JSON_PROPERTY_PROPERTIES]); $this->getProperties()->jsonDeserialize($data[static::PROPERTY_PROPERTIES]);
} }
return $this; return $this;

View File

@@ -18,16 +18,17 @@ namespace KTXF\Resource\Provider\Node;
*/ */
abstract class NodePropertiesBaseAbstract implements NodePropertiesBaseInterface { abstract class NodePropertiesBaseAbstract implements NodePropertiesBaseInterface {
protected string $type = 'resource.data';
protected array $data = []; protected array $data = [];
public function __construct(array $data) { public function __construct(array $data) {
if (!isset($data[static::JSON_PROPERTY_TYPE])) { if (!isset($data[static::PROPERTY_TYPE])) {
$data[static::JSON_PROPERTY_TYPE] = static::JSON_TYPE; $data[static::PROPERTY_TYPE] = $this->type;
} }
if (!isset($data[static::JSON_PROPERTY_SCHEMA])) { if (!isset($data[static::PROPERTY_SCHEMA])) {
$data[static::JSON_PROPERTY_SCHEMA] = 1; $data[static::PROPERTY_SCHEMA] = 1;
} }
$this->data = $data; $this->data = $data;
@@ -44,14 +45,14 @@ abstract class NodePropertiesBaseAbstract implements NodePropertiesBaseInterface
* @inheritDoc * @inheritDoc
*/ */
public function type(): string { public function type(): string {
return $this->data[static::JSON_PROPERTY_TYPE]; return $this->data[static::PROPERTY_TYPE];
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function schema(): int { public function schema(): int {
return $this->data[static::JSON_PROPERTY_SCHEMA]; return $this->data[static::PROPERTY_SCHEMA];
} }
} }

View File

@@ -18,11 +18,8 @@ use JsonSerializable;
*/ */
interface NodePropertiesBaseInterface extends JsonSerializable { interface NodePropertiesBaseInterface extends JsonSerializable {
public const RESOURCE_TYPE = 'resource.data'; public const PROPERTY_TYPE = '@type';
public const PROPERTY_SCHEMA = 'schema';
public const JSON_TYPE = 'resource.data';
public const JSON_PROPERTY_TYPE = '@type';
public const JSON_PROPERTY_SCHEMA = 'schema';
/** /**
* Get resource node properties type * Get resource node properties type

View File

@@ -16,6 +16,4 @@ use KTXF\Json\JsonDeserializable;
* *
* @since 2025.05.01 * @since 2025.05.01
*/ */
interface NodePropertiesMutableInterface extends NodePropertiesBaseInterface, JsonDeserializable { interface NodePropertiesMutableInterface extends NodePropertiesBaseInterface, JsonDeserializable {}
}