Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
95.24% covered (success)
95.24%
40 / 42
66.67% covered (warning)
66.67%
2 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
InboundEmailSyncTask
95.12% covered (success)
95.12%
39 / 41
66.67% covered (warning)
66.67%
2 / 3
6
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
1 / 1
2
 run
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
2
 resolvePdo
66.67% covered (warning)
66.67%
4 / 6
0.00% covered (danger)
0.00%
0 / 1
2.15
1<?php
2
3declare(strict_types=1);
4
5/** @license For full copyright and license information, please see the LICENSE.md file. */
6
7namespace App\Modules\Mail\Task;
8
9defined('AMMONLY_APP') || exit('Direct script access is forbidden.');
10
11use App\Core\Cron\CronTaskInterface;
12use App\Core\Database\MultiDbRouter;
13use App\Core\Engine\Infrastructure\Repository\SqlAuditRepository;
14use App\Core\Engine\Infrastructure\Settings\EngineSettings;
15use App\Core\Event\SystemEventDispatcher;
16use App\Core\Security\Encryption\AesGcmEncryptionService;
17use App\Modules\Automation\Application\Listener\WorkflowRecordLifecycleListener;
18use App\Modules\Automation\Application\Service\WorkflowDagEngine;
19use App\Modules\Automation\Infrastructure\Repository\SqlWorkflowRepository;
20use App\Modules\Mail\Application\Contract\InboundEmailSyncServiceInterface;
21use App\Modules\Mail\Application\Service\InboundEmailSyncService;
22use App\Modules\Mail\Infrastructure\Protocol\MailProtocolDriverRegistry;
23use App\Modules\Mail\Infrastructure\Repository\SqlMailRepository;
24use App\Shared\Infrastructure\Config\InstallerConfigLoader;
25use PDO;
26use Throwable;
27
28/**
29 * Background Cron Task for Inbound Email Polling & Workflow Triggering.
30 *
31 * Connects to active inbound mailboxes over IMAP, creates email records,
32 * and triggers automated workflows for incoming support tickets.
33 *
34 * @package App\Modules\Mail\Task
35 */
36final class InboundEmailSyncTask implements CronTaskInterface
37{
38    private InboundEmailSyncServiceInterface $syncService;
39
40    /**
41     * InboundEmailSyncTask constructor.
42     *
43     * @param InboundEmailSyncServiceInterface|null $syncService Optional sync service instance.
44     * @param PDO|null                              $pdo         Optional database connection.
45     * @param string                                $tablePrefix Database table prefix.
46     */
47    public function __construct(
48        ?InboundEmailSyncServiceInterface $syncService = null,
49        ?PDO $pdo = null,
50        string $tablePrefix = 'a_'
51    ) {
52        if ($syncService !== null) {
53            $this->syncService = $syncService;
54            return;
55        }
56
57        $resolvedPdo = $pdo ?? $this->resolvePdo();
58        $mailRepo = new SqlMailRepository($resolvedPdo, $tablePrefix);
59        $encryption = new AesGcmEncryptionService();
60        $driverRegistry = new MailProtocolDriverRegistry();
61
62        $auditRepo = new SqlAuditRepository($resolvedPdo, $tablePrefix);
63        $engineSettings = new EngineSettings($resolvedPdo, $tablePrefix);
64        $workflowRepo = new SqlWorkflowRepository($resolvedPdo, $tablePrefix);
65        $workflowEngine = new WorkflowDagEngine($workflowRepo, $resolvedPdo, $tablePrefix);
66        $workflowListener = new WorkflowRecordLifecycleListener($workflowEngine);
67        $dispatcher = new SystemEventDispatcher($auditRepo, $engineSettings, null, $workflowListener);
68
69        $this->syncService = new InboundEmailSyncService(
70            $resolvedPdo,
71            $mailRepo,
72            $encryption,
73            $driverRegistry,
74            $dispatcher,
75            $tablePrefix
76        );
77    }
78
79    /**
80     * Executes inbound mailbox synchronization.
81     *
82     * @return string Execution summary message.
83     */
84    public function run(): string
85    {
86        $result = $this->syncService->syncInboundMailboxes();
87        $checked = $result['mailboxes_checked'];
88        $imported = $result['emails_imported'];
89        $merged = $result['duplicates_merged'] ?? 0;
90        $errors = $result['errors'];
91
92        $summary = sprintf(
93            'Inbound email sync: %d mailboxes checked, %d emails imported, %d co-owners merged.',
94            $checked,
95            $imported,
96            $merged
97        );
98
99        if (!empty($errors)) {
100            $summary .= sprintf(' Errors: %s', implode('; ', $errors));
101        }
102
103        return $summary;
104    }
105
106    /**
107     * Resolves default PDO connection using installer config.
108     *
109     * @return PDO Database handle.
110     */
111    private function resolvePdo(): PDO
112    {
113        try {
114            $config = InstallerConfigLoader::load();
115            $dbParams = $config['db'] ?? [];
116
117            $router = new MultiDbRouter(['default' => $dbParams]);
118            return $router->getConnection('default');
119        } catch (Throwable) {
120            return new PDO('sqlite::memory:');
121        }
122    }
123}