Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
d4a5172
feat: add messaging services for campaign management and notification
tatevikg1 Sep 10, 2026
3c660a5
ref: rename CampaignProcessor message handler classes and update name…
tatevikg1 Sep 10, 2026
0f9cab9
ref: standardize configuration parameter naming conventions
tatevikg1 Sep 10, 2026
350db9b
ref: update template ID casting in MessagePrecacheService and enhance…
tatevikg1 Sep 10, 2026
ae2e337
fix: improve error handling in message precaching and ensure template…
tatevikg1 Sep 10, 2026
ced7614
fix: prevent processing of messages without an owner in MessagePrecac…
tatevikg1 Sep 10, 2026
98beb65
ref: refactor cache key generation in messaging services for consistency
tatevikg1 Sep 10, 2026
4de1554
fix: update countSentSince method to accurately count messages based …
tatevikg1 Sep 10, 2026
81f5084
logs
tatevikg1 Sep 10, 2026
f420ba6
fix: update expected argument in sending loop test for campaign messa…
tatevikg1 Sep 10, 2026
fc4d051
fix: remove logger dependency and handle unique constraint violations…
tatevikg1 Sep 10, 2026
ee3765a
fix: update message status handling for size limit exceptions in camp…
tatevikg1 Sep 10, 2026
6e1a54d
fix: update logging messages to use subscriber ID instead of email ad…
tatevikg1 Sep 10, 2026
ee0ad5e
fix: update user message status before message status to flush once
tatevikg1 Sep 10, 2026
efd637d
fix: move cache check logic up to avoid setting user message status t…
tatevikg1 Sep 10, 2026
65c86ca
fix: add test for handling UniqueConstraintViolationException during …
tatevikg1 Sep 18, 2026
ba8406d
fix: update error message formatting in campaign message precaching
tatevikg1 Sep 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env.dist
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ PREFERENCEPAGE_SHOW_PRIVATE_LISTS=0
API_BASE_URL=http://api.phplist.local/
FRONT_END_BASE_URL=http://frontend.phplist.local

PARALLER_USE_WITH_PHPLIST3=0
PARALLEL_USE_WITH_PHPLIST3=0

# Email configuration
MAILER_FROM=noreply@phplist.com
Expand Down
50 changes: 28 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,14 @@ If your module provides any Symfony bundles, the bundle class names need to be
listed in the `extra` section of the module's `composer.json` like this:

```json
"extra": {
"phplist/core": {
"bundles": [
"Symfony\\Bundle\\FrameworkBundle\\FrameworkBundle",
"PhpList\\Core\\EmptyStartPageBundle\\PhpListEmptyStartPageBundle"
]
{
"extra": {
"phplist/core": {
"bundles": [
"Symfony\\Bundle\\FrameworkBundle\\FrameworkBundle",
"PhpList\\Core\\EmptyStartPageBundle\\PhpListEmptyStartPageBundle"
]
}
}
}
```
Expand All @@ -137,12 +139,14 @@ Similarly, if your module provides any routes, those also need to be listed in
the `extra` section of the module's `composer.json` like this:

```json
"extra": {
"phplist/core": {
"routes": {
"homepage": {
"resource": "@PhpListEmptyStartPageBundle/Controller/",
"type": "annotation"
{
"extra": {
"phplist/core": {
"routes": {
"homepage": {
"resource": "@PhpListEmptyStartPageBundle/Controller/",
"type": "annotation"
}
}
}
}
Expand All @@ -152,18 +156,20 @@ the `extra` section of the module's `composer.json` like this:
You can also provide system configuration for your module:

```json
"extra": {
"phplist/core": {
"configuration": {
"framework": {
"templating": {
"engines": [
"twig"
]
{
"extra": {
"phplist/core": {
"configuration": {
"framework": {
"templating": {
"engines": [
"twig"
]
}
}
}
}
}
}
}
```

Expand Down Expand Up @@ -203,7 +209,7 @@ To extract translation strings from the source into an XLIFF catalog:
```bash
php bin/console translation:extract --force en --format=xlf
php bin/console messenger:setup-transports
php bin/console messenger:consume async --limit=1
php bin/console messenger:consume async_email --limit=1
php bin/console phplist:search:init-indices
```

Expand Down
2 changes: 1 addition & 1 deletion config/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ framework:
default_path: '%kernel.project_dir%/resources/translations'
fallbacks: ['%locale%']

secret: '%secret%'
secret: '%app.secret%'
router:
resource: '%kernel.project_dir%/config/routing.yml'
strict_requirements: ~
Expand Down
4 changes: 2 additions & 2 deletions config/config_dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ monolog:
# graylog:
# type: gelf
# publisher:
# hostname: '%app.config.graylog_host%'
# port: '%app.config.graylog_port%'
# hostname: '%graylog.host%'
# port: '%graylog.port%'
# level: debug
# channels: ['!event']
console:
Expand Down
4 changes: 2 additions & 2 deletions config/config_prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ monolog:
# graylog:
# type: gelf
# publisher:
# hostname: '%graylog_host%'
# port: '%graylog_port%'
# hostname: '%graylog.host%'
# port: '%graylog.port%'
# level: error
# Local file logging as backup
main:
Expand Down
12 changes: 6 additions & 6 deletions config/config_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ doctrine:
# in-memory SQLite database instead (no MySQL server needed), set in .env.test.local:
# PHPLIST_DATABASE_DRIVER=pdo_sqlite
# PHPLIST_DATABASE_PATH=:memory:
driver: '%database_driver%'
path: '%database_path%'
host: '%database_host%'
port: '%database_port%'
driver: '%database.driver%'
path: '%database.path%'
host: '%database.host%'
port: '%database.port%'
dbname: 'phplist'
user: '%database_user%'
password: '%database_password%'
user: '%database.user%'
password: '%database.password%'
charset: UTF8

14 changes: 7 additions & 7 deletions config/doctrine.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ doctrine:
dbal:
# These variables come from parameters.yml. There, the values are read from environment variables
# and can also be set directly in the parameters.yml file.
driver: '%database_driver%'
host: '%database_host%'
path: '%database_path%'
port: '%database_port%'
dbname: '%database_name%'
user: '%database_user%'
password: '%database_password%'
driver: '%database.driver%'
host: '%database.host%'
path: '%database.path%'
port: '%database.port%'
dbname: '%database.name%'
user: '%database.user%'
password: '%database.password%'
charset: UTF8
use_savepoints: true

Expand Down
28 changes: 14 additions & 14 deletions config/parameters.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,25 @@
# The environment variables themselves are defined in the ".env" file (see ".env.dist" for the template)
# and/or in the actual environment (e.g. Apache host configuration, command line).
parameters:
database_driver: '%env(PHPLIST_DATABASE_DRIVER)%'
database_path: '%env(PHPLIST_DATABASE_PATH)%'
database_host: '%env(PHPLIST_DATABASE_HOST)%'
database_port: '%env(PHPLIST_DATABASE_PORT)%'
database_name: '%env(PHPLIST_DATABASE_NAME)%'
database_user: '%env(PHPLIST_DATABASE_USER)%'
database_password: '%env(PHPLIST_DATABASE_PASSWORD)%'
database_prefix: '%env(DATABASE_PREFIX)%'
list_table_prefix: '%env(LIST_TABLE_PREFIX)%'
database.driver: '%env(PHPLIST_DATABASE_DRIVER)%'
database.path: '%env(PHPLIST_DATABASE_PATH)%'
database.host: '%env(PHPLIST_DATABASE_HOST)%'
database.port: '%env(PHPLIST_DATABASE_PORT)%'
database.name: '%env(PHPLIST_DATABASE_NAME)%'
database.user: '%env(PHPLIST_DATABASE_USER)%'
database.password: '%env(PHPLIST_DATABASE_PASSWORD)%'
database.prefix: '%env(DATABASE_PREFIX)%'
database.list_table_prefix: '%env(LIST_TABLE_PREFIX)%'

app.dev_version: '%env(APP_DEV_VERSION)%'
app.dev_email: '%env(APP_DEV_EMAIL)%'
app.powered_by_phplist: '%env(APP_POWERED_BY_PHPLIST)%'
app.preference_page_show_private_lists: '%env(PREFERENCEPAGE_SHOW_PRIVATE_LISTS)%'

app.rest_api_base_url: '%env(API_BASE_URL)%/api/v2'
app.api_base_url: '%env(API_BASE_URL)%'
app.frontend_base_url: '%env(FRONT_END_BASE_URL)%'

parallel_use_with_phplist3: '%env(PARALLER_USE_WITH_PHPLIST3)%'
app.parallel_use_with_phplist3: '%env(PARALLEL_USE_WITH_PHPLIST3)%'

# Email configuration
app.mailer_from: '%env(MAILER_FROM)%'
Expand Down Expand Up @@ -63,11 +63,11 @@ parameters:
elasticsearch.purge.subscriber_history_retention: '%env(ELASTICSEARCH_PURGE_SUBSCRIBER_HISTORY_RETENTION)%'

# A secret key that's used to generate certain security-related tokens
secret: '%env(PHPLIST_SECRET)%'
app.secret: '%env(PHPLIST_SECRET)%'
phplist.verify_ssl: '%env(VERIFY_SSL)%'

graylog_host: 'graylog.phplist.local'
graylog_port: 12201
graylog.host: 'graylog.phplist.local'
graylog.port: 12201

app.phplist_isp_conf_path: '%env(APP_PHPLIST_ISP_CONF_PATH)%'

Expand Down
2 changes: 1 addition & 1 deletion config/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ services:

PhpList\Core\Core\Doctrine\TablePrefixListener:
arguments:
$tablePrefix: '%database_prefix%'
$tablePrefix: '%database.prefix%'

PhpList\Core\Core\Doctrine\SearchIndexDoctrineListener:
arguments:
Expand Down
4 changes: 2 additions & 2 deletions config/services/managers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@ services:
autoconfigure: true
public: true
arguments:
$dbPrefix: '%database_prefix%'
$dynamicListTablePrefix: '%list_table_prefix%'
$dbPrefix: '%database.prefix%'
$dynamicListTablePrefix: '%database.list_table_prefix%'
4 changes: 2 additions & 2 deletions config/services/messenger.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ services:
resource: '../../src/Domain/Search/MessageHandler'
tags: [ 'messenger.message_handler' ]

PhpList\Core\Domain\Messaging\MessageHandler\CampaignProcessor\CampaignProcessorMessageHandler:
PhpList\Core\Domain\Messaging\MessageHandler\CampaignProcessorMessageHandler:
autowire: true
autoconfigure: true

PhpList\Core\Domain\Messaging\MessageHandler\CampaignProcessor\TestCampaignProcessorMessageHandler:
PhpList\Core\Domain\Messaging\MessageHandler\CampaignProcessorTestMessageHandler:
autowire: true
autoconfigure: true
4 changes: 2 additions & 2 deletions config/services/repositories.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ services:
PhpList\Core\Domain\Subscription\Repository\DynamicListAttrRepository:
autowire: true
arguments:
$dbPrefix: '%database_prefix%'
$dynamicListTablePrefix: '%list_table_prefix%'
$dbPrefix: '%database.prefix%'
$dynamicListTablePrefix: '%database.list_table_prefix%'
PhpList\Core\Domain\Subscription\Repository\SubscriberHistoryRepository:
parent: PhpList\Core\Domain\Common\Repository\AbstractRepository
arguments:
Expand Down
24 changes: 24 additions & 0 deletions config/services/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,30 @@ services:
autowire: true
autoconfigure: true

PhpList\Core\Domain\Messaging\Service\MessageStatusUpdater:
autowire: true
autoconfigure: true

PhpList\Core\Domain\Messaging\Service\SystemNotificationMailer:
autowire: true
autoconfigure: true

PhpList\Core\Domain\Messaging\Service\CampaignExclusionService:
autowire: true
autoconfigure: true

PhpList\Core\Domain\Messaging\Service\CampaignAdminNotifier:
autowire: true
autoconfigure: true

PhpList\Core\Domain\Messaging\Service\CampaignEmailSender:
autowire: true
autoconfigure: true

PhpList\Core\Domain\Messaging\Service\CampaignSendingLoop:
autowire: true
autoconfigure: true

_instanceof:
PhpList\Core\Domain\Messaging\Service\Handler\BounceActionHandlerInterface:
tags:
Expand Down
16 changes: 16 additions & 0 deletions resources/translations/messages.en.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,22 @@ Thank you.</target>
<source>%subscriber% has forwarded message %campaignId% to %email%</source>
<target>__%subscriber% has forwarded message %campaignId% to %email%</target>
</trans-unit>
<trans-unit id="FPstK2o" resname="Error precaching campaign message: %error%">
<source>Error precaching campaign message: %error%</source>
<target>__Error precaching campaign message: %error%</target>
</trans-unit>
<trans-unit id="IqU0fUe" resname="phplist system error">
<source>phplist system error</source>
<target>__phplist system error</target>
</trans-unit>
<trans-unit id="dGEyObO" resname="Failed to send to: %subscriber_id%">
<source>Failed to send to: %subscriber_id%</source>
<target>__Failed to send to: %subscriber_id%</target>
</trans-unit>
<trans-unit id="ETHGTu1" resname="Invalid email, marking unconfirmed: %subscriber_id%">
<source>Invalid email, marking unconfirmed: %subscriber_id%</source>
<target>__Invalid email, marking unconfirmed: %subscriber_id%</target>
</trans-unit>
</body>
</file>
</xliff>
28 changes: 28 additions & 0 deletions resources/translations/validators.en.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -557,6 +557,30 @@
<source>This filename does not match the expected charset.</source>
<target>This filename does not match the expected charset.</target>
</trans-unit>
<trans-unit id="9EAmiNT" resname="This value is not valid XML.">
<source>This value is not valid XML.</source>
<target>This value is not valid XML.</target>
</trans-unit>
<trans-unit id="7zWzlwW" resname="This value does not conform to the expected XSD schema.">
<source>This value does not conform to the expected XSD schema.</source>
<target>This value does not conform to the expected XSD schema.</target>
</trans-unit>
<trans-unit id="RNPkmA2" resname="This XML payload is too large ({{ size }} bytes): it exceeds the limit of {{ limit }} bytes.">
<source>This XML payload is too large ({{ size }} bytes): it exceeds the limit of {{ limit }} bytes.</source>
<target>This XML payload is too large ({{ size }} bytes): it exceeds the limit of {{ limit }} bytes.</target>
</trans-unit>
<trans-unit id="6IWIt6b" resname="This value is not a valid cron expression.">
<source>This value is not a valid cron expression.</source>
<target>This value is not a valid cron expression.</target>
</trans-unit>
<trans-unit id="Q_VBnqu" resname="The referenced entity does not exist.">
<source>The referenced entity does not exist.</source>
<target>The referenced entity does not exist.</target>
</trans-unit>
<trans-unit id="kQwgJ0r" resname="This is not a valid ULID.">
<source>This is not a valid ULID.</source>
<target>This value is not a valid ULID.</target>
</trans-unit>
<trans-unit id=".SEaaBa" resname="This form should not contain extra fields.">
<source>This form should not contain extra fields.</source>
<target>This form should not contain extra fields.</target>
Expand Down Expand Up @@ -689,6 +713,10 @@
<source>Please enter a valid week.</source>
<target>Please enter a valid week.</target>
</trans-unit>
<trans-unit id="OizF.Ma" resname="Please enter a valid UUID.">
<source>Please enter a valid UUID.</source>
<target>Please enter a valid UUID.</target>
</trans-unit>
</body>
</file>
</xliff>
2 changes: 1 addition & 1 deletion src/Domain/Configuration/Service/Manager/ConfigManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class ConfigManager
{
public function __construct(
private readonly ConfigRepository $configRepository,
#[Autowire('%parallel_use_with_phplist3%')]
#[Autowire('%app.parallel_use_with_phplist3%')]
private readonly bool $parallelUseWithPhpList3,
) {
}
Expand Down
2 changes: 2 additions & 0 deletions src/Domain/Messaging/Command/ProcessQueueCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$lock->release();
}

$output->writeln('Processed ' . count($campaigns) . ' campaigns from the queue.');

return Command::SUCCESS;
}
}
Loading
Loading