feat: admin editable email templates
addresses #869eg7ptr
This commit is contained in:
1 parent
804dab335f
commit
3e08965e48
49 files changed
+1760
-276
No files matched your search
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace App\Config;
|
||||
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
/**
|
||||
* Reads the delivered wording of the admin-editable mails from config/email_texts.yaml.
|
||||
*
|
||||
* That wording is the fallback used whenever no email_text row exists for a key, so the
|
||||
* mails keep working on a fresh database and "reset to default" needs nothing but deleting
|
||||
* the row.
|
||||
*
|
||||
* The file is parsed lazily and memoised: a request that sends no mail and opens no admin
|
||||
* screen never touches it, and one that does reads it once. Nothing here is validated at
|
||||
* compile time, so a missing entry surfaces as an error the first time the catalogue is
|
||||
* built - EmailTextCatalogTest builds all of them.
|
||||
*/
|
||||
class EmailTextCatalog
|
||||
{
|
||||
/**
|
||||
* @var array<string, EmailTextDefinition>|null
|
||||
*/
|
||||
private ?array $definitions = null;
|
||||
|
||||
public function __construct(
|
||||
private readonly string $emailTextsFile,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, EmailTextDefinition> keyed by EmailTextKey value
|
||||
*/
|
||||
public function all(): array
|
||||
{
|
||||
return $this->definitions ??= $this->build();
|
||||
}
|
||||
|
||||
public function get(EmailTextKey $key): EmailTextDefinition
|
||||
{
|
||||
return $this->all()[$key->value];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, EmailTextDefinition>
|
||||
*/
|
||||
private function build(): array
|
||||
{
|
||||
$config = Yaml::parseFile($this->emailTextsFile);
|
||||
$descriptions = $config['placeholders'];
|
||||
|
||||
$definitions = [];
|
||||
|
||||
foreach (EmailTextKey::cases() as $key) {
|
||||
$text = $config['texts'][$key->value];
|
||||
|
||||
$placeholders = [];
|
||||
|
||||
foreach ($text['placeholders'] as $name) {
|
||||
$placeholders[$name] = $descriptions[$name];
|
||||
}
|
||||
|
||||
$definitions[$key->value] = new EmailTextDefinition(
|
||||
$key,
|
||||
$text['label'],
|
||||
$placeholders,
|
||||
$text['subject'],
|
||||
$text['headline'],
|
||||
$text['body'],
|
||||
);
|
||||
}
|
||||
|
||||
return $definitions;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Config;
|
||||
|
||||
/**
|
||||
* The parts of an editable mail that stay in code: its name in the admin UI, the
|
||||
* placeholders it accepts, and the wording that applies until an admin overrides it.
|
||||
*/
|
||||
readonly class EmailTextDefinition
|
||||
{
|
||||
/**
|
||||
* @param array<string, string> $placeholders name => description shown to the admin
|
||||
*/
|
||||
public function __construct(
|
||||
public EmailTextKey $key,
|
||||
public string $label,
|
||||
public array $placeholders,
|
||||
public string $defaultSubject,
|
||||
public string $defaultHeadline,
|
||||
public string $defaultBody,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public function getPlaceholderNames(): array
|
||||
{
|
||||
return array_keys($this->placeholders);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace App\Config;
|
||||
|
||||
/**
|
||||
* The transactional mails whose wording admins may edit.
|
||||
*
|
||||
* A case's value is what ends up in email_text.template_key, so renaming one orphans
|
||||
* the stored override and silently falls back to the default in EmailTextCatalog.
|
||||
*/
|
||||
enum EmailTextKey: string
|
||||
{
|
||||
case APPLICATION_ACCEPTED = 'application_accepted';
|
||||
case APPLICATION_REJECTED = 'application_rejected';
|
||||
case ASSIGNMENT_CALLED_OFF = 'assignment_called_off';
|
||||
case DISPOSITION_CALLED_OFF = 'disposition_called_off';
|
||||
case DOCUMENT_REJECTED = 'document_rejected';
|
||||
case REMINDER_CONTRACT_UPLOAD = 'reminder_contract_upload';
|
||||
case REMINDER_INVOICE_UPLOAD = 'reminder_invoice_upload';
|
||||
case REMINDER_DISPOSITION = 'reminder_disposition';
|
||||
}
|
||||
Reference in new issue
Block a user