Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
52.22% |
47 / 90 |
|
46.15% |
6 / 13 |
CRAP | |
0.00% |
0 / 1 |
| BaseController | |
52.22% |
47 / 90 |
|
46.15% |
6 / 13 |
195.49 | |
0.00% |
0 / 1 |
| __construct | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
| getLogList | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| clearLogList | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| getSpendTime | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
| getNow | |
75.00% |
3 / 4 |
|
0.00% |
0 / 1 |
2.06 | |||
| getHttp | |
75.00% |
3 / 4 |
|
0.00% |
0 / 1 |
2.06 | |||
| sendMailer | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
6 | |||
| removeEntityOlderThanOneHour | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
2 | |||
| deleteEntityFromQueue | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
2 | |||
| testEntity | |
36.36% |
8 / 22 |
|
0.00% |
0 / 1 |
19.63 | |||
| monitorProcesses | |
0.00% |
0 / 19 |
|
0.00% |
0 / 1 |
90 | |||
| log | |
90.91% |
10 / 11 |
|
0.00% |
0 / 1 |
2.00 | |||
| convertCollectionToArray | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
6 | |||
| 1 | <?php |
| 2 | |
| 3 | /** |
| 4 | * |
| 5 | * @package Zmsmessaging |
| 6 | * |
| 7 | */ |
| 8 | |
| 9 | namespace BO\Zmsmessaging; |
| 10 | |
| 11 | use BO\Zmsentities\Mail; |
| 12 | use BO\Zmsentities\Mimepart; |
| 13 | use BO\Zmsentities\Schema\Entity; |
| 14 | use BO\Mellon\Validator; |
| 15 | use BO\Zmsclient\Http; |
| 16 | |
| 17 | class BaseController |
| 18 | { |
| 19 | protected mixed $verbose = false; |
| 20 | protected static array $logList = []; |
| 21 | protected mixed $workstation = null; |
| 22 | protected float $startTime; |
| 23 | protected mixed $maxRunTime = 50; |
| 24 | |
| 25 | public function __construct(mixed $verbose = false, mixed $maxRunTime = 50) |
| 26 | { |
| 27 | $this->verbose = $verbose; |
| 28 | $this->startTime = microtime(true); |
| 29 | $this->maxRunTime = $maxRunTime; |
| 30 | } |
| 31 | |
| 32 | public static function getLogList(): array |
| 33 | { |
| 34 | return static::$logList; |
| 35 | } |
| 36 | |
| 37 | public static function clearLogList(): void |
| 38 | { |
| 39 | static::$logList = []; |
| 40 | } |
| 41 | |
| 42 | protected function getSpendTime(): float |
| 43 | { |
| 44 | $time = round(microtime(true) - $this->startTime, 3); |
| 45 | return $time; |
| 46 | } |
| 47 | |
| 48 | protected function getNow(): \DateTimeInterface |
| 49 | { |
| 50 | $now = \App::$now; |
| 51 | if ($now instanceof \DateTimeInterface) { |
| 52 | return $now; |
| 53 | } |
| 54 | throw new \RuntimeException('Current time is not initialized'); |
| 55 | } |
| 56 | |
| 57 | protected function getHttp(): Http |
| 58 | { |
| 59 | $http = \App::$http; |
| 60 | if ($http instanceof Http) { |
| 61 | return $http; |
| 62 | } |
| 63 | throw new \RuntimeException('HTTP client is not initialized'); |
| 64 | } |
| 65 | |
| 66 | protected function sendMailer(Entity $entity, mixed $mailer = null, mixed $action = false): mixed |
| 67 | { |
| 68 | // @codeCoverageIgnoreStart |
| 69 | $hasSendSuccess = ($action) ? $mailer->Send() : $action; |
| 70 | if (false !== $action && null !== $mailer && ! $hasSendSuccess) { |
| 71 | $this->log("Exception: SendingFailed - " . $this->getNow()->format('c')); |
| 72 | throw new Exception\SendingFailed(); |
| 73 | } |
| 74 | // @codeCoverageIgnoreEnd |
| 75 | $log = new Mimepart(['mime' => 'text/plain']); |
| 76 | $log['content'] = ($entity instanceof Mail) ? $entity['subject'] : $entity['message']; |
| 77 | $this->getHttp()->readPostResult('/log/process/' . $entity['process']['id'] . '/', $log); |
| 78 | return $mailer; |
| 79 | } |
| 80 | |
| 81 | /** |
| 82 | * @return false|null |
| 83 | */ |
| 84 | protected function removeEntityOlderThanOneHour(Mail $entity) |
| 85 | { |
| 86 | if (3600 < $this->getNow()->getTimestamp() - $entity['createTimestamp']) { |
| 87 | $this->deleteEntityFromQueue($entity); |
| 88 | $log = new Mimepart(['mime' => 'text/plain']); |
| 89 | $log['content'] = 'Zmsmessaging Failure: Queue entry older than 1 hour has been removed'; |
| 90 | $this->getHttp()->readPostResult('/log/process/' . $entity['process']['id'] . '/', $log, ['error' => 1]); |
| 91 | \App::$log->warning($log['content']); |
| 92 | return false; |
| 93 | } |
| 94 | } |
| 95 | |
| 96 | public function deleteEntityFromQueue(Mail $entity): bool |
| 97 | { |
| 98 | try { |
| 99 | $entity = $this->getHttp() |
| 100 | ->readDeleteResult('/mails/' . $entity['id'] . '/') |
| 101 | ->getEntity(); |
| 102 | } catch (\BO\Zmsclient\Exception $exception) { |
| 103 | throw $exception; |
| 104 | } |
| 105 | |
| 106 | return (bool) $entity; |
| 107 | } |
| 108 | |
| 109 | /** |
| 110 | * @return void |
| 111 | */ |
| 112 | public function testEntity(Mail $entity) |
| 113 | { |
| 114 | if (!isset($entity['department'])) { |
| 115 | throw new \Exception("Could not resolve department for message " . $entity['id']); |
| 116 | } |
| 117 | if (!isset($entity['department']['email'])) { |
| 118 | throw new \Exception( |
| 119 | "No mail address for department " |
| 120 | . $entity['department']['name'] |
| 121 | . " (departmentID=" |
| 122 | . $entity['department']['id'] |
| 123 | . " Vorgang=" |
| 124 | . $entity['process']['id'] |
| 125 | . ") " |
| 126 | . $entity['id'] |
| 127 | ); |
| 128 | } |
| 129 | if (! $entity->hasContent()) { |
| 130 | throw new \BO\Zmsmessaging\Exception\MailWithoutContent(); |
| 131 | } |
| 132 | $isMail = Validator::value($entity->getRecipient())->isMail()->getValue(); |
| 133 | if (!$isMail) { |
| 134 | throw new \BO\Zmsmessaging\Exception\InvalidMailAddress(); |
| 135 | } |
| 136 | if (\App::$verify_dns_enabled) { |
| 137 | $hasDns = Validator::value($entity->getRecipient())->isMail()->hasDNS()->getValue(); |
| 138 | if (!$hasDns) { |
| 139 | throw new \BO\Zmsmessaging\Exception\InvalidMailAddress(); |
| 140 | } |
| 141 | } |
| 142 | } |
| 143 | |
| 144 | protected function monitorProcesses(array $processHandles): void |
| 145 | { |
| 146 | $running = true; |
| 147 | while ($running) { |
| 148 | $running = false; |
| 149 | foreach ($processHandles as &$handle) { |
| 150 | if (is_resource($handle['process'])) { |
| 151 | $status = proc_get_status($handle['process']); |
| 152 | if ($status['running']) { |
| 153 | $running = true; |
| 154 | } else { |
| 155 | $output = stream_get_contents($handle['pipes'][1]); // stdout |
| 156 | $errorOutput = stream_get_contents($handle['pipes'][2]); // stderr |
| 157 | fclose($handle['pipes'][1]); |
| 158 | fclose($handle['pipes'][2]); |
| 159 | if (is_string($output) && trim($output)) { |
| 160 | $this->log("\nProcess stdout: " . trim($output) . "\n"); |
| 161 | } |
| 162 | if (is_string($errorOutput) && trim($errorOutput)) { |
| 163 | $this->log("\nProcess stderr: " . trim($errorOutput) . "\n"); |
| 164 | } |
| 165 | |
| 166 | proc_close($handle['process']); |
| 167 | $handle['process'] = null; |
| 168 | } |
| 169 | } |
| 170 | } |
| 171 | usleep(500000); |
| 172 | } |
| 173 | } |
| 174 | |
| 175 | |
| 176 | |
| 177 | |
| 178 | public function log(string $message): void |
| 179 | { |
| 180 | $time = $this->getSpendTime(); |
| 181 | $memory = memory_get_usage() / (1024 * 1024); |
| 182 | static::$logList[] = $message; |
| 183 | |
| 184 | $context = [ |
| 185 | 'component' => 'zmsmessaging', |
| 186 | 'elapsed' => $time, |
| 187 | 'memory_mb' => $memory, |
| 188 | ]; |
| 189 | if ($this->verbose) { |
| 190 | \App::$log->debug($message, $context); |
| 191 | } else { |
| 192 | \App::$log->info($message, $context); |
| 193 | } |
| 194 | } |
| 195 | |
| 196 | protected function convertCollectionToArray(mixed $collection): array |
| 197 | { |
| 198 | $this->log("Converting collection to array"); |
| 199 | $array = []; |
| 200 | foreach ($collection as $item) { |
| 201 | $array[] = $item; |
| 202 | } |
| 203 | $this->log("Conversion complete, array size: " . count($array)); |
| 204 | return $array; |
| 205 | } |
| 206 | } |