refactor: fetch command

Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
2026-09-25 11:42:13 -04:00
parent 9a86292bcf
commit 56fc949e83
4 changed files with 21 additions and 14 deletions
@@ -6,7 +6,7 @@ namespace KTXM\ProviderImap\Client\Protocol\Command;
use KTXM\ProviderImap\Client\Protocol\IdentifierMode; use KTXM\ProviderImap\Client\Protocol\IdentifierMode;
use KTXM\ProviderImap\Client\Protocol\Parser\FetchResponseParser; use KTXM\ProviderImap\Client\Protocol\FetchResultReader;
use Generator; use Generator;
use KTXM\ProviderImap\Client\Protocol\Command\Argument\MessageTarget; use KTXM\ProviderImap\Client\Protocol\Command\Argument\MessageTarget;
use KTXM\ProviderImap\Client\Protocol\Command\Argument\FetchOptions; use KTXM\ProviderImap\Client\Protocol\Command\Argument\FetchOptions;
@@ -65,6 +65,6 @@ final class FetchManyCommand implements CommandInterface
throw new ImapException('FETCH requires a selected mailbox.'); throw new ImapException('FETCH requires a selected mailbox.');
} }
return (new FetchResponseParser())->parseMany($responses); return (new FetchResultReader())->readMany($responses);
} }
} }
@@ -6,7 +6,7 @@ namespace KTXM\ProviderImap\Client\Protocol\Command;
use KTXM\ProviderImap\Client\Protocol\IdentifierMode; use KTXM\ProviderImap\Client\Protocol\IdentifierMode;
use KTXM\ProviderImap\Client\Protocol\Parser\FetchResponseParser; use KTXM\ProviderImap\Client\Protocol\FetchResultReader;
use KTXM\ProviderImap\Client\Protocol\Command\Argument\MessageTarget; use KTXM\ProviderImap\Client\Protocol\Command\Argument\MessageTarget;
use KTXM\ProviderImap\Client\Protocol\Command\Argument\FetchOptions; use KTXM\ProviderImap\Client\Protocol\Command\Argument\FetchOptions;
use KTXM\ProviderImap\Client\ImapException; use KTXM\ProviderImap\Client\ImapException;
@@ -60,6 +60,6 @@ final class FetchOneCommand implements CommandInterface
throw new ImapException('FETCH requires a selected mailbox.'); throw new ImapException('FETCH requires a selected mailbox.');
} }
return (new FetchResponseParser())->parseOne($responses); return (new FetchResultReader())->readOne($responses);
} }
} }
@@ -2,23 +2,25 @@
declare(strict_types=1); declare(strict_types=1);
namespace KTXM\ProviderImap\Client\Protocol\Parser; namespace KTXM\ProviderImap\Client\Protocol;
use Generator; use Generator;
use KTXM\ProviderImap\Client\ImapException; use KTXM\ProviderImap\Client\ImapException;
use KTXM\ProviderImap\Client\Message; use KTXM\ProviderImap\Client\Message;
use KTXM\ProviderImap\Client\Protocol\Parser\MessageParser; use KTXM\ProviderImap\Client\Protocol\Parser\FetchMessageParser;
use KTXM\ProviderImap\Client\Protocol\Response\TaggedResponse; use KTXM\ProviderImap\Client\Protocol\Response\TaggedResponse;
use KTXM\ProviderImap\Client\Protocol\Response\UntaggedResponse; use KTXM\ProviderImap\Client\Protocol\Response\UntaggedResponse;
use KTXM\ProviderImap\Client\Protocol\ResponseStream;
final class FetchResponseParser /**
* Reads FETCH messages from a response stream and validates command completion.
*/
final class FetchResultReader
{ {
public function parseOne(ResponseStream $responses): Message public function readOne(ResponseStream $responses): Message
{ {
$message = null; $message = null;
foreach ($this->parseMany($responses) as $summary) { foreach ($this->readMany($responses) as $summary) {
if ($message !== null) { if ($message !== null) {
throw new ImapException('FETCH returned multiple messages for a single-message request.'); throw new ImapException('FETCH returned multiple messages for a single-message request.');
} }
@@ -34,13 +36,15 @@ final class FetchResponseParser
} }
/** /**
* Consume the generator fully to reach and validate the tagged completion.
*
* @return Generator<int, Message> * @return Generator<int, Message>
*/ */
public function parseMany(ResponseStream $responses): Generator public function readMany(ResponseStream $responses): Generator
{ {
foreach ($responses as $response) { foreach ($responses as $response) {
if ($response instanceof UntaggedResponse && MessageParser::isFetchMessage($response->raw())) { if ($response instanceof UntaggedResponse && FetchMessageParser::isFetchMessage($response->raw())) {
yield MessageParser::parse($response->raw()); yield FetchMessageParser::parse($response->raw());
continue; continue;
} }
@@ -10,7 +10,10 @@ use KTXM\ProviderImap\Client\MessageAddress;
use KTXM\ProviderImap\Client\MessagePart; use KTXM\ProviderImap\Client\MessagePart;
use DateTimeInterface; use DateTimeInterface;
final class MessageParser /**
* Decodes an individual untagged FETCH response into a message.
*/
final class FetchMessageParser
{ {
public static function isFetchMessage(string $raw): bool public static function isFetchMessage(string $raw): bool
{ {