CluPilotCloud/app/Services/Mail/MailboxResolver.php

58 lines
2.0 KiB
PHP

<?php
namespace App\Services\Mail;
use App\Models\Mailbox;
use App\Support\Settings;
use InvalidArgumentException;
/**
* Which mailbox a given kind of mail goes out from.
*
* Read on every resolve rather than cached in a property: a queue worker lives
* for hours, and a mapping cached at construction would keep sending from the
* address that was configured when the worker started.
*/
final class MailboxResolver
{
public function for(string $purpose): ?Mailbox
{
if (! in_array($purpose, MailPurpose::ALL, true)) {
throw new InvalidArgumentException("Unknown mail purpose [{$purpose}].");
}
$box = $this->active($this->named(Settings::get(MailPurpose::settingKey($purpose))));
if ($box !== null) {
return $box;
}
// Fall back rather than fail: a mail that goes out from the wrong
// address is recoverable, one that is never sent may not be noticed.
return $purpose === MailPurpose::SYSTEM
? null
: $this->active($this->named(Settings::get(MailPurpose::settingKey(MailPurpose::SYSTEM))));
}
private function named(mixed $key): ?Mailbox
{
return is_string($key) && $key !== '' ? Mailbox::findByKey($key) : null;
}
/**
* Deactivating a mailbox is an explicit operator action meaning "do not
* use this" — it must fall back exactly like a mapping that points
* nowhere or a row that is gone, so it is filtered here, at BOTH lookup
* sites, rather than left for a caller to notice.
*
* A mailbox with no password is deliberately NOT filtered here: silently
* sending support mail from billing@ because support@ has no password
* yet is worse than a loud failure naming the mailbox that needs one —
* that check stays a MailboxTransport concern, not this one.
*/
private function active(?Mailbox $box): ?Mailbox
{
return $box?->active === true ? $box : null;
}
}