98 lines
4.4 KiB
PHP
98 lines
4.4 KiB
PHP
<?php
|
|
|
|
namespace App\Containers\Dashboard\Tasks\Email;
|
|
|
|
use App\Containers\Dashboard\Exceptions\EmailFetchException;
|
|
use App\Containers\Dashboard\Traits\MemoryAwareTrait;
|
|
use Webklex\PHPIMAP\Folder;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
/**
|
|
* Получение непрочитанных писем из папки
|
|
*
|
|
* OPTIMIZATION: Загружает только заголовки писем (без тел и вложений).
|
|
* Тела загружаются лениво только при необходимости в DownloadAttachmentsTask.
|
|
*/
|
|
class FetchUnreadEmailsTask
|
|
{
|
|
use MemoryAwareTrait;
|
|
|
|
/**
|
|
* Получить непрочитанные письма
|
|
*
|
|
* @param Folder $folder IMAP папка
|
|
* @param int|null $limit Лимит сообщений (null = использовать конфиг)
|
|
* @return array Массив писем (только метаданные, без тел)
|
|
* @throws EmailFetchException При ошибках IMAP-подключения
|
|
*/
|
|
public function run(Folder $folder, ?int $limit = null): array
|
|
{
|
|
$limit = $limit ?? config('imap.options.fetch_limit', 20);
|
|
|
|
Log::channel('email')->debug('Получение непрочитанных писем', [
|
|
'folder' => $folder->full_name ?? $folder->name ?? 'unknown',
|
|
'limit' => $limit,
|
|
]);
|
|
|
|
try {
|
|
// NOTE: setFetchBody(true) необходим для загрузки структуры письма (вложения)
|
|
// Контроль памяти осуществляется через limit() и batch-обработку в Action
|
|
$query = $folder->messages()
|
|
->unseen()
|
|
->setFetchBody(true) // Загружаем структуру (нужна для вложений)
|
|
->setFetchFlags(false); // Флаги не нужны
|
|
|
|
// Применяем лимит для предотвращения переполнения памяти
|
|
if ($limit > 0) {
|
|
$query->limit($limit);
|
|
}
|
|
|
|
$messages = $query->get();
|
|
|
|
$emails = [];
|
|
foreach ($messages as $message) {
|
|
// OPTIMIZATION: Извлекаем только метаданные (не загружаем тело)
|
|
$from = $message->getFrom()[0] ?? null;
|
|
$subjectAttr = $message->getSubject();
|
|
|
|
$emails[] = [
|
|
'message' => $message,
|
|
'message_id' => $message->getMessageId(),
|
|
'uid' => $message->getUid(),
|
|
'from_email' => $from?->mail ?? null,
|
|
'from_name' => $from?->name ?? null,
|
|
// FIX: Attribute объект нужно конвертировать в строку
|
|
'subject' => $subjectAttr instanceof \Webklex\PHPIMAP\Attribute ? (string) $subjectAttr : ($subjectAttr ?? 'Без темы'),
|
|
'date' => $message->getDate(),
|
|
// NOTE: hasAttachments() может быть неточным без загрузки структуры
|
|
'has_attachments' => $message->hasAttachments(),
|
|
'size' => $message->getSize(),
|
|
];
|
|
}
|
|
|
|
// OPTIMIZATION: Логируем память после загрузки
|
|
$this->logMemoryUsage('after_fetching_emails', [
|
|
'emails_count' => count($emails),
|
|
]);
|
|
|
|
Log::channel('email')->debug('Получены письма', [
|
|
'count' => count($emails),
|
|
'folder' => $folder->full_name ?? $folder->name ?? 'unknown',
|
|
]);
|
|
|
|
return $emails;
|
|
} catch (EmailFetchException $e) {
|
|
// Пробрасываем наши кастомные исключения
|
|
throw $e;
|
|
} catch (\Exception $e) {
|
|
Log::channel('email')->error('Ошибка получения писем', [
|
|
'error' => $e->getMessage(),
|
|
'trace' => $e->getTraceAsString(),
|
|
]);
|
|
|
|
// Пробрасываем как EmailFetchException для правильной обработки в Action
|
|
throw EmailFetchException::connectionFailed('Failed to fetch emails: ' . $e->getMessage(), 0, $e);
|
|
}
|
|
}
|
|
}
|