diff --git a/.env.dist b/.env.dist new file mode 100644 index 00000000..03df0e91 --- /dev/null +++ b/.env.dist @@ -0,0 +1,96 @@ +# This file is a "template" of what your .env file should look like. +# Set variables here that may be different on each deployment target of the app, +# e.g. development, staging, production. +# +# On `composer install`/`composer update`, this file is copied to `.env` (unless +# it already exists) and PHPLIST_SECRET is replaced with a freshly generated value. +# +# https://symfony.com/doc/current/configuration.html#configuring-environment-variables-in-env-files + +PHPLIST_DATABASE_DRIVER=pdo_mysql +PHPLIST_DATABASE_PATH= +PHPLIST_DATABASE_HOST=127.0.0.1 +PHPLIST_DATABASE_PORT=3306 +PHPLIST_DATABASE_NAME=phplistdb +PHPLIST_DATABASE_USER=phplist +PHPLIST_DATABASE_PASSWORD=phplist +DATABASE_PREFIX=phplist_ +LIST_TABLE_PREFIX=listattr_ +PHPLIST_ADMIN_PASSWORD=admin + +APP_DEV_VERSION=0 +APP_DEV_EMAIL=dev@dev.com +APP_POWERED_BY_PHPLIST=0 +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 + +# Email configuration +MAILER_FROM=noreply@phplist.com +MAILER_DSN=null://null +CONFIRMATION_URL=http://api.phplist.local/api/v2/subscriber/confirm/ +SUBSCRIPTION_CONFIRMATION_URL=http://api.phplist.local/api/v2/subscription/confirm/ +PASSWORD_RESET_URL=https://example.com/reset/ +SHOW_UNSUBSCRIBELINK=1 + +# Bounce email settings +BOUNCE_EMAIL=bounce@phplist.com +BOUNCE_IMAP_PASS=bounce@phplist.com +BOUNCE_IMAP_HOST=imap.phplist.com +BOUNCE_IMAP_PORT=993 +BOUNCE_IMAP_ENCRYPTION=ssl +BOUNCE_IMAP_MAILBOX=/var/spool/mail/bounces +BOUNCE_IMAP_MAILBOX_NAME=INBOX,ONE_MORE +BOUNCE_IMAP_PROTOCOL=imap +BOUNCE_IMAP_UNSUBSCRIBE_THRESHOLD=5 +BOUNCE_IMAP_BLACKLIST_THRESHOLD=3 +BOUNCE_IMAP_PURGE=0 +BOUNCE_IMAP_PURGE_UNPROCESSED=0 + +# Messenger configuration for asynchronous processing +MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=true + +# A secret key that's used to generate certain security-related tokens +PHPLIST_SECRET=%s +VERIFY_SSL=1 + +APP_PHPLIST_ISP_CONF_PATH=/etc/phplist.conf + +# Message sending +MAILQUEUE_BATCH_SIZE=5 +MAILQUEUE_BATCH_PERIOD=5 +MAILQUEUE_THROTTLE=5 +MESSAGING_MAX_PROCESS_TIME=600 +MAX_MAILSIZE=209715200 +DEFAULT_MESSAGEAGE=691200 +USE_MANUAL_TEXT_PART=0 +MESSAGING_BLACKLIST_GRACE_TIME=600 +GOOGLE_SENDERID= +USE_AMAZONSES=0 +USE_PRECEDENCE_HEADER=0 +EMBEDEXTERNALIMAGES=0 +EMBEDUPLOADIMAGES=0 +EXTERNALIMAGE_MAXAGE=0 +EXTERNALIMAGE_TIMEOUT=30 +EXTERNALIMAGE_MAXSIZE=204800 +FORWARD_ALTERNATIVE_CONTENT=0 +EMAILTEXTCREDITS=0 +ALWAYS_ADD_USERTRACK=1 +SEND_LISTADMIN_COPY=0 + +FORWARD_EMAIL_PERIOD="1 minute" +FORWARD_EMAIL_COUNT=1 +FORWARD_PERSONAL_NOTE_SIZE=0 +FORWARD_FRIEND_COUNT_ATTRIBUTE= +KEEPFORWARDERATTRIBUTES=0 + +UPLOADIMAGES_DIR=uploadimages +PHPLIST_UPLOADS_MAX_SIZE=5M + +PUBLIC_SCHEMA=https +PHPLIST_ATTACHMENT_DOWNLOAD_URL=https://example.com/download/ +PHPLIST_ATTACHMENT_REPOSITORY_PATH=/tmp +MAX_AVATAR_SIZE=100000 diff --git a/.gitignore b/.gitignore index 25db886b..072e5252 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,9 @@ /composer.lock /config/bundles.yml /config/config_modules.yml -/config/parameters.yml +/.env +/.env.local +/.env.*.local /config/routing_modules.yml /nbproject /var/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 0254484d..f6e2111f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,10 @@ This project adheres to [Semantic Versioning](https://semver.org/). ### Added - Graylog integration for centralized logging (#TBD) +- `symfony/dotenv` support: configuration values are now read from a `.env` file (generated from `.env.dist` on install/update), in addition to real environment variables (#TBD) ### Changed +- `config/parameters.yml.dist` no longer contains inline `env(VAR): default` fallbacks; defaults now live in `.env.dist` (#TBD) ### Deprecated diff --git a/README.md b/README.md index 2015718a..cddd934b 100755 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ this code. The phpList application is configured so that the built-in PHP web server can run in development and testing mode, while Apache can run in production mode. -Please first set the database credentials in `config/parameters.yml`. +Please first set the database credentials in `.env` (created from `.env.dist` on `composer install`/`composer update`). ### Development @@ -228,3 +228,8 @@ vendor/bin/phpstan analyse -c phpstan.neon; vendor/bin/phpmd src/ text config/PHPMD/rules.xml; vendor/bin/phpcs --standard=config/PhpCodeSniffer/ --ignore=*/Migrations/* bin/ src/ tests/ public/; ``` + + +```bash +php bin/console messenger:consume async_email +``` diff --git a/composer.json b/composer.json index 9c95fb23..4bab2a2c 100644 --- a/composer.json +++ b/composer.json @@ -87,7 +87,9 @@ "ext-fileinfo": "*", "setasign/fpdf": "^1.8", "phpdocumentor/reflection-docblock": "^5.2", - "guzzlehttp/guzzle": "^7.4.5" + "guzzlehttp/guzzle": "^7.4.5", + "symfony/dotenv": "^6.4", + "symfony/doctrine-messenger": "^6.4" }, "require-dev": { "phpunit/phpunit": "^9.5", @@ -127,7 +129,7 @@ "PhpList\\Core\\Composer\\ScriptHandler::createGeneralConfiguration", "PhpList\\Core\\Composer\\ScriptHandler::createBundleConfiguration", "PhpList\\Core\\Composer\\ScriptHandler::createRoutesConfiguration", - "PhpList\\Core\\Composer\\ScriptHandler::createParametersConfiguration", + "PhpList\\Core\\Composer\\ScriptHandler::createDotenvConfiguration", "php bin/console cache:clear", "php bin/console cache:warmup" ], diff --git a/config/packages/messenger.yaml b/config/packages/messenger.yaml index 4193c501..2c32337b 100644 --- a/config/packages/messenger.yaml +++ b/config/packages/messenger.yaml @@ -28,7 +28,7 @@ framework: 'PhpList\Core\Domain\Messaging\Message\SubscriberConfirmationMessage': async_email 'PhpList\Core\Domain\Messaging\Message\SubscriptionConfirmationMessage': async_email 'PhpList\Core\Domain\Messaging\Message\PasswordResetMessage': async_email - 'PhpList\Core\Domain\Messaging\Message\CampaignProcessorMessage': async_email - 'PhpList\Core\Domain\Messaging\Message\SyncCampaignProcessorMessage': sync + 'PhpList\Core\Domain\Messaging\Message\CampaignProcessor\CampaignProcessorMessage': async_email + 'PhpList\Core\Domain\Messaging\Message\CampaignProcessor\SyncCampaignProcessorMessage': sync 'PhpList\Core\Domain\Subscription\Message\DynamicTableMessage': sync diff --git a/config/parameters.yml b/config/parameters.yml new file mode 100644 index 00000000..f2793be5 --- /dev/null +++ b/config/parameters.yml @@ -0,0 +1,100 @@ +# This file is a "template" of what your parameters.yml file should look like +# Set parameters here that may be different on each deployment target of the app, e.g. development, staging, production. +# https://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration +# +# These variables are read from environment variables using the "env" construct. +# 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)%' + app.default_admin_password: '%env(PHPLIST_DEFAULT_ADMIN_PASSWORD)%' + 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)%' + + # Email configuration + app.mailer_from: '%env(MAILER_FROM)%' + app.mailer_dsn: '%env(MAILER_DSN)%' + app.confirmation_url: '%env(CONFIRMATION_URL)%' + app.subscription_confirmation_url: '%env(SUBSCRIPTION_CONFIRMATION_URL)%' + app.password_reset_url: '%env(PASSWORD_RESET_URL)%' + app.show_unsubscribe_link: '%env(SHOW_UNSUBSCRIBELINK)%' + + # bounce email settings + imap_bounce.email: '%env(BOUNCE_EMAIL)%' + imap_bounce.password: '%env(BOUNCE_IMAP_PASS)%' + imap_bounce.host: '%env(BOUNCE_IMAP_HOST)%' + imap_bounce.port: '%env(BOUNCE_IMAP_PORT)%' + imap_bounce.encryption: '%env(BOUNCE_IMAP_ENCRYPTION)%' + imap_bounce.mailbox: '%env(BOUNCE_IMAP_MAILBOX)%' + imap_bounce.mailbox_name: '%env(BOUNCE_IMAP_MAILBOX_NAME)%' + imap_bounce.protocol: '%env(BOUNCE_IMAP_PROTOCOL)%' + imap_bounce.unsubscribe_threshold: '%env(BOUNCE_IMAP_UNSUBSCRIBE_THRESHOLD)%' + imap_bounce.blacklist_threshold: '%env(BOUNCE_IMAP_BLACKLIST_THRESHOLD)%' + imap_bounce.purge: '%env(BOUNCE_IMAP_PURGE)%' + imap_bounce.purge_unprocessed: '%env(BOUNCE_IMAP_PURGE_UNPROCESSED)%' + + # Messenger configuration for asynchronous processing + app.messenger_transport_dsn: '%env(MESSENGER_TRANSPORT_DSN)%' + + # A secret key that's used to generate certain security-related tokens + secret: '%env(PHPLIST_SECRET)%' + phplist.verify_ssl: '%env(VERIFY_SSL)%' + + graylog_host: 'graylog.phplist.local' + graylog_port: 12201 + + app.phplist_isp_conf_path: '%env(APP_PHPLIST_ISP_CONF_PATH)%' + + # Message sending + messaging.mail_queue_batch_size: '%env(MAILQUEUE_BATCH_SIZE)%' + messaging.mail_queue_period: '%env(MAILQUEUE_BATCH_PERIOD)%' + messaging.mail_queue_throttle: '%env(MAILQUEUE_THROTTLE)%' + messaging.max_process_time: '%env(MESSAGING_MAX_PROCESS_TIME)%' + messaging.max_mail_size: '%env(MAX_MAILSIZE)%' + messaging.default_message_age: '%env(DEFAULT_MESSAGEAGE)%' + messaging.use_manual_text_part: '%env(USE_MANUAL_TEXT_PART)%' + messaging.blacklist_grace_time: '%env(MESSAGING_BLACKLIST_GRACE_TIME)%' + messaging.google_sender_id: '%env(GOOGLE_SENDERID)%' + messaging.use_amazon_ses: '%env(USE_AMAZONSES)%' + messaging.use_precedence_header: '%env(USE_PRECEDENCE_HEADER)%' + messaging.embed_external_images: '%env(EMBEDEXTERNALIMAGES)%' + messaging.embed_uploaded_images: '%env(EMBEDUPLOADIMAGES)%' + messaging.external_image_max_age: '%env(EXTERNALIMAGE_MAXAGE)%' + messaging.external_image_timeout: '%env(EXTERNALIMAGE_TIMEOUT)%' + messaging.external_image_max_size: '%env(EXTERNALIMAGE_MAXSIZE)%' + messaging.forward_alternative_content: '%env(FORWARD_ALTERNATIVE_CONTENT)%' + messaging.email_text_credits: '%env(EMAILTEXTCREDITS)%' + messaging.always_add_user_track: '%env(ALWAYS_ADD_USERTRACK)%' + messaging.send_list_admin_copy: '%env(SEND_LISTADMIN_COPY)%' + + phplist.forward_email_period: '%env(FORWARD_EMAIL_PERIOD)%' + phplist.forward_email_count: '%env(FORWARD_EMAIL_COUNT)%' + phplist.forward_personal_note_size: '%env(FORWARD_PERSONAL_NOTE_SIZE)%' + phplist.forward_friend_count_attribute: '%env(FORWARD_FRIEND_COUNT_ATTRIBUTE)%' + phplist.keep_forwarded_attributes: '%env(KEEPFORWARDERATTRIBUTES)%' + + phplist.upload_images_dir: '%env(UPLOADIMAGES_DIR)%' + phplist.uploads.allowed_mime_types: ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/svg+xml'] + phplist.uploads.allowed_extensions: ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg'] + phplist.uploads.max_size: '%env(PHPLIST_UPLOADS_MAX_SIZE)%' + + phplist.public_schema: '%env(PUBLIC_SCHEMA)%' + phplist.attachment_download_url: '%env(PHPLIST_ATTACHMENT_DOWNLOAD_URL)%' + phplist.attachment_repository_path: '%env(PHPLIST_ATTACHMENT_REPOSITORY_PATH)%' + phplist.max_avatar_size: '%env(MAX_AVATAR_SIZE)%' diff --git a/config/parameters.yml.dist b/config/parameters.yml.dist deleted file mode 100644 index cf9a17e6..00000000 --- a/config/parameters.yml.dist +++ /dev/null @@ -1,168 +0,0 @@ -# This file is a "template" of what your parameters.yml file should look like -# Set parameters here that may be different on each deployment target of the app, e.g. development, staging, production. -# https://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration -# -# These variables are read from environment variables using the "env" construct. -# You can set environment variables in the Apache host configuration and also on the command line. -# If you cannot provide any environment variables, you can also set the variables in this file -# in the lines with "env(VARIABLE_NAME)". -parameters: - database_driver: '%%env(PHPLIST_DATABASE_DRIVER)%%' - env(PHPLIST_DATABASE_DRIVER): 'pdo_mysql' - database_path: '%%env(PHPLIST_DATABASE_PATH)%%' - env(PHPLIST_DATABASE_PATH): null - database_host: '%%env(PHPLIST_DATABASE_HOST)%%' - env(PHPLIST_DATABASE_HOST): '127.0.0.1' - database_port: '%%env(PHPLIST_DATABASE_PORT)%%' - env(PHPLIST_DATABASE_PORT): '3306' - database_name: '%%env(PHPLIST_DATABASE_NAME)%%' - env(PHPLIST_DATABASE_NAME): 'phplistdb' - database_user: '%%env(PHPLIST_DATABASE_USER)%%' - env(PHPLIST_DATABASE_USER): 'phplist' - database_password: '%%env(PHPLIST_DATABASE_PASSWORD)%%' - env(PHPLIST_DATABASE_PASSWORD): 'phplist' - database_prefix: '%%env(DATABASE_PREFIX)%%' - env(DATABASE_PREFIX): 'phplist_' - list_table_prefix: '%%env(LIST_TABLE_PREFIX)%%' - env(LIST_TABLE_PREFIX): 'listattr_' - app.dev_version: '%%env(APP_DEV_VERSION)%%' - env(APP_DEV_VERSION): '0' - app.dev_email: '%%env(APP_DEV_EMAIL)%%' - env(APP_DEV_EMAIL): 'dev@dev.com' - app.powered_by_phplist: '%%env(APP_POWERED_BY_PHPLIST)%%' - env(APP_POWERED_BY_PHPLIST): '0' - app.preference_page_show_private_lists: '%%env(PREFERENCEPAGE_SHOW_PRIVATE_LISTS)%%' - env(PREFERENCEPAGE_SHOW_PRIVATE_LISTS): '0' - app.rest_api_base_url: '%%env(REST_API_BASE_URL)%%' - env(REST_API_BASE_URL): 'http://api.phplist.local/api/v2' - api_base_url: '%%env(API_BASE_URL)%%' - env(API_BASE_URL): 'http://api.phplist.local/' - app.frontend_base_url: '%%env(FRONT_END_BASE_URL)%%' - env(FRONT_END_BASE_URL): 'http://frontend.phplist.local' - parallel_use_with_phplist3: '%%env(parallel_use_with_phplist3)%%' - env(parallel_use_with_phplist3): '0' - - # Email configuration - app.mailer_from: '%%env(MAILER_FROM)%%' - env(MAILER_FROM): 'noreply@phplist.com' - app.mailer_dsn: '%%env(MAILER_DSN)%%' - env(MAILER_DSN): 'null://null' # set local_domain on transport - app.confirmation_url: '%%env(CONFIRMATION_URL)%%' - env(CONFIRMATION_URL): 'http://api.phplist.local/api/v2/subscriber/confirm/' - app.subscription_confirmation_url: '%%env(SUBSCRIPTION_CONFIRMATION_URL)%%' - env(SUBSCRIPTION_CONFIRMATION_URL): 'http://api.phplist.local/api/v2/subscription/confirm/' - app.password_reset_url: '%%env(PASSWORD_RESET_URL)%%' - env(PASSWORD_RESET_URL): 'https://example.com/reset/' - app.show_unsubscribe_link: '%%env(SHOW_UNSUBSCRIBELINK)%%' - env(SHOW_UNSUBSCRIBELINK): '1' - - # bounce email settings - imap_bounce.email: '%%env(BOUNCE_EMAIL)%%' - env(BOUNCE_EMAIL): 'bounce@phplist.com' - imap_bounce.password: '%%env(BOUNCE_IMAP_PASS)%%' - env(BOUNCE_IMAP_PASS): 'bounce@phplist.com' - imap_bounce.host: '%%env(BOUNCE_IMAP_HOST)%%' - env(BOUNCE_IMAP_HOST): 'imap.phplist.com' - imap_bounce.port: '%%env(BOUNCE_IMAP_PORT)%%' - env(BOUNCE_IMAP_PORT): '993' - imap_bounce.encryption: '%%env(BOUNCE_IMAP_ENCRYPTION)%%' - env(BOUNCE_IMAP_ENCRYPTION): 'ssl' - imap_bounce.mailbox: '%%env(BOUNCE_IMAP_MAILBOX)%%' - env(BOUNCE_IMAP_MAILBOX): '/var/spool/mail/bounces' - imap_bounce.mailbox_name: '%%env(BOUNCE_IMAP_MAILBOX_NAME)%%' - env(BOUNCE_IMAP_MAILBOX_NAME): 'INBOX,ONE_MORE' - imap_bounce.protocol: '%%env(BOUNCE_IMAP_PROTOCOL)%%' - env(BOUNCE_IMAP_PROTOCOL): 'imap' - imap_bounce.unsubscribe_threshold: '%%env(BOUNCE_IMAP_UNSUBSCRIBE_THRESHOLD)%%' - env(BOUNCE_IMAP_UNSUBSCRIBE_THRESHOLD): '5' - imap_bounce.blacklist_threshold: '%%env(BOUNCE_IMAP_BLACKLIST_THRESHOLD)%%' - env(BOUNCE_IMAP_BLACKLIST_THRESHOLD): '3' - imap_bounce.purge: '%%env(BOUNCE_IMAP_PURGE)%%' - env(BOUNCE_IMAP_PURGE): '0' - imap_bounce.purge_unprocessed: '%%env(BOUNCE_IMAP_PURGE_UNPROCESSED)%%' - env(BOUNCE_IMAP_PURGE_UNPROCESSED): '0' - - # Messenger configuration for asynchronous processing - app.messenger_transport_dsn: '%%env(MESSENGER_TRANSPORT_DSN)%%' - env(MESSENGER_TRANSPORT_DSN): 'doctrine://default?auto_setup=true' - - # A secret key that's used to generate certain security-related tokens - secret: '%%env(PHPLIST_SECRET)%%' - env(PHPLIST_SECRET): %1$s - phplist.verify_ssl: '%%env(VERIFY_SSL)%%' - env(VERIFY_SSL): '1' - - graylog_host: 'graylog.phplist.local' - graylog_port: 12201 - - app.phplist_isp_conf_path: '%%env(APP_PHPLIST_ISP_CONF_PATH)%%' - env(APP_PHPLIST_ISP_CONF_PATH): '/etc/phplist.conf' - - # Message sending - messaging.mail_queue_batch_size: '%%env(MAILQUEUE_BATCH_SIZE)%%' - env(MAILQUEUE_BATCH_SIZE): '5' - messaging.mail_queue_period: '%%env(MAILQUEUE_BATCH_PERIOD)%%' - env(MAILQUEUE_BATCH_PERIOD): '5' - messaging.mail_queue_throttle: '%%env(MAILQUEUE_THROTTLE)%%' - env(MAILQUEUE_THROTTLE): '5' - messaging.max_process_time: '%%env(MESSAGING_MAX_PROCESS_TIME)%%' - env(MESSAGING_MAX_PROCESS_TIME): '600' - messaging.max_mail_size: '%%env(MAX_MAILSIZE)%%' - env(MAX_MAILSIZE): '209715200' - messaging.default_message_age: '%%env(DEFAULT_MESSAGEAGE)%%' - env(DEFAULT_MESSAGEAGE): '691200' - messaging.use_manual_text_part: '%%env(USE_MANUAL_TEXT_PART)%%' - env(USE_MANUAL_TEXT_PART): '0' - messaging.blacklist_grace_time: '%%env(MESSAGING_BLACKLIST_GRACE_TIME)%%' - env(MESSAGING_BLACKLIST_GRACE_TIME): '600' - messaging.google_sender_id: '%%env(GOOGLE_SENDERID)%%' - env(GOOGLE_SENDERID): '' - messaging.use_amazon_ses: '%%env(USE_AMAZONSES)%%' - env(USE_AMAZONSES): '0' - messaging.use_precedence_header: '%%env(USE_PRECEDENCE_HEADER)%%' - env(USE_PRECEDENCE_HEADER): '0' - messaging.embed_external_images: '%%env(EMBEDEXTERNALIMAGES)%%' - env(EMBEDEXTERNALIMAGES): '0' - messaging.embed_uploaded_images: '%%env(EMBEDUPLOADIMAGES)%%' - env(EMBEDUPLOADIMAGES): '0' - messaging.external_image_max_age: '%%env(EXTERNALIMAGE_MAXAGE)%%' - env(EXTERNALIMAGE_MAXAGE): '0' - messaging.external_image_timeout: '%%env(EXTERNALIMAGE_TIMEOUT)%%' - env(EXTERNALIMAGE_TIMEOUT): '30' - messaging.external_image_max_size: '%%env(EXTERNALIMAGE_MAXSIZE)%%' - env(EXTERNALIMAGE_MAXSIZE): '204800' - messaging.forward_alternative_content: '%%env(FORWARD_ALTERNATIVE_CONTENT)%%' - env(FORWARD_ALTERNATIVE_CONTENT): '0' - messaging.email_text_credits: '%%env(EMAILTEXTCREDITS)%%' - env(EMAILTEXTCREDITS): '0' - messaging.always_add_user_track: '%%env(ALWAYS_ADD_USERTRACK)%%' - env(ALWAYS_ADD_USERTRACK): '1' - messaging.send_list_admin_copy: '%%env(SEND_LISTADMIN_COPY)%%' - env(SEND_LISTADMIN_COPY): '0' - - phplist.forward_email_period: '%%env(FORWARD_EMAIL_PERIOD)%%' - env(FORWARD_EMAIL_PERIOD): '1 minute' - phplist.forward_email_count: '%%env(FORWARD_EMAIL_COUNT)%%' - env(FORWARD_EMAIL_COUNT): '1' - phplist.forward_personal_note_size: '%%env(FORWARD_PERSONAL_NOTE_SIZE)%%' - env(FORWARD_PERSONAL_NOTE_SIZE): '0' - phplist.forward_friend_count_attribute: '%%env(FORWARD_FRIEND_COUNT_ATTRIBUTE)%%' - env(FORWARD_FRIEND_COUNT_ATTRIBUTE): '' - phplist.keep_forwarded_attributes: '%%env(KEEPFORWARDERATTRIBUTES)%%' - env(KEEPFORWARDERATTRIBUTES): '0' - - phplist.upload_images_dir: '%%env(UPLOADIMAGES_DIR)%%' - env(UPLOADIMAGES_DIR): 'uploadimages' - phplist.uploads.allowed_mime_types: ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/svg+xml'] - phplist.uploads.allowed_extensions: ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg'] - phplist.uploads.max_size: '%%env(PHPLIST_UPLOADS_MAX_SIZE)%%' - env(PHPLIST_UPLOADS_MAX_SIZE): '5M' - - phplist.public_schema: '%%env(PUBLIC_SCHEMA)%%' - env(PUBLIC_SCHEMA): 'https' - phplist.attachment_download_url: '%%env(PHPLIST_ATTACHMENT_DOWNLOAD_URL)%%' - env(PHPLIST_ATTACHMENT_DOWNLOAD_URL): 'https://example.com/download/' - phplist.attachment_repository_path: '%%env(PHPLIST_ATTACHMENT_REPOSITORY_PATH)%%' - env(PHPLIST_ATTACHMENT_REPOSITORY_PATH): '/tmp' - phplist.max_avatar_size: '%%env(MAX_AVATAR_SIZE)%%' - env(MAX_AVATAR_SIZE): '100000' diff --git a/config/services.yml b/config/services.yml index 7c053ed9..1fcc3b35 100644 --- a/config/services.yml +++ b/config/services.yml @@ -51,6 +51,10 @@ services: tags: - { name: 'doctrine.dbal.schema_filter', connection: 'default' } + PhpList\Core\Core\Doctrine\TablePrefixListener: + arguments: + $tablePrefix: '%database_prefix%' + HTMLPurifier_Config: class: HTMLPurifier_Config factory: [ 'HTMLPurifier_Config', 'createDefault' ] diff --git a/public/app.php b/public/app.php deleted file mode 100644 index 8e58c4f4..00000000 --- a/public/app.php +++ /dev/null @@ -1,11 +0,0 @@ -configure() - ->dispatch(); diff --git a/public/app_dev.php b/public/app_dev.php deleted file mode 100644 index 46c49194..00000000 --- a/public/app_dev.php +++ /dev/null @@ -1,14 +0,0 @@ -ensureDevelopmentOrTestingEnvironment() - ->setEnvironment(Environment::DEVELOPMENT) - ->configure() - ->dispatch(); diff --git a/public/app_test.php b/public/app_test.php deleted file mode 100644 index af816b87..00000000 --- a/public/app_test.php +++ /dev/null @@ -1,14 +0,0 @@ -ensureDevelopmentOrTestingEnvironment() - ->setEnvironment(Environment::TESTING) - ->configure() - ->dispatch(); diff --git a/src/Composer/ScriptHandler.php b/src/Composer/ScriptHandler.php index 55e23739..426ac71c 100644 --- a/src/Composer/ScriptHandler.php +++ b/src/Composer/ScriptHandler.php @@ -36,17 +36,22 @@ class ScriptHandler /** * @var string */ - const PARAMETERS_CONFIGURATION_FILE = '/config/parameters.yml'; + const GENERAL_CONFIGURATION_FILE = '/config/config_modules.yml'; /** * @var string */ - const GENERAL_CONFIGURATION_FILE = '/config/config_modules.yml'; + const DOTENV_FILE = '/.env'; + + /** + * @var string + */ + const DOTENV_TEMPLATE_FILE = '/.env.dist'; /** * @var string */ - const PARAMETERS_TEMPLATE_FILE = '/config/parameters.yml.dist'; + const PARAMETERS_CONFIGURATION_FILE = '/config/parameters.yml'; /** * @return string absolute application root directory without the trailing slash @@ -265,23 +270,40 @@ public static function clearAllCaches():void } /** - * Creates config/parameters.yml (the parameters configuration file). + * Creates the .env file (the environment variables consumed by the parameters configuration) + * by copying it from .env.dist, generating a fresh app secret in the process. * * @return void */ - public static function createParametersConfiguration(): void + public static function createDotenvConfiguration(): void { - $configurationFilePath = self::getApplicationRoot() . self::PARAMETERS_CONFIGURATION_FILE; - if (file_exists($configurationFilePath)) { + $appDotenvFilePath = self::getApplicationRoot() . self::DOTENV_FILE; + $templateFilePath = __DIR__ . '/../..' . static::DOTENV_TEMPLATE_FILE; + + if (file_exists($appDotenvFilePath)) { return; } - $templateFilePath = __DIR__ . '/../..' . static::PARAMETERS_TEMPLATE_FILE; $template = file_get_contents($templateFilePath); $secret = bin2hex(random_bytes(20)); $configuration = sprintf($template, $secret); + self::createAndWriteFile($appDotenvFilePath, $configuration); + } + + + /** + * Creates config/parameters.yml (the parameters configuration file). + * + * @return void + */ + public static function createParametersConfiguration(): void + { + $configurationFilePath = self::getApplicationRoot() . self::PARAMETERS_CONFIGURATION_FILE; + $templateFilePath = __DIR__ . '/../..' . static::PARAMETERS_CONFIGURATION_FILE; + $configuration = file_get_contents($templateFilePath); + self::createAndWriteFile($configurationFilePath, $configuration); } diff --git a/src/Core/ApplicationKernel.php b/src/Core/ApplicationKernel.php index 8f43e62b..8f67de65 100644 --- a/src/Core/ApplicationKernel.php +++ b/src/Core/ApplicationKernel.php @@ -128,6 +128,11 @@ public function registerContainerConfiguration(LoaderInterface $loader): void if (file_exists($twigConfigFile)) { $loader->load($twigConfigFile); } + + $messengerConfigFile = $this->getApplicationDir() . '/config/packages/messenger.yaml'; + if (file_exists($messengerConfigFile)) { + $loader->load($messengerConfigFile); + } } /** diff --git a/src/Core/Bootstrap.php b/src/Core/Bootstrap.php index 82ddb28f..4c7af464 100644 --- a/src/Core/Bootstrap.php +++ b/src/Core/Bootstrap.php @@ -7,6 +7,7 @@ use Doctrine\ORM\EntityManagerInterface; use Exception; use RuntimeException; +use Symfony\Component\Dotenv\Dotenv; use Symfony\Component\ErrorHandler\ErrorHandler; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\Request; @@ -147,10 +148,50 @@ public function configure(): Bootstrap { $this->isConfigured = true; - return $this->configureDebugging() + return $this->loadEnvironmentVariables() + ->configureDebugging() ->configureApplicationKernel(); } + /** + * Loads environment variables from the application's ".env" files (if present) using Symfony Dotenv, + * following the standard ".env" -> ".env.local" -> ".env.$environment" -> ".env.$environment.local" cascade. + * + * ".env.dist" is a template only and must never be used to source real configuration: Symfony Dotenv + * would otherwise silently load it (with its literal placeholder values) whenever ".env" is missing. + * + * @return Bootstrap fluent interface + * + * @throws RuntimeException if ".env" does not exist, or PHPLIST_SECRET was not resolved to a real value + * @SuppressWarnings("PHPMD.Superglobals") + */ + private function loadEnvironmentVariables(): Bootstrap + { + $applicationRoot = $this->applicationStructure->getApplicationRoot(); + $dotenvPath = $applicationRoot . '/.env'; + if (!file_exists($dotenvPath)) { + throw new RuntimeException( + 'No ".env" file was found at "' . $dotenvPath . '". Run "composer install"/"composer update" ' . + 'to generate it from ".env.dist" (which is a template only and must not be used directly), ' . + 'or create ".env" manually with a real PHPLIST_SECRET.', + 1754766600 + ); + } + + (new Dotenv())->loadEnv($dotenvPath, 'APP_ENV', $this->environment); + + $secret = $_SERVER['PHPLIST_SECRET'] ?? $_ENV['PHPLIST_SECRET'] ?? ''; + if ($secret === '' || $secret === '%s') { + throw new RuntimeException( + 'PHPLIST_SECRET in ".env" is missing or still set to the ".env.dist" template placeholder. ' . + 'Set it to a real, unique, freshly generated secret before starting the application.', + 1754766601 + ); + } + + return $this; + } + /** * Makes sure that configure has been called before. * diff --git a/src/Core/Doctrine/TablePrefixListener.php b/src/Core/Doctrine/TablePrefixListener.php new file mode 100644 index 00000000..eee9098f --- /dev/null +++ b/src/Core/Doctrine/TablePrefixListener.php @@ -0,0 +1,34 @@ +getClassMetadata(); + + if ($metadata->isMappedSuperclass || $metadata->isEmbeddedClass) { + return; + } + + if (!str_starts_with($metadata->getName(), 'PhpList\\Core\\Domain\\')) { + return; + } + + $metadata->setPrimaryTable([ + 'name' => $this->tablePrefix . $metadata->getTableName(), + ]); + } +} diff --git a/src/Domain/Analytics/Model/LinkTrack.php b/src/Domain/Analytics/Model/LinkTrack.php index 848dde5e..1c8b3755 100644 --- a/src/Domain/Analytics/Model/LinkTrack.php +++ b/src/Domain/Analytics/Model/LinkTrack.php @@ -12,7 +12,7 @@ use PhpList\Core\Domain\Common\Model\Interfaces\Identity; #[ORM\Entity(repositoryClass: LinkTrackRepository::class)] -#[ORM\Table(name: 'phplist_linktrack')] +#[ORM\Table(name: 'linktrack')] #[ORM\UniqueConstraint(name: 'phplist_linktrack_miduidurlindex', columns: ['messageid', 'userid', 'url'])] #[ORM\Index(name: 'phplist_linktrack_midindex', columns: ['messageid'])] #[ORM\Index(name: 'phplist_linktrack_miduidindex', columns: ['messageid', 'userid'])] diff --git a/src/Domain/Analytics/Model/LinkTrackForward.php b/src/Domain/Analytics/Model/LinkTrackForward.php index 0e03c017..2bc059b0 100644 --- a/src/Domain/Analytics/Model/LinkTrackForward.php +++ b/src/Domain/Analytics/Model/LinkTrackForward.php @@ -10,7 +10,7 @@ use PhpList\Core\Domain\Common\Model\Interfaces\Identity; #[ORM\Entity(repositoryClass: LinkTrackForwardRepository::class)] -#[ORM\Table(name: 'phplist_linktrack_forward')] +#[ORM\Table(name: 'linktrack_forward')] #[ORM\UniqueConstraint(name: 'phplist_linktrack_forward_urlunique', columns: ['urlhash'])] #[ORM\Index(name: 'phplist_linktrack_forward_urlindex', columns: ['url'])] #[ORM\Index(name: 'phplist_linktrack_forward_uuididx', columns: ['uuid'])] diff --git a/src/Domain/Analytics/Model/LinkTrackMl.php b/src/Domain/Analytics/Model/LinkTrackMl.php index 419c7911..ff6bab0a 100644 --- a/src/Domain/Analytics/Model/LinkTrackMl.php +++ b/src/Domain/Analytics/Model/LinkTrackMl.php @@ -10,7 +10,7 @@ use PhpList\Core\Domain\Common\Model\Interfaces\DomainModel; #[ORM\Entity(repositoryClass: LinkTrackMlRepository::class)] -#[ORM\Table(name: 'phplist_linktrack_ml')] +#[ORM\Table(name: 'linktrack_ml')] #[ORM\Index(name: 'phplist_linktrack_ml_fwdindex', columns: ['forwardid'])] #[ORM\Index(name: 'phplist_linktrack_ml_midindex', columns: ['messageid'])] class LinkTrackMl implements DomainModel diff --git a/src/Domain/Analytics/Model/LinkTrackUmlClick.php b/src/Domain/Analytics/Model/LinkTrackUmlClick.php index 3faf811d..93a4b487 100644 --- a/src/Domain/Analytics/Model/LinkTrackUmlClick.php +++ b/src/Domain/Analytics/Model/LinkTrackUmlClick.php @@ -11,7 +11,7 @@ use PhpList\Core\Domain\Common\Model\Interfaces\Identity; #[ORM\Entity(repositoryClass: LinkTrackUmlClickRepository::class)] -#[ORM\Table(name: 'phplist_linktrack_uml_click')] +#[ORM\Table(name: 'linktrack_uml_click')] #[ORM\UniqueConstraint(name: 'phplist_linktrack_uml_click_miduidfwdid', columns: ['messageid', 'userid', 'forwardid'])] #[ORM\Index(name: 'phplist_linktrack_uml_click_midindex', columns: ['messageid'])] #[ORM\Index(name: 'phplist_linktrack_uml_click_miduidindex', columns: ['messageid', 'userid'])] diff --git a/src/Domain/Analytics/Model/LinkTrackUserClick.php b/src/Domain/Analytics/Model/LinkTrackUserClick.php index 27205cbb..3725cf15 100644 --- a/src/Domain/Analytics/Model/LinkTrackUserClick.php +++ b/src/Domain/Analytics/Model/LinkTrackUserClick.php @@ -10,7 +10,7 @@ use PhpList\Core\Domain\Common\Model\Interfaces\DomainModel; #[ORM\Entity(repositoryClass: LinkTrackUserClickRepository::class)] -#[ORM\Table(name: 'phplist_linktrack_userclick')] +#[ORM\Table(name: 'linktrack_userclick')] #[ORM\Index(name: 'phplist_linktrack_userclick_linkindex', columns: ['linkid'])] #[ORM\Index(name: 'phplist_linktrack_userclick_linkuserindex', columns: ['linkid', 'userid'])] #[ORM\Index(name: 'phplist_linktrack_userclick_linkusermessageindex', columns: ['linkid', 'userid', 'messageid'])] diff --git a/src/Domain/Analytics/Model/UserMessageView.php b/src/Domain/Analytics/Model/UserMessageView.php index b391d3f3..7c0e1b36 100644 --- a/src/Domain/Analytics/Model/UserMessageView.php +++ b/src/Domain/Analytics/Model/UserMessageView.php @@ -11,7 +11,7 @@ use PhpList\Core\Domain\Common\Model\Interfaces\Identity; #[ORM\Entity(repositoryClass: UserMessageViewRepository::class)] -#[ORM\Table(name: 'phplist_user_message_view')] +#[ORM\Table(name: 'user_message_view')] #[ORM\Index(name: 'phplist_user_message_view_msgidx', columns: ['messageid'])] #[ORM\Index(name: 'phplist_user_message_view_useridx', columns: ['userid'])] #[ORM\Index(name: 'phplist_user_message_view_usermsgidx', columns: ['userid', 'messageid'])] diff --git a/src/Domain/Analytics/Model/UserStats.php b/src/Domain/Analytics/Model/UserStats.php index c7b4b97e..57e671f7 100644 --- a/src/Domain/Analytics/Model/UserStats.php +++ b/src/Domain/Analytics/Model/UserStats.php @@ -10,7 +10,7 @@ use PhpList\Core\Domain\Common\Model\Interfaces\Identity; #[ORM\Entity(repositoryClass: UserStatsRepository::class)] -#[ORM\Table(name: 'phplist_userstats')] +#[ORM\Table(name: 'userstats')] #[ORM\UniqueConstraint(name: 'phplist_userstats_entry', columns: ['unixdate', 'item', 'listid'])] #[ORM\Index(name: 'phplist_userstats_dateindex', columns: ['unixdate'])] #[ORM\Index(name: 'phplist_userstats_itemindex', columns: ['item'])] diff --git a/src/Domain/Configuration/Model/Config.php b/src/Domain/Configuration/Model/Config.php index 00f0a6c5..80f60f19 100644 --- a/src/Domain/Configuration/Model/Config.php +++ b/src/Domain/Configuration/Model/Config.php @@ -9,7 +9,7 @@ use PhpList\Core\Domain\Configuration\Repository\ConfigRepository; #[ORM\Entity(repositoryClass: ConfigRepository::class)] -#[ORM\Table(name: 'phplist_config')] +#[ORM\Table(name: 'config')] class Config implements DomainModel { #[ORM\Id] diff --git a/src/Domain/Configuration/Model/EventLog.php b/src/Domain/Configuration/Model/EventLog.php index c0cff22b..7e1ac3af 100644 --- a/src/Domain/Configuration/Model/EventLog.php +++ b/src/Domain/Configuration/Model/EventLog.php @@ -12,7 +12,7 @@ use PhpList\Core\Domain\Configuration\Repository\EventLogRepository; #[ORM\Entity(repositoryClass: EventLogRepository::class)] -#[ORM\Table(name: 'phplist_eventlog')] +#[ORM\Table(name: 'eventlog')] #[ORM\Index(name: 'phplist_eventlog_enteredidx', columns: ['entered'])] #[ORM\Index(name: 'phplist_eventlog_pageidx', columns: ['page'])] #[ORM\HasLifecycleCallbacks] diff --git a/src/Domain/Configuration/Model/I18n.php b/src/Domain/Configuration/Model/I18n.php index 72397bb4..0f709259 100644 --- a/src/Domain/Configuration/Model/I18n.php +++ b/src/Domain/Configuration/Model/I18n.php @@ -14,7 +14,7 @@ * Symfony\Contracts\Translation will be used instead. */ #[ORM\Entity(repositoryClass: I18nRepository::class)] -#[ORM\Table(name: 'phplist_i18n')] +#[ORM\Table(name: 'i18n')] #[ORM\UniqueConstraint(name: 'phplist_i18n_lanorigunq', columns: ['lan', 'original'])] #[ORM\Index(name: 'phplist_i18n_lanorigidx', columns: ['lan', 'original'])] class I18n implements DomainModel diff --git a/src/Domain/Configuration/Model/UrlCache.php b/src/Domain/Configuration/Model/UrlCache.php index b6d032b9..a8394212 100644 --- a/src/Domain/Configuration/Model/UrlCache.php +++ b/src/Domain/Configuration/Model/UrlCache.php @@ -11,7 +11,7 @@ use PhpList\Core\Domain\Configuration\Repository\UrlCacheRepository; #[ORM\Entity(repositoryClass: UrlCacheRepository::class)] -#[ORM\Table(name: 'phplist_urlcache')] +#[ORM\Table(name: 'urlcache')] #[ORM\Index(name: 'phplist_urlcache_urlindex', columns: ['url'])] #[ORM\HasLifecycleCallbacks] class UrlCache implements DomainModel, Identity diff --git a/src/Domain/Configuration/Service/Provider/ConfigProvider.php b/src/Domain/Configuration/Service/Provider/ConfigProvider.php index 3b22285f..2890a86d 100644 --- a/src/Domain/Configuration/Service/Provider/ConfigProvider.php +++ b/src/Domain/Configuration/Service/Provider/ConfigProvider.php @@ -33,7 +33,7 @@ public function isEnabled(ConfigOption $key): bool if (!in_array($key, $this->booleanValues, true)) { throw new InvalidArgumentException('Invalid boolean value key'); } - $config = $this->configRepository->findOneBy(['item' => $key->value]); + $config = $this->configRepository->findOneBy(['key' => $key->value]); if ($config !== null) { return filter_var($config->getValue(), FILTER_VALIDATE_BOOLEAN); diff --git a/src/Domain/Identity/Command/ImportDefaultsCommand.php b/src/Domain/Identity/Command/ImportDefaultsCommand.php index 47ac4295..c91457c3 100644 --- a/src/Domain/Identity/Command/ImportDefaultsCommand.php +++ b/src/Domain/Identity/Command/ImportDefaultsCommand.php @@ -15,6 +15,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Question\Question; +use Symfony\Component\DependencyInjection\Attribute\Autowire; #[AsCommand( name: 'phplist:defaults:import', @@ -29,6 +30,8 @@ public function __construct( private readonly AdministratorRepository $administratorRepository, private readonly AdministratorManager $administratorManager, private readonly EntityManagerInterface $entityManager, + #[Autowire('%app.default_admin_password%')] + private readonly string $defaultAdminPassword = '' ) { parent::__construct(); } @@ -37,15 +40,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int { $login = self::DEFAULT_LOGIN; $email = self::DEFAULT_EMAIL; - $envPassword = getenv('PHPLIST_ADMIN_PASSWORD'); - $envPassword = is_string($envPassword) && trim($envPassword) !== '' ? $envPassword : null; + $password = $this->defaultAdminPassword !== '' ? $this->defaultAdminPassword : null; $allPrivileges = $this->allPrivilegesGranted(); $existing = $this->administratorRepository->findOneBy(['loginName' => $login]); if ($existing === null) { // If creating the default admin, require a password. Prefer env var, else prompt for input. - $password = $envPassword; if ($password === null) { /** @var QuestionHelper $helper */ $helper = $this->getHelper('question'); diff --git a/src/Domain/Identity/Model/AdminAttributeDefinition.php b/src/Domain/Identity/Model/AdminAttributeDefinition.php index 3fe45e76..c2b20d0b 100644 --- a/src/Domain/Identity/Model/AdminAttributeDefinition.php +++ b/src/Domain/Identity/Model/AdminAttributeDefinition.php @@ -12,7 +12,7 @@ use PhpList\Core\Domain\Identity\Repository\AdminAttributeDefinitionRepository; #[ORM\Entity(repositoryClass: AdminAttributeDefinitionRepository::class)] -#[ORM\Table(name: 'phplist_adminattribute')] +#[ORM\Table(name: 'adminattribute')] #[ORM\HasLifecycleCallbacks] class AdminAttributeDefinition implements DomainModel, Identity { diff --git a/src/Domain/Identity/Model/AdminAttributeValue.php b/src/Domain/Identity/Model/AdminAttributeValue.php index 3d99ba73..35188ec6 100644 --- a/src/Domain/Identity/Model/AdminAttributeValue.php +++ b/src/Domain/Identity/Model/AdminAttributeValue.php @@ -9,7 +9,7 @@ use PhpList\Core\Domain\Identity\Repository\AdminAttributeValueRepository; #[ORM\Entity(repositoryClass: AdminAttributeValueRepository::class)] -#[ORM\Table(name: 'phplist_admin_attribute')] +#[ORM\Table(name: 'admin_attribute')] #[ORM\HasLifecycleCallbacks] class AdminAttributeValue implements DomainModel { diff --git a/src/Domain/Identity/Model/AdminLogin.php b/src/Domain/Identity/Model/AdminLogin.php index 91be3331..74d9abee 100644 --- a/src/Domain/Identity/Model/AdminLogin.php +++ b/src/Domain/Identity/Model/AdminLogin.php @@ -12,7 +12,7 @@ use PhpList\Core\Domain\Identity\Repository\AdminLoginRepository; #[ORM\Entity(repositoryClass: AdminLoginRepository::class)] -#[ORM\Table(name: 'phplist_admin_login')] +#[ORM\Table(name: 'admin_login')] #[ORM\HasLifecycleCallbacks] class AdminLogin implements DomainModel, Identity { diff --git a/src/Domain/Identity/Model/AdminPasswordRequest.php b/src/Domain/Identity/Model/AdminPasswordRequest.php index 0d761adf..230e675a 100644 --- a/src/Domain/Identity/Model/AdminPasswordRequest.php +++ b/src/Domain/Identity/Model/AdminPasswordRequest.php @@ -11,7 +11,7 @@ use PhpList\Core\Domain\Identity\Repository\AdminPasswordRequestRepository; #[ORM\Entity(repositoryClass: AdminPasswordRequestRepository::class)] -#[ORM\Table(name: 'phplist_admin_password_request')] +#[ORM\Table(name: 'admin_password_request')] class AdminPasswordRequest implements DomainModel, Identity { #[ORM\Id] diff --git a/src/Domain/Identity/Model/Administrator.php b/src/Domain/Identity/Model/Administrator.php index 2f3de5eb..f6c9ba05 100644 --- a/src/Domain/Identity/Model/Administrator.php +++ b/src/Domain/Identity/Model/Administrator.php @@ -25,7 +25,7 @@ * @author Tatevik Grigoryan */ #[ORM\Entity(repositoryClass: AdministratorRepository::class)] -#[ORM\Table(name: 'phplist_admin')] +#[ORM\Table(name: 'admin')] #[ORM\UniqueConstraint(name: 'phplist_admin_loginnameidx', columns: ['loginname'])] #[ORM\HasLifecycleCallbacks] class Administrator implements DomainModel, Identity, CreationDate, ModificationDate diff --git a/src/Domain/Identity/Model/AdministratorToken.php b/src/Domain/Identity/Model/AdministratorToken.php index 4e37b2b5..3d9da22d 100644 --- a/src/Domain/Identity/Model/AdministratorToken.php +++ b/src/Domain/Identity/Model/AdministratorToken.php @@ -19,7 +19,7 @@ * @author Tateik Grigoryan */ #[ORM\Entity(repositoryClass: AdministratorTokenRepository::class)] -#[ORM\Table(name: 'phplist_admintoken')] +#[ORM\Table(name: 'admintoken')] #[ORM\HasLifecycleCallbacks] class AdministratorToken implements DomainModel, Identity, CreationDate { diff --git a/src/Domain/Messaging/Command/ProcessQueueCommand.php b/src/Domain/Messaging/Command/ProcessQueueCommand.php index 080c24cb..69bf967b 100644 --- a/src/Domain/Messaging/Command/ProcessQueueCommand.php +++ b/src/Domain/Messaging/Command/ProcessQueueCommand.php @@ -27,31 +27,16 @@ )] class ProcessQueueCommand extends Command { - private MessageRepository $messageRepository; - private LockFactory $lockFactory; - private MessageProcessingPreparator $messagePreparator; - private MessageBusInterface $messageBus; - private ConfigProvider $configProvider; - private TranslatorInterface $translator; - private EntityManagerInterface $entityManager; - public function __construct( - MessageRepository $messageRepository, - LockFactory $lockFactory, - MessageProcessingPreparator $messagePreparator, - MessageBusInterface $messageBus, - ConfigProvider $configProvider, - TranslatorInterface $translator, - EntityManagerInterface $entityManager, + private readonly MessageRepository $messageRepository, + private readonly LockFactory $lockFactory, + private readonly MessageProcessingPreparator $messagePreparator, + private readonly MessageBusInterface $messageBus, + private readonly ConfigProvider $configProvider, + private readonly TranslatorInterface $translator, + private readonly EntityManagerInterface $entityManager, ) { parent::__construct(); - $this->messageRepository = $messageRepository; - $this->lockFactory = $lockFactory; - $this->messagePreparator = $messagePreparator; - $this->messageBus = $messageBus; - $this->configProvider = $configProvider; - $this->translator = $translator; - $this->entityManager = $entityManager; } protected function execute(InputInterface $input, OutputInterface $output): int diff --git a/src/Domain/Messaging/Command/SendTestEmailCommand.php b/src/Domain/Messaging/Command/SendTestEmailCommand.php index e9670239..2766af9d 100644 --- a/src/Domain/Messaging/Command/SendTestEmailCommand.php +++ b/src/Domain/Messaging/Command/SendTestEmailCommand.php @@ -21,14 +21,11 @@ )] class SendTestEmailCommand extends Command { - private EmailService $emailService; - private TranslatorInterface $translator; - - public function __construct(EmailService $emailService, TranslatorInterface $translator) - { + public function __construct( + private readonly EmailService $emailService, + private readonly TranslatorInterface $translator + ) { parent::__construct(); - $this->emailService = $emailService; - $this->translator = $translator; } protected function configure(): void diff --git a/src/Domain/Messaging/Model/Attachment.php b/src/Domain/Messaging/Model/Attachment.php index d49cd386..a8b38b4b 100644 --- a/src/Domain/Messaging/Model/Attachment.php +++ b/src/Domain/Messaging/Model/Attachment.php @@ -10,7 +10,7 @@ use PhpList\Core\Domain\Messaging\Repository\AttachmentRepository; #[ORM\Entity(repositoryClass: AttachmentRepository::class)] -#[ORM\Table(name: 'phplist_attachment')] +#[ORM\Table(name: 'attachment')] class Attachment implements DomainModel, Identity { public const FORWARD = 'forwarded'; diff --git a/src/Domain/Messaging/Model/Bounce.php b/src/Domain/Messaging/Model/Bounce.php index 54e5895d..071b869f 100644 --- a/src/Domain/Messaging/Model/Bounce.php +++ b/src/Domain/Messaging/Model/Bounce.php @@ -11,7 +11,7 @@ use PhpList\Core\Domain\Messaging\Repository\BounceRepository; #[ORM\Entity(repositoryClass: BounceRepository::class)] -#[ORM\Table(name: 'phplist_bounce')] +#[ORM\Table(name: 'bounce')] #[ORM\Index(name: 'phplist_bounce_dateindex', columns: ['date'])] #[ORM\Index(name: 'phplist_bounce_statusidx', columns: ['status'])] class Bounce implements DomainModel, Identity diff --git a/src/Domain/Messaging/Model/BounceRegex.php b/src/Domain/Messaging/Model/BounceRegex.php index c54ca7c0..5d0d0521 100644 --- a/src/Domain/Messaging/Model/BounceRegex.php +++ b/src/Domain/Messaging/Model/BounceRegex.php @@ -10,7 +10,7 @@ use PhpList\Core\Domain\Messaging\Repository\BounceRegexRepository; #[ORM\Entity(repositoryClass: BounceRegexRepository::class)] -#[ORM\Table(name: 'phplist_bounceregex')] +#[ORM\Table(name: 'bounceregex')] #[ORM\UniqueConstraint(name: 'phplist_bounceregex_regex', columns: ['regexhash'])] class BounceRegex implements DomainModel, Identity { diff --git a/src/Domain/Messaging/Model/BounceRegexBounce.php b/src/Domain/Messaging/Model/BounceRegexBounce.php index e815cd1f..c50d20d5 100644 --- a/src/Domain/Messaging/Model/BounceRegexBounce.php +++ b/src/Domain/Messaging/Model/BounceRegexBounce.php @@ -9,7 +9,7 @@ use PhpList\Core\Domain\Messaging\Repository\BounceRegexBounceRepository; #[ORM\Entity(repositoryClass: BounceRegexBounceRepository::class)] -#[ORM\Table(name: 'phplist_bounceregex_bounce')] +#[ORM\Table(name: 'bounceregex_bounce')] class BounceRegexBounce implements DomainModel { #[ORM\Id] diff --git a/src/Domain/Messaging/Model/ListMessage.php b/src/Domain/Messaging/Model/ListMessage.php index 3a5d655a..d624b699 100644 --- a/src/Domain/Messaging/Model/ListMessage.php +++ b/src/Domain/Messaging/Model/ListMessage.php @@ -14,7 +14,7 @@ use PhpList\Core\Domain\Subscription\Model\SubscriberList; #[ORM\Entity(repositoryClass: ListMessageRepository::class)] -#[ORM\Table(name: 'phplist_listmessage')] +#[ORM\Table(name: 'listmessage')] #[ORM\UniqueConstraint(name: 'phplist_listmessage_messageid', columns: ['messageid', 'listid'])] #[ORM\Index(name: 'phplist_listmessage_listmessageidx', columns: ['listid', 'messageid'])] #[ORM\HasLifecycleCallbacks] diff --git a/src/Domain/Messaging/Model/Message.php b/src/Domain/Messaging/Model/Message.php index 4d5f4e8f..072661b4 100644 --- a/src/Domain/Messaging/Model/Message.php +++ b/src/Domain/Messaging/Model/Message.php @@ -22,7 +22,7 @@ use PhpList\Core\Domain\Messaging\Repository\MessageRepository; #[ORM\Entity(repositoryClass: MessageRepository::class)] -#[ORM\Table(name: 'phplist_message')] +#[ORM\Table(name: 'message')] #[ORM\Index(name: 'phplist_message_uuididx', columns: ['uuid'])] #[ORM\HasLifecycleCallbacks] class Message implements DomainModel, Identity, ModificationDate, OwnableInterface diff --git a/src/Domain/Messaging/Model/Message/MessageStatus.php b/src/Domain/Messaging/Model/Message/MessageStatus.php index 789f07c2..7f6e0daa 100644 --- a/src/Domain/Messaging/Model/Message/MessageStatus.php +++ b/src/Domain/Messaging/Model/Message/MessageStatus.php @@ -12,7 +12,6 @@ enum MessageStatus: string case InProcess = 'inprocess'; case Sent = 'sent'; case Suspended = 'suspended'; - case Requeued = 'requeued'; /** * Allowed transitions for each state @@ -23,12 +22,10 @@ public function allowedTransitions(): array { return match ($this) { self::Draft => [self::Prepared, self::Submitted], - self::Suspended => [self::Submitted, self::Requeued], + self::Suspended, self::Sent => [self::Submitted], self::Submitted => [self::Prepared, self::InProcess, self::Suspended], self::Prepared => [self::InProcess, self::Suspended], self::InProcess => [self::Sent, self::Suspended, self::Submitted], - self::Requeued => [self::InProcess, self::Suspended], - self::Sent => [self::Requeued], }; } diff --git a/src/Domain/Messaging/Model/MessageAttachment.php b/src/Domain/Messaging/Model/MessageAttachment.php index e26d0d87..2007ad5c 100644 --- a/src/Domain/Messaging/Model/MessageAttachment.php +++ b/src/Domain/Messaging/Model/MessageAttachment.php @@ -9,7 +9,7 @@ use PhpList\Core\Domain\Messaging\Repository\MessageAttachmentRepository; #[ORM\Entity(repositoryClass: MessageAttachmentRepository::class)] -#[ORM\Table(name: 'phplist_message_attachment')] +#[ORM\Table(name: 'message_attachment')] #[ORM\Index(name: 'phplist_message_attachment_messageattidx', columns: ['messageid', 'attachmentid'])] #[ORM\Index(name: 'phplist_message_attachment_messageidx', columns: ['messageid'])] class MessageAttachment implements Identity diff --git a/src/Domain/Messaging/Model/MessageData.php b/src/Domain/Messaging/Model/MessageData.php index 56744251..d364889c 100644 --- a/src/Domain/Messaging/Model/MessageData.php +++ b/src/Domain/Messaging/Model/MessageData.php @@ -9,7 +9,7 @@ use PhpList\Core\Domain\Messaging\Repository\MessageDataRepository; #[ORM\Entity(repositoryClass: MessageDataRepository::class)] -#[ORM\Table(name: 'phplist_messagedata')] +#[ORM\Table(name: 'messagedata')] class MessageData implements DomainModel { #[ORM\Id] diff --git a/src/Domain/Messaging/Model/SendProcess.php b/src/Domain/Messaging/Model/SendProcess.php index 5faeaf35..14abe737 100644 --- a/src/Domain/Messaging/Model/SendProcess.php +++ b/src/Domain/Messaging/Model/SendProcess.php @@ -12,7 +12,7 @@ use PhpList\Core\Domain\Messaging\Repository\SendProcessRepository; #[ORM\Entity(repositoryClass: SendProcessRepository::class)] -#[ORM\Table(name: 'phplist_sendprocess')] +#[ORM\Table(name: 'sendprocess')] #[ORM\HasLifecycleCallbacks] class SendProcess implements DomainModel, Identity, ModificationDate { diff --git a/src/Domain/Messaging/Model/Template.php b/src/Domain/Messaging/Model/Template.php index dc1b67a0..3bbd8c8c 100644 --- a/src/Domain/Messaging/Model/Template.php +++ b/src/Domain/Messaging/Model/Template.php @@ -12,7 +12,7 @@ use PhpList\Core\Domain\Messaging\Repository\TemplateRepository; #[ORM\Entity(repositoryClass: TemplateRepository::class)] -#[ORM\Table(name: 'phplist_template')] +#[ORM\Table(name: 'template')] #[ORM\UniqueConstraint(name: 'phplist_template_title', columns: ['title'])] class Template implements DomainModel, Identity { diff --git a/src/Domain/Messaging/Model/TemplateImage.php b/src/Domain/Messaging/Model/TemplateImage.php index c1c5c8c4..a0da4692 100644 --- a/src/Domain/Messaging/Model/TemplateImage.php +++ b/src/Domain/Messaging/Model/TemplateImage.php @@ -10,7 +10,7 @@ use PhpList\Core\Domain\Messaging\Repository\TemplateImageRepository; #[ORM\Entity(repositoryClass: TemplateImageRepository::class)] -#[ORM\Table(name: 'phplist_templateimage')] +#[ORM\Table(name: 'templateimage')] #[ORM\Index(name: 'phplist_templateimage_templateidx', columns: ['template'])] class TemplateImage implements DomainModel, Identity { diff --git a/src/Domain/Messaging/Model/UserMessage.php b/src/Domain/Messaging/Model/UserMessage.php index d5fe202c..93b457f3 100644 --- a/src/Domain/Messaging/Model/UserMessage.php +++ b/src/Domain/Messaging/Model/UserMessage.php @@ -12,7 +12,7 @@ use PhpList\Core\Domain\Subscription\Model\Subscriber; #[ORM\Entity(repositoryClass: UserMessageRepository::class)] -#[ORM\Table(name: 'phplist_usermessage')] +#[ORM\Table(name: 'usermessage')] #[ORM\Index(name: 'phplist_usermessage_enteredindex', columns: ['entered'])] #[ORM\Index(name: 'phplist_usermessage_messageidindex', columns: ['messageid'])] #[ORM\Index(name: 'phplist_usermessage_statusidx', columns: ['status'])] diff --git a/src/Domain/Messaging/Model/UserMessageBounce.php b/src/Domain/Messaging/Model/UserMessageBounce.php index 3b58bf47..48b97b5c 100644 --- a/src/Domain/Messaging/Model/UserMessageBounce.php +++ b/src/Domain/Messaging/Model/UserMessageBounce.php @@ -11,7 +11,7 @@ use PhpList\Core\Domain\Messaging\Repository\UserMessageBounceRepository; #[ORM\Entity(repositoryClass: UserMessageBounceRepository::class)] -#[ORM\Table(name: 'phplist_user_message_bounce')] +#[ORM\Table(name: 'user_message_bounce')] #[ORM\Index(name: 'phplist_user_message_bounce_bounceidx', columns: ['bounce'])] #[ORM\Index(name: 'phplist_user_message_bounce_msgidx', columns: ['message'])] #[ORM\Index(name: 'phplist_user_message_bounce_umbindex', columns: ['user', 'message', 'bounce'])] diff --git a/src/Domain/Messaging/Model/UserMessageForward.php b/src/Domain/Messaging/Model/UserMessageForward.php index 3b920189..1dd32806 100644 --- a/src/Domain/Messaging/Model/UserMessageForward.php +++ b/src/Domain/Messaging/Model/UserMessageForward.php @@ -11,7 +11,7 @@ use PhpList\Core\Domain\Messaging\Repository\UserMessageForwardRepository; #[ORM\Entity(repositoryClass: UserMessageForwardRepository::class)] -#[ORM\Table(name: 'phplist_user_message_forward')] +#[ORM\Table(name: 'user_message_forward')] #[ORM\Index(name: 'phplist_user_message_forward_messageidx', columns: ['message'])] #[ORM\Index(name: 'phplist_user_message_forward_useridx', columns: ['user'])] #[ORM\Index(name: 'phplist_user_message_forward_usermessageidx', columns: ['user', 'message'])] diff --git a/src/Domain/Messaging/Repository/MessageRepository.php b/src/Domain/Messaging/Repository/MessageRepository.php index d18ce68b..cc22602c 100644 --- a/src/Domain/Messaging/Repository/MessageRepository.php +++ b/src/Domain/Messaging/Repository/MessageRepository.php @@ -116,7 +116,7 @@ public function getByStatusAndEmbargo(Message\MessageStatus $status, DateTimeImm { return $this->createQueryBuilder('m') ->where('m.metadata.status = :status') - ->andWhere('m.schedule.embargo IS NULL OR m.embargo <= :embargo') + ->andWhere('m.schedule.embargo IS NULL OR m.schedule.embargo <= :embargo') ->setParameter('status', $status->value) ->setParameter('embargo', $embargo) ->getQuery() diff --git a/src/Domain/Subscription/Model/SubscribePage.php b/src/Domain/Subscription/Model/SubscribePage.php index 3b484920..bc4ea54f 100644 --- a/src/Domain/Subscription/Model/SubscribePage.php +++ b/src/Domain/Subscription/Model/SubscribePage.php @@ -12,7 +12,7 @@ use PhpList\Core\Domain\Subscription\Repository\SubscriberPageRepository; #[ORM\Entity(repositoryClass: SubscriberPageRepository::class)] -#[ORM\Table(name: 'phplist_subscribepage')] +#[ORM\Table(name: 'subscribepage')] class SubscribePage implements DomainModel, Identity, OwnableInterface { #[ORM\Id] diff --git a/src/Domain/Subscription/Model/SubscribePageData.php b/src/Domain/Subscription/Model/SubscribePageData.php index 7d8dcd4e..8b94e729 100644 --- a/src/Domain/Subscription/Model/SubscribePageData.php +++ b/src/Domain/Subscription/Model/SubscribePageData.php @@ -9,7 +9,7 @@ use PhpList\Core\Domain\Subscription\Repository\SubscriberPageDataRepository; #[ORM\Entity(repositoryClass: SubscriberPageDataRepository::class)] -#[ORM\Table(name: 'phplist_subscribepage_data')] +#[ORM\Table(name: 'subscribepage_data')] class SubscribePageData implements DomainModel { #[ORM\Id] diff --git a/src/Domain/Subscription/Model/Subscriber.php b/src/Domain/Subscription/Model/Subscriber.php index 97d45b83..8eda5ed6 100644 --- a/src/Domain/Subscription/Model/Subscriber.php +++ b/src/Domain/Subscription/Model/Subscriber.php @@ -24,7 +24,7 @@ * @SuppressWarnings(PHPMD.ExcessivePublicCount) */ #[ORM\Entity(repositoryClass: SubscriberRepository::class)] -#[ORM\Table(name: 'phplist_user_user')] +#[ORM\Table(name: 'user_user')] #[ORM\Index(name: 'phplist_user_user_idxuniqid', columns: ['uniqid'])] #[ORM\Index(name: 'phplist_user_user_enteredindex', columns: ['entered'])] #[ORM\Index(name: 'phplist_user_user_confidx', columns: ['confirmed'])] diff --git a/src/Domain/Subscription/Model/SubscriberAttributeDefinition.php b/src/Domain/Subscription/Model/SubscriberAttributeDefinition.php index 26b7a786..dbe397d2 100644 --- a/src/Domain/Subscription/Model/SubscriberAttributeDefinition.php +++ b/src/Domain/Subscription/Model/SubscriberAttributeDefinition.php @@ -12,7 +12,7 @@ use PhpList\Core\Domain\Subscription\Repository\SubscriberAttributeDefinitionRepository; #[ORM\Entity(repositoryClass: SubscriberAttributeDefinitionRepository::class)] -#[ORM\Table(name: 'phplist_user_attribute')] +#[ORM\Table(name: 'user_attribute')] #[ORM\Index(name: 'phplist_user_attribute_idnameindex', columns: ['id', 'name'])] #[ORM\Index(name: 'phplist_user_attribute_nameindex', columns: ['name'])] class SubscriberAttributeDefinition implements DomainModel, Identity diff --git a/src/Domain/Subscription/Model/SubscriberAttributeValue.php b/src/Domain/Subscription/Model/SubscriberAttributeValue.php index 3af333ff..6678b489 100644 --- a/src/Domain/Subscription/Model/SubscriberAttributeValue.php +++ b/src/Domain/Subscription/Model/SubscriberAttributeValue.php @@ -9,7 +9,7 @@ use PhpList\Core\Domain\Subscription\Repository\SubscriberAttributeValueRepository; #[ORM\Entity(repositoryClass: SubscriberAttributeValueRepository::class)] -#[ORM\Table(name: 'phplist_user_user_attribute')] +#[ORM\Table(name: 'user_user_attribute')] #[ORM\Index(name: 'phplist_user_user_attribute_attindex', columns: ['attributeid'])] #[ORM\Index(name: 'phplist_user_user_attribute_attuserid', columns: ['userid', 'attributeid'])] #[ORM\Index(name: 'phplist_user_user_attribute_userindex', columns: ['userid'])] diff --git a/src/Domain/Subscription/Model/SubscriberHistory.php b/src/Domain/Subscription/Model/SubscriberHistory.php index 1799c01b..08f4f974 100644 --- a/src/Domain/Subscription/Model/SubscriberHistory.php +++ b/src/Domain/Subscription/Model/SubscriberHistory.php @@ -11,7 +11,7 @@ use PhpList\Core\Domain\Subscription\Repository\SubscriberHistoryRepository; #[ORM\Entity(repositoryClass: SubscriberHistoryRepository::class)] -#[ORM\Table(name: 'phplist_user_user_history')] +#[ORM\Table(name: 'user_user_history')] #[ORM\Index(name: 'phplist_user_user_history_dateidx', columns: ['date'])] #[ORM\Index(name: 'phplist_user_user_history_userididx', columns: ['userid'])] class SubscriberHistory implements DomainModel, Identity diff --git a/src/Domain/Subscription/Model/SubscriberList.php b/src/Domain/Subscription/Model/SubscriberList.php index 621f855e..d1d2a071 100644 --- a/src/Domain/Subscription/Model/SubscriberList.php +++ b/src/Domain/Subscription/Model/SubscriberList.php @@ -25,7 +25,7 @@ * @author Tatevik Grigoryan */ #[ORM\Entity(repositoryClass: SubscriberListRepository::class)] -#[ORM\Table(name: 'phplist_list')] +#[ORM\Table(name: 'list')] #[ORM\Index(name: 'phplist_list_nameidx', columns: ['name'])] #[ORM\Index(name: 'phplist_list_listorderidx', columns: ['listorder'])] #[ORM\HasLifecycleCallbacks] diff --git a/src/Domain/Subscription/Model/Subscription.php b/src/Domain/Subscription/Model/Subscription.php index fe4b5e2a..98df4703 100644 --- a/src/Domain/Subscription/Model/Subscription.php +++ b/src/Domain/Subscription/Model/Subscription.php @@ -22,7 +22,7 @@ * @author Tatevik Grigoryan */ #[ORM\Entity(repositoryClass: SubscriptionRepository::class)] -#[ORM\Table(name: 'phplist_listuser')] +#[ORM\Table(name: 'listuser')] #[ORM\Index(name: 'phplist_listuser_userenteredidx', columns: ['userid', 'entered'])] #[ORM\Index(name: 'phplist_listuser_userlistenteredidx', columns: ['userid', 'entered', 'listid'])] #[ORM\Index(name: 'phplist_listuser_useridx', columns: ['userid'])] diff --git a/src/Domain/Subscription/Model/UserBlacklist.php b/src/Domain/Subscription/Model/UserBlacklist.php index 9b150686..f940f79b 100644 --- a/src/Domain/Subscription/Model/UserBlacklist.php +++ b/src/Domain/Subscription/Model/UserBlacklist.php @@ -10,7 +10,7 @@ use PhpList\Core\Domain\Subscription\Repository\UserBlacklistRepository; #[ORM\Entity(repositoryClass: UserBlacklistRepository::class)] -#[ORM\Table(name: 'phplist_user_blacklist')] +#[ORM\Table(name: 'user_blacklist')] #[ORM\Index(name: 'phplist_user_blacklist_emailidx', columns: ['email'])] class UserBlacklist implements DomainModel { diff --git a/src/Domain/Subscription/Model/UserBlacklistData.php b/src/Domain/Subscription/Model/UserBlacklistData.php index ff133161..52725e1b 100644 --- a/src/Domain/Subscription/Model/UserBlacklistData.php +++ b/src/Domain/Subscription/Model/UserBlacklistData.php @@ -9,7 +9,7 @@ use PhpList\Core\Domain\Subscription\Repository\UserBlacklistDataRepository; #[ORM\Entity(repositoryClass: UserBlacklistDataRepository::class)] -#[ORM\Table(name: 'phplist_user_blacklist_data')] +#[ORM\Table(name: 'user_blacklist_data')] #[ORM\Index(name: 'phplist_user_blacklist_data_emailidx', columns: ['email'])] #[ORM\Index(name: 'phplist_user_blacklist_data_emailnameidx', columns: ['email', 'name'])] class UserBlacklistData implements DomainModel diff --git a/src/Migrations/AbstractPrefixedMigration.php b/src/Migrations/AbstractPrefixedMigration.php new file mode 100644 index 00000000..f0f67b5c --- /dev/null +++ b/src/Migrations/AbstractPrefixedMigration.php @@ -0,0 +1,36 @@ +getTablePrefix(), + $sql + ), + $params, + $types + ); + } + + private function getTablePrefix(): string + { + $prefix = $_ENV['DATABASE_PREFIX'] ?? getenv('DATABASE_PREFIX'); + + return is_string($prefix) && $prefix !== '' ? $prefix : self::DEFAULT_PREFIX; + } +} diff --git a/src/Migrations/Version20251028092901MySqlInit.php b/src/Migrations/Version20251028092901MySqlInit.php index 5589fadf..7de730c0 100644 --- a/src/Migrations/Version20251028092901MySqlInit.php +++ b/src/Migrations/Version20251028092901MySqlInit.php @@ -6,12 +6,11 @@ use Doctrine\DBAL\Platforms\MySQLPlatform; use Doctrine\DBAL\Schema\Schema; -use Doctrine\Migrations\AbstractMigration; /** * Manual Migration */ -final class Version20251028092901MySqlInit extends AbstractMigration +final class Version20251028092901MySqlInit extends AbstractPrefixedMigration { public function getDescription(): string { diff --git a/src/Migrations/Version20251028092902MySqlUpdate.php b/src/Migrations/Version20251028092902MySqlUpdate.php index 2c0e872e..2881be2f 100644 --- a/src/Migrations/Version20251028092902MySqlUpdate.php +++ b/src/Migrations/Version20251028092902MySqlUpdate.php @@ -6,10 +6,9 @@ use Doctrine\DBAL\Platforms\PostgreSQLPlatform; use Doctrine\DBAL\Platforms\MySQLPlatform; -use Doctrine\Migrations\AbstractMigration; use Doctrine\DBAL\Schema\Schema; -final class Version20251028092902MySqlUpdate extends AbstractMigration +final class Version20251028092902MySqlUpdate extends AbstractPrefixedMigration { public function getDescription(): string { diff --git a/src/Migrations/Version20251031072945PostGreInit.php b/src/Migrations/Version20251031072945PostGreInit.php index 80c27956..6b2446c9 100644 --- a/src/Migrations/Version20251031072945PostGreInit.php +++ b/src/Migrations/Version20251031072945PostGreInit.php @@ -5,7 +5,6 @@ namespace PhpList\Core\Migrations; use Doctrine\DBAL\Platforms\PostgreSQLPlatform; -use Doctrine\Migrations\AbstractMigration; use Doctrine\DBAL\Schema\Schema; /** @@ -15,7 +14,7 @@ * * Ex: phplist_linktrack_forward phplist_linktrack_forward_urlindex (but there are more) */ -final class Version20251031072945PostGreInit extends AbstractMigration +final class Version20251031072945PostGreInit extends AbstractPrefixedMigration { public function getDescription(): string { diff --git a/src/Migrations/Version20260204094237.php b/src/Migrations/Version20260204094237.php index 00e7fd91..56ab5b1a 100644 --- a/src/Migrations/Version20260204094237.php +++ b/src/Migrations/Version20260204094237.php @@ -6,7 +6,6 @@ use Doctrine\DBAL\Platforms\PostgreSQLPlatform; use Doctrine\DBAL\Platforms\MySQLPlatform; -use Doctrine\Migrations\AbstractMigration; use Doctrine\DBAL\Schema\Schema; /** @@ -16,7 +15,7 @@ * * Ex: phplist_linktrack_forward phplist_linktrack_forward_urlindex (but there are more) */ -final class Version20260204094237 extends AbstractMigration +final class Version20260204094237 extends AbstractPrefixedMigration { public function getDescription(): string { diff --git a/src/Migrations/_template_migration.php.tpl b/src/Migrations/_template_migration.php.tpl index 72561549..cd2cde8f 100644 --- a/src/Migrations/_template_migration.php.tpl +++ b/src/Migrations/_template_migration.php.tpl @@ -6,7 +6,6 @@ namespace ; use Doctrine\DBAL\Platforms\PostgreSQLPlatform; use Doctrine\DBAL\Platforms\MySQLPlatform; -use Doctrine\Migrations\AbstractMigration; use Doctrine\DBAL\Schema\Schema; /** @@ -16,7 +15,7 @@ use Doctrine\DBAL\Schema\Schema; * * Ex: phplist_linktrack_forward phplist_linktrack_forward_urlindex (but there are more) */ -final class extends AbstractMigration +final class extends AbstractPrefixedMigration { public function getDescription(): string { diff --git a/tests/Unit/Domain/Configuration/Service/Provider/ConfigProviderTest.php b/tests/Unit/Domain/Configuration/Service/Provider/ConfigProviderTest.php index ab6e90c5..bd7eee08 100644 --- a/tests/Unit/Domain/Configuration/Service/Provider/ConfigProviderTest.php +++ b/tests/Unit/Domain/Configuration/Service/Provider/ConfigProviderTest.php @@ -71,7 +71,7 @@ public function testIsEnabledUsesRepositoryValueWhenPresent(): void $this->repo ->expects($this->once()) ->method('findOneBy') - ->with(['item' => $key->value]) + ->with(['key' => $key->value]) ->willReturn($configEntity); // Defaults should not be consulted if repo has value @@ -90,7 +90,7 @@ public function testIsEnabledFallsBackToDefaultsWhenRepoMissing(): void $this->repo ->expects($this->once()) ->method('findOneBy') - ->with(['item' => $key->value]) + ->with(['key' => $key->value]) ->willReturn(null); $this->defaults