Skip to content

Commit ccdce7f

Browse files
committed
In progress
1 parent 183af8f commit ccdce7f

File tree

9 files changed

+173
-15
lines changed

9 files changed

+173
-15
lines changed

resources/translations/messages.en.xlf

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@
7979
</trans-unit>
8080

8181
<trans-unit id="identity.subscription_confirmation">
82-
<source>Please confirm your subscription</source>
83-
<target>Please confirm your subscription</target>
82+
<source>Request for confirmation</source>
83+
<target>Request for confirmation</target>
8484
</trans-unit>
8585

8686
<trans-unit id="identity.subscription_confirmation.text">

src/Domain/Configuration/Model/ConfigOption.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,7 @@ enum ConfigOption: string
88
{
99
case MaintenanceMode = 'maintenancemode';
1010
case SendSubscribeMessage = 'subscribemessage';
11+
12+
case SubscribeEmailSubject = 'subscribesubject';
13+
case SubscribeEmailBody = 'subscribemessage';
1114
}

src/Domain/Configuration/Repository/ConfigRepository.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,8 @@
88

99
class ConfigRepository extends AbstractRepository
1010
{
11+
public function findValueByItem(string $name): ?string
12+
{
13+
return $this->findOneBy(['item' => $name])?->getValue();
14+
}
1115
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpList\Core\Domain\Configuration\Service;
6+
7+
class PlaceholderResolver
8+
{
9+
/** @var array<string, callable():string> */
10+
private array $providers = [];
11+
12+
public function register(string $token, callable $provider): void
13+
{
14+
// tokens like [UNSUBSCRIBEURL] (case-insensitive)
15+
$this->providers[strtoupper($token)] = $provider;
16+
}
17+
18+
public function resolve(?string $input): ?string
19+
{
20+
if ($input === null || $input === '') return $input;
21+
22+
// Replace [TOKEN] (case-insensitive). Keep simple & fast:
23+
return preg_replace_callback('/\[(\w+)\]/i', function ($m) {
24+
$key = strtoupper($m[1]);
25+
if (!isset($this->providers[$key])) {
26+
return $m[0]; // leave as-is
27+
}
28+
$val = (string) ($this->providers[$key])();
29+
return $val; // no auto-added spaces
30+
}, $input);
31+
}
32+
}

src/Domain/Configuration/Service/Provider/ConfigProvider.php

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use InvalidArgumentException;
88
use PhpList\Core\Domain\Configuration\Model\ConfigOption;
99
use PhpList\Core\Domain\Configuration\Repository\ConfigRepository;
10+
use Psr\SimpleCache\CacheInterface;
1011

1112
class ConfigProvider
1213
{
@@ -15,11 +16,11 @@ class ConfigProvider
1516
ConfigOption::SendSubscribeMessage,
1617
];
1718

18-
private ConfigRepository $configRepository;
19-
20-
public function __construct(ConfigRepository $configRepository)
21-
{
22-
$this->configRepository = $configRepository;
19+
public function __construct(
20+
private readonly ConfigRepository $configRepository,
21+
private readonly CacheInterface $cache,
22+
private readonly int $ttlSeconds = 300
23+
) {
2324
}
2425

2526
public function isEnabled(ConfigOption $key): bool
@@ -35,11 +36,35 @@ public function isEnabled(ConfigOption $key): bool
3536
/**
3637
* Get configuration value by its key
3738
*/
38-
public function getValue(string $ikey, ?string $default = null): ?string
39+
public function getValue(ConfigOption $key, ?string $default = null): ?string
3940
{
40-
$config = $this->configRepository->findOneBy(['item' => $ikey]);
41+
if (in_array($key, $this->booleanValues)) {
42+
throw new InvalidArgumentException('Key is a boolean value, use isEnabled instead');
43+
}
44+
$cacheKey = 'cfg:' . $key->value;
45+
$value = $this->cache->get($cacheKey);
46+
if ($value === null) {
47+
$value = $this->configRepository->findValueByItem($key->value);
48+
$this->cache->set($cacheKey, $value, $this->ttlSeconds);
49+
}
4150

42-
return $config?->getValue() ?? $default;
51+
return $value ?? $default;
4352
}
4453

54+
public function getValueWithNamespace(ConfigOption $key, ?string $default = null): ?string
55+
{
56+
$full = $this->getValue($key);
57+
if ($full !== null && $full !== '') {
58+
return $full;
59+
}
60+
61+
if (str_contains($key->value, ':')) {
62+
[$parent] = explode(':', $key->value, 2);
63+
$parentKey = ConfigOption::from($parent);
64+
65+
return $this->getValue($parentKey, $default);
66+
}
67+
68+
return $default;
69+
}
4570
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpList\Core\Domain\Configuration\Service;
6+
7+
class UrlBuilder
8+
{
9+
public function withUid(string $baseUrl, string $uid): string
10+
{
11+
$parts = parse_url($baseUrl) ?: [];
12+
$query = [];
13+
if (!empty($parts['query'])) {
14+
parse_str($parts['query'], $query);
15+
}
16+
$query['uid'] = $uid;
17+
18+
$parts['query'] = http_build_query($query);
19+
20+
// rebuild url
21+
$scheme = $parts['scheme'] ?? 'https';
22+
$host = $parts['host'] ?? '';
23+
$port = isset($parts['port']) ? ':'.$parts['port'] : '';
24+
$path = $parts['path'] ?? '';
25+
$queryStr = $parts['query'] ? '?'.$parts['query'] : '';
26+
$frag = isset($parts['fragment']) ? '#'.$parts['fragment'] : '';
27+
28+
return "{$scheme}://{$host}{$port}{$path}{$queryStr}{$frag}";
29+
}
30+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpList\Core\Domain\Configuration\Service;
6+
7+
class UserPersonalizer
8+
{
9+
public function __construct(
10+
private ConfigService $config,
11+
private UrlBuilder $urlBuilder,
12+
private UserRepository $users,
13+
private AttributeService $attributes // getUserAttributeValues()
14+
) {}
15+
16+
public function personalize(string $value, int $userId): string
17+
{
18+
$user = $this->users->findById($userId);
19+
if (!$user) {
20+
return $value;
21+
}
22+
23+
$resolver = new PlaceholderResolver();
24+
25+
$resolver->register('EMAIL', fn() => $user->email);
26+
27+
$resolver->register('UNSUBSCRIBEURL', function () use ($user) {
28+
$base = $this->config->getString(ConfigOption::unsubscribeurl) ?? '';
29+
return $this->urlBuilder->withUid($base, $user->uniqid);
30+
});
31+
$resolver->register('CONFIRMATIONURL', function () use ($user) {
32+
$base = $this->config->getString(ConfigOption::confirmationurl) ?? '';
33+
return $this->urlBuilder->withUid($base, $user->uniqid);
34+
});
35+
$resolver->register('PREFERENCESURL', function () use ($user) {
36+
$base = $this->config->getString(ConfigOption::preferencesurl) ?? '';
37+
return $this->urlBuilder->withUid($base, $user->uniqid);
38+
});
39+
40+
// global tokens available here too if you want a single pass:
41+
$resolver->register('SUBSCRIBEURL', fn() => $this->config->getString(ConfigOption::subscribeurl) ?? '');
42+
$resolver->register('DOMAIN', fn() => $this->config->getString(ConfigOption::domain) ?? '');
43+
$resolver->register('WEBSITE', fn() => $this->config->getString(ConfigOption::website) ?? '');
44+
45+
// attribute placeholders (e.g., [FIRSTNAME], [CITY], etc.)
46+
$attrs = $this->attributes->forEmail($user->email); // returns array<string,string>
47+
foreach ($attrs as $k => $v) {
48+
$resolver->register(strtoupper($k), fn() => $v);
49+
}
50+
51+
$out = $resolver->resolve($value);
52+
return $out !== null ? trim($out) : $out;
53+
}
54+
}

src/Domain/Messaging/MessageHandler/SubscriberConfirmationMessageHandler.php

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
namespace PhpList\Core\Domain\Messaging\MessageHandler;
66

7+
use PhpList\Core\Domain\Configuration\Model\ConfigOption;
8+
use PhpList\Core\Domain\Configuration\Service\Provider\ConfigProvider;
79
use PhpList\Core\Domain\Messaging\Message\SubscriberConfirmationMessage;
810
use PhpList\Core\Domain\Messaging\Service\EmailService;
911
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
@@ -18,12 +20,18 @@ class SubscriberConfirmationMessageHandler
1820
{
1921
private EmailService $emailService;
2022
private TranslatorInterface $translator;
23+
private ConfigProvider $configProvider;
2124
private string $confirmationUrl;
2225

23-
public function __construct(EmailService $emailService, TranslatorInterface $translator, string $confirmationUrl)
24-
{
26+
public function __construct(
27+
EmailService $emailService,
28+
TranslatorInterface $translator,
29+
ConfigProvider $configProvider,
30+
string $confirmationUrl
31+
) {
2532
$this->emailService = $emailService;
2633
$this->translator = $translator;
34+
$this->configProvider = $configProvider;
2735
$this->confirmationUrl = $confirmationUrl;
2836
}
2937

@@ -33,8 +41,10 @@ public function __construct(EmailService $emailService, TranslatorInterface $tra
3341
public function __invoke(SubscriberConfirmationMessage $message): void
3442
{
3543
$confirmationLink = $this->generateConfirmationLink($message->getUniqueId());
36-
37-
$subject = $this->translator->trans('Please confirm your subscription');
44+
$subject = $this->configProvider->getValue(
45+
key: ConfigOption::SubscribeEmailSubject,
46+
default: $this->translator->trans('Request for confirmation')
47+
);
3848

3949
$textContent = $this->translator->trans(
4050
"Thank you for subscribing!\n\n" .

src/Domain/Subscription/Service/SubscriberCsvImporter.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ private function sendSubscribeEmail(string $subscriberEmail, array $listIds): vo
210210
}
211211
$listOfLists = implode(', ', $listNames);
212212

213-
$subject = $this->configProvider->getValue('subscribesubject', 'Subscription');
213+
$subject =
214214
$message = $this->configProvider->getValue('subscribemessage', 'You have been subscribed to: [LISTS]');
215215
$message = str_replace('[LISTS]', $listOfLists, (string)$message);
216216

0 commit comments

Comments
 (0)