generated from Nodarx/template
Merge pull request 'feat: implement entity mutable interface' (#11) from feat/implement-EntityMutableInterface into main
All checks were successful
Renovate / renovate (push) Successful in 1m41s
All checks were successful
Renovate / renovate (push) Successful in 1m41s
Reviewed-on: #11
This commit was merged in pull request #11.
This commit is contained in:
@@ -112,20 +112,33 @@ class MessageProperties extends MessagePropertiesMutableAbstract {
|
||||
return $this;
|
||||
}
|
||||
|
||||
private static function normalizeFlag(string $flag): string
|
||||
public function toImap(): array
|
||||
{
|
||||
$flag = ltrim($flag, '\\');
|
||||
$message = [];
|
||||
|
||||
return match (strtolower($flag)) {
|
||||
'seen' => 'read',
|
||||
'flagged' => 'flagged',
|
||||
'answered' => 'answered',
|
||||
'draft' => 'draft',
|
||||
'deleted' => 'deleted',
|
||||
default => strtolower($flag),
|
||||
};
|
||||
if (isset($this->data['flags'])) {
|
||||
$message['flags'] = $this->data['flags'];
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hydrate from store array
|
||||
*/
|
||||
public function fromStore(array $data): static {
|
||||
$this->data = $data;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize to store array
|
||||
*/
|
||||
public function toStore(): array {
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a string to UTF-8 from the given charset.
|
||||
*
|
||||
@@ -181,18 +194,4 @@ class MessageProperties extends MessagePropertiesMutableAbstract {
|
||||
$attachments[] = $part->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize to store array
|
||||
*/
|
||||
public function toStore(): array {
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hydrate from store array
|
||||
*/
|
||||
public function fromStore(array $data): static {
|
||||
$this->data = $data;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,10 +12,13 @@ namespace KTXM\ProviderImap\Providers;
|
||||
use Generator;
|
||||
use KTXF\Mail\Collection\CollectionBaseInterface;
|
||||
use KTXF\Mail\Collection\CollectionMutableInterface;
|
||||
use KTXF\Mail\Entity\EntityBaseInterface;
|
||||
use KTXF\Mail\Entity\EntityMutableInterface;
|
||||
use KTXF\Mail\Object\Address;
|
||||
use KTXF\Mail\Object\AddressInterface;
|
||||
use KTXF\Mail\Service\ServiceBaseInterface;
|
||||
use KTXF\Mail\Service\ServiceCollectionMutableInterface;
|
||||
use KTXF\Mail\Service\ServiceEntityMutableInterface;
|
||||
use KTXF\Mail\Service\ServiceConfigurableInterface;
|
||||
use KTXF\Mail\Service\ServiceMutableInterface;
|
||||
use KTXF\Resource\Provider\ResourceServiceIdentityInterface;
|
||||
@@ -37,12 +40,13 @@ use KTXM\ProviderImap\Service\Remote\RemoteMailService;
|
||||
use KTXM\ProviderImap\Service\Remote\RemoteService;
|
||||
use KTXM\ProviderImap\Providers\CollectionResource;
|
||||
use KTXF\Mail\Collection\CollectionRoles;
|
||||
use KTXF\Mail\Object\MessagePropertiesMutableInterface;
|
||||
use KTXM\ProviderImap\Providers\EntityResource;
|
||||
|
||||
/**
|
||||
* IMAP Mail Service
|
||||
*/
|
||||
class Service implements ServiceBaseInterface, ServiceMutableInterface, ServiceConfigurableInterface, ServiceCollectionMutableInterface
|
||||
class Service implements ServiceBaseInterface, ServiceMutableInterface, ServiceConfigurableInterface, ServiceCollectionMutableInterface, ServiceEntityMutableInterface
|
||||
{
|
||||
public const JSON_TYPE = ServiceBaseInterface::JSON_TYPE;
|
||||
|
||||
@@ -354,6 +358,8 @@ class Service implements ServiceBaseInterface, ServiceMutableInterface, ServiceC
|
||||
{
|
||||
$this->initialize();
|
||||
|
||||
$list = [];
|
||||
|
||||
foreach ($this->mailService->collectionList($location, $filter, $sort) as $mailbox) {
|
||||
$resource = $this->collectionFresh();
|
||||
$resource->fromImap($mailbox);
|
||||
@@ -377,10 +383,10 @@ class Service implements ServiceBaseInterface, ServiceMutableInterface, ServiceC
|
||||
{
|
||||
$this->initialize();
|
||||
|
||||
$mailboxes = $this->collectionList();
|
||||
$mailboxes = $this->collectionList(null);
|
||||
$extant = [];
|
||||
foreach ($identifiers as $id) {
|
||||
$extant[(string) $id] = isset($existing[(string) $id]);
|
||||
$extant[(string) $id] = isset($mailboxes[(string) $id]);
|
||||
}
|
||||
return $extant;
|
||||
}
|
||||
@@ -400,12 +406,12 @@ class Service implements ServiceBaseInterface, ServiceMutableInterface, ServiceC
|
||||
return $collection;
|
||||
}
|
||||
|
||||
public function collectionFresh(): CollectionMutableInterface
|
||||
public function collectionFresh(): CollectionResource
|
||||
{
|
||||
return new CollectionResource($this->provider(), $this->identifier());
|
||||
}
|
||||
|
||||
public function collectionCreate(string|int|null $location, CollectionMutableInterface $collection, array $options = []): CollectionBaseInterface
|
||||
public function collectionCreate(string|int|null $location, CollectionMutableInterface $collection, array $options = []): CollectionBaseInterface
|
||||
{
|
||||
$this->initialize();
|
||||
|
||||
@@ -540,7 +546,7 @@ class Service implements ServiceBaseInterface, ServiceMutableInterface, ServiceC
|
||||
};
|
||||
}
|
||||
|
||||
public function entityFetch(string|int $collection, string|int ...$identifiers): array
|
||||
public function entityFetch(string|int $collection, string|int ...$identifiers): array
|
||||
{
|
||||
$this->initialize();
|
||||
|
||||
@@ -571,10 +577,20 @@ class Service implements ServiceBaseInterface, ServiceMutableInterface, ServiceC
|
||||
return new EntityResource($this->provider(), $this->identifier());
|
||||
}
|
||||
|
||||
public function entityDelete(EntityIdentifier ...$identifiers): array
|
||||
public function entityCreate(CollectionIdentifier $target, MessagePropertiesMutableInterface $properties, array $options = []): EntityResource
|
||||
{
|
||||
return $this->entityFresh();
|
||||
}
|
||||
|
||||
public function entityModify(EntityIdentifier $target, MessagePropertiesMutableInterface $properties): EntityResource
|
||||
{
|
||||
return $this->entityFresh();
|
||||
}
|
||||
|
||||
public function entityDelete(EntityIdentifier ...$targets): array
|
||||
{
|
||||
// validate identifiers and group by collection
|
||||
$identifiers = $this->groupEntitiesByCollection(...$identifiers);
|
||||
$targets = $this->groupEntitiesByCollection(...$targets);
|
||||
|
||||
// determine delete mode and target collection (e.g. Trash) if applicable
|
||||
$deleteMode = $this->auxiliary['deleteMode'] ?? 'soft';
|
||||
@@ -606,7 +622,7 @@ class Service implements ServiceBaseInterface, ServiceMutableInterface, ServiceC
|
||||
|
||||
// entities need to be moved or deleted by collection
|
||||
$list = [];
|
||||
foreach ($identifiers as $sourceCollection => $sourceEntities) {
|
||||
foreach ($targets as $sourceCollection => $sourceEntities) {
|
||||
if ($deleteMode === 'soft' && $sourceCollection === $deleteTargetNative) {
|
||||
continue;
|
||||
}
|
||||
@@ -631,7 +647,30 @@ class Service implements ServiceBaseInterface, ServiceMutableInterface, ServiceC
|
||||
return $results;
|
||||
}
|
||||
|
||||
public function entityMove(CollectionIdentifier $target, EntityIdentifier ...$identifiers): array
|
||||
public function entityPatch(MessagePropertiesMutableInterface $properties, EntityIdentifier ...$targets): array
|
||||
{
|
||||
// validate identifiers and group by collection
|
||||
$targets = $this->groupEntitiesByCollection(...$targets);
|
||||
|
||||
// move entities on remote store and construct result map
|
||||
$this->initialize();
|
||||
|
||||
$list = [];
|
||||
|
||||
foreach ($targets as $targetCollection => $targetIdentifiers) {
|
||||
$uids = array_keys($targetIdentifiers);
|
||||
|
||||
$mutations = $this->mailService->entityPatch($targetCollection, $properties, ...$uids);
|
||||
|
||||
foreach ($uids as $uid) {
|
||||
$list[(string)$targetIdentifiers[$uid]] = ['disposition' => 'patched'];
|
||||
}
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
public function entityCopy(CollectionIdentifier $target, EntityIdentifier ...$sources): array
|
||||
{
|
||||
// validate target belongs to this service
|
||||
if ($target->provider() !== $this->provider() || $target->service() !== $this->identifier()) {
|
||||
@@ -639,12 +678,47 @@ class Service implements ServiceBaseInterface, ServiceMutableInterface, ServiceC
|
||||
}
|
||||
|
||||
// validate identifiers and group by collection
|
||||
$identifiers = $this->groupEntitiesByCollection(...$identifiers);
|
||||
$sources = $this->groupEntitiesByCollection(...$sources);
|
||||
|
||||
// copy entities on remote store and construct result map
|
||||
$this->initialize();
|
||||
|
||||
$list = [];
|
||||
|
||||
foreach ($sources as $sourceCollection => $sourceEntities) {
|
||||
$uids = array_keys($sourceEntities);
|
||||
|
||||
$mutations = $this->mailService->entityCopy($target->collection(), $sourceCollection, ...$uids);
|
||||
|
||||
foreach ($uids as $uid) {
|
||||
$mutatedUid = $mutations[$uid] ?? null;
|
||||
$list[(string)$sourceEntities[$uid]] = [
|
||||
'disposition' => $mutatedUid !== null ? 'copied' : 'error',
|
||||
'destination' => $target,
|
||||
'mutation' => $mutatedUid !== null ? new EntityIdentifier($this->provider(), $this->identifier(), $target->collection(), $mutatedUid) : null,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $list;
|
||||
}
|
||||
|
||||
public function entityMove(CollectionIdentifier $target, EntityIdentifier ...$sources): array
|
||||
{
|
||||
// validate target belongs to this service
|
||||
if ($target->provider() !== $this->provider() || $target->service() !== $this->identifier()) {
|
||||
throw new \InvalidArgumentException('Target collection does not belong to this service: ' . $target);
|
||||
}
|
||||
|
||||
// validate identifiers and group by collection
|
||||
$sources = $this->groupEntitiesByCollection(...$sources);
|
||||
|
||||
// move entities on remote store and construct result map
|
||||
$this->initialize();
|
||||
|
||||
$list = [];
|
||||
foreach ($identifiers as $sourceCollection => $sourceEntities) {
|
||||
|
||||
foreach ($sources as $sourceCollection => $sourceEntities) {
|
||||
$uids = array_keys($sourceEntities);
|
||||
|
||||
$mutations = $this->mailService->entityMove($target->collection(), $sourceCollection, ...$uids);
|
||||
|
||||
@@ -59,8 +59,6 @@ class RemoteMailService
|
||||
|
||||
public function __construct(
|
||||
private readonly Client $client,
|
||||
private readonly string $provider,
|
||||
private readonly string|int $service,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -330,6 +328,31 @@ class RemoteMailService
|
||||
return array_fill_keys($uids, true);
|
||||
}
|
||||
|
||||
public function entityPatch(string $collection, array $flagsToAdd = [], array $flagsToRemove = [], int ...$uids): void
|
||||
{
|
||||
if (empty($uids)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->client->perform(new SelectCommand($collection, false));
|
||||
|
||||
if (!empty($flagsToAdd)) {
|
||||
$this->client->perform(new StoreCommand(
|
||||
FetchTarget::uid(SequenceSet::items(...array_values($uids))),
|
||||
$flagsToAdd,
|
||||
'+',
|
||||
));
|
||||
}
|
||||
|
||||
if (!empty($flagsToRemove)) {
|
||||
$this->client->perform(new StoreCommand(
|
||||
FetchTarget::uid(SequenceSet::items(...array_values($uids))),
|
||||
$flagsToRemove,
|
||||
'-',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
public function entityMove(string $targetCollection, string $sourceCollection, int ...$uids): array
|
||||
{
|
||||
if (empty($uids)) {
|
||||
|
||||
Reference in New Issue
Block a user