Conversation
* Refactor: env * feat: add support for .env configuration files and dotenv integration * feat: add parameters configuration file creation to ScriptHandler * remove legacy public app files * fix: correct environment variable naming for parallel usage with phplist3 --------- Co-authored-by: Tatevik <tatevikg1@gmail.com>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThe PR replaces deployment defaults with dotenv configuration, adds configurable Doctrine table prefixes, and updates migrations, messaging configuration, domain behavior, documentation, and administrator defaults. ChangesEnvironment configuration migration
Database prefixing
Messaging and domain updates
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Composer
participant ScriptHandler
participant Bootstrap
participant Dotenv
participant Doctrine
Composer->>ScriptHandler: run update-configuration
ScriptHandler->>Dotenv: create /.env from /.env.dist
Bootstrap->>Dotenv: load and validate environment variables
Bootstrap->>Doctrine: configure application metadata
Doctrine->>Doctrine: apply DATABASE_PREFIX to eligible tables
Possibly related PRs
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/Composer/ScriptHandler.php (1)
283-285: 🗄️ Data Integrity & Integration | 🔵 Trivial | 🏗️ Heavy liftHandle existing
.envfiles during upgrades.Preserving an existing file avoids overwriting deployment secrets, but it also prevents newly required keys from
.env.distfrom being added. Sinceconfig/parameters.ymlnow references those keys without inline fallbacks, older or partial.envfiles can leave required parameters unresolved. Add a merge/validation step or document an explicit upgrade procedure.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/Composer/ScriptHandler.php` around lines 283 - 285, Update the existing `.env` handling in the upgrade flow so an early return from the file-exists check no longer skips required-key validation and incorporation of newly introduced values from `.env.dist`. Preserve existing deployment secrets while merging only missing required keys, or invoke the project’s established validation/upgrade mechanism to ensure parameters referenced by `config/parameters.yml` are resolved.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.env.dist:
- Around line 55-57: Update the environment-loading flow around
loadEnvironmentVariables so .env.dist remains template-only and PHPLIST_SECRET
never accepts the literal “%s” placeholder. Require a non-placeholder generated
or explicitly supplied secret, and fail fast when it is missing before security
tokens are used.
In `@CHANGELOG.md`:
- Line 13: Update the changelog entry to reference the current parameters
template path, config/parameters.yml, or explicitly state that
config/parameters.yml.dist was renamed to config/parameters.yml; keep the
description of defaults moving to .env.dist unchanged.
---
Nitpick comments:
In `@src/Composer/ScriptHandler.php`:
- Around line 283-285: Update the existing `.env` handling in the upgrade flow
so an early return from the file-exists check no longer skips required-key
validation and incorporation of newly introduced values from `.env.dist`.
Preserve existing deployment secrets while merging only missing required keys,
or invoke the project’s established validation/upgrade mechanism to ensure
parameters referenced by `config/parameters.yml` are resolved.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 5c64df25-bce9-461d-83d0-2f202a1f882d
📒 Files selected for processing (12)
.env.dist.gitignoreCHANGELOG.mdREADME.mdcomposer.jsonconfig/parameters.ymlconfig/parameters.yml.distpublic/app.phppublic/app_dev.phppublic/app_test.phpsrc/Composer/ScriptHandler.phpsrc/Core/Bootstrap.php
💤 Files with no reviewable changes (4)
- public/app_test.php
- config/parameters.yml.dist
- public/app_dev.php
- public/app.php
| - `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) |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Use the current parameters template path.
This entry names config/parameters.yml.dist, while the migrated template and ScriptHandler now use config/parameters.yml. Use the current path or explicitly describe the rename.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@CHANGELOG.md` at line 13, Update the changelog entry to reference the current
parameters template path, config/parameters.yml, or explicitly state that
config/parameters.yml.dist was renamed to config/parameters.yml; keep the
description of defaults moving to .env.dist unchanged.
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.env.dist:
- Line 19: Replace the usable PHPLIST_ADMIN_PASSWORD value in the environment
template with a non-operational placeholder, and update the bootstrap logic
around the .env fallback (the code loading .env.dist near Bootstrap
initialization) to fail fast when that placeholder or an otherwise missing
deployment password is used, ensuring deployment must provide a strong
administrator password.
In `@src/Domain/Identity/Command/ImportDefaultsCommand.php`:
- Line 26: Update the default-user existence check in ImportDefaultsCommand to
recognize both the current DEFAULT_LOGIN value “test1” and the legacy “admin”
login before prompting or creating a user. Preserve the existing behavior for
fresh installations while preventing creation of a duplicate superuser when
either default account already exists.
- Line 26: Update the fallback prompt in ImportDefaultsCommand to interpolate
the `$login` value instead of hardcoding “admin”, so it reflects the
DEFAULT_LOGIN constant and any supplied login.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 6a67eb95-daed-4ef7-af7e-7f0513b09068
📒 Files selected for processing (3)
.env.distconfig/parameters.ymlsrc/Domain/Identity/Command/ImportDefaultsCommand.php
🚧 Files skipped from review as they are similar to previous changes (1)
- config/parameters.yml
… TablePrefixListener for dynamic table prefixing
…namic table prefixing in migrations
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/Core/Doctrine/TablePrefixListener.php`:
- Around line 30-32: Update TablePrefixListener so setPrimaryTable preserves and
prefixes metadata indexes and uniqueConstraints using the configured table
prefix, matching the renamed primary table and AbstractPrefixedMigration SQL
identifiers. Ensure index and unique-constraint names receive the prefix
consistently while retaining their existing definitions.
In `@src/Domain/Identity/Model/Administrator.php`:
- Line 28: Align the ORM metadata names with the prefixed migration names in
Administrator.php at line 28 and TemplateImage.php at line 13. Update the
relevant unique-constraint/index names using the DATABASE_PREFIX-aware naming
convention, or skip creating those explicitly named objects when a custom prefix
is active, so Doctrine schema tooling matches AbstractPrefixedMigration and
TablePrefixListener behavior.
In `@src/Domain/Messaging/Model/ListMessage.php`:
- Around line 17-19: Align explicit index and unique-constraint names with the
runtime table prefix, either by applying the TablePrefixListener naming pattern
or by making them database-default/unprefixed. Apply this consistently at
src/Domain/Messaging/Model/ListMessage.php:17-19, Message.php:25-26,
MessageAttachment.php:12-14, Template.php:15-16, UserMessage.php:15-20,
UserMessageBounce.php:14-18, UserMessageForward.php:14-17, and
src/Domain/Subscription/Model/SubscriberList.php:28-30; update the attributes in
each location so Doctrine’s metadata names follow the configured prefix.
In `@src/Migrations/AbstractPrefixedMigration.php`:
- Around line 17-27: Restrict prefix rewriting in
AbstractPrefixedMigration::addSql() to SQL schema identifiers rather than
applying str_replace across the entire SQL text; use explicit identifier
substitution or token-aware SQL rewriting while preserving parameters and types.
Apply this root-cause fix for the SQL consumed by
Version20251028092901MySqlInit::up(); no direct change is required in
src/Migrations/Version20251028092901MySqlInit.php:13.
In `@src/Migrations/Version20251028092902MySqlUpdate.php`:
- Line 11: Apply the custom DATABASE_PREFIX policy to both migration index names
and ORM index metadata so they remain consistent when the prefix differs from
phplist_. Update Version20251028092902MySqlUpdate.php and the index definitions
in UserMessageView.php, UserStats.php, Subscriber.php,
SubscriberAttributeDefinition.php, SubscriberAttributeValue.php,
SubscriberHistory.php, and Subscription.php at the specified ranges; use the
existing prefix-aware mechanism rather than hardcoded phplist_ names, and ensure
the migration update/down paths match the entity metadata.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 83ffa9fd-132b-4f22-9b41-db0b3536f4ff
📒 Files selected for processing (50)
config/services.ymlsrc/Core/Doctrine/TablePrefixListener.phpsrc/Domain/Analytics/Model/LinkTrack.phpsrc/Domain/Analytics/Model/LinkTrackForward.phpsrc/Domain/Analytics/Model/LinkTrackMl.phpsrc/Domain/Analytics/Model/LinkTrackUmlClick.phpsrc/Domain/Analytics/Model/LinkTrackUserClick.phpsrc/Domain/Analytics/Model/UserMessageView.phpsrc/Domain/Analytics/Model/UserStats.phpsrc/Domain/Configuration/Model/Config.phpsrc/Domain/Configuration/Model/EventLog.phpsrc/Domain/Configuration/Model/I18n.phpsrc/Domain/Configuration/Model/UrlCache.phpsrc/Domain/Identity/Model/AdminAttributeDefinition.phpsrc/Domain/Identity/Model/AdminAttributeValue.phpsrc/Domain/Identity/Model/AdminLogin.phpsrc/Domain/Identity/Model/AdminPasswordRequest.phpsrc/Domain/Identity/Model/Administrator.phpsrc/Domain/Identity/Model/AdministratorToken.phpsrc/Domain/Messaging/Model/Attachment.phpsrc/Domain/Messaging/Model/Bounce.phpsrc/Domain/Messaging/Model/BounceRegex.phpsrc/Domain/Messaging/Model/BounceRegexBounce.phpsrc/Domain/Messaging/Model/ListMessage.phpsrc/Domain/Messaging/Model/Message.phpsrc/Domain/Messaging/Model/MessageAttachment.phpsrc/Domain/Messaging/Model/MessageData.phpsrc/Domain/Messaging/Model/SendProcess.phpsrc/Domain/Messaging/Model/Template.phpsrc/Domain/Messaging/Model/TemplateImage.phpsrc/Domain/Messaging/Model/UserMessage.phpsrc/Domain/Messaging/Model/UserMessageBounce.phpsrc/Domain/Messaging/Model/UserMessageForward.phpsrc/Domain/Subscription/Model/SubscribePage.phpsrc/Domain/Subscription/Model/SubscribePageData.phpsrc/Domain/Subscription/Model/Subscriber.phpsrc/Domain/Subscription/Model/SubscriberAttributeDefinition.phpsrc/Domain/Subscription/Model/SubscriberAttributeValue.phpsrc/Domain/Subscription/Model/SubscriberHistory.phpsrc/Domain/Subscription/Model/SubscriberList.phpsrc/Domain/Subscription/Model/Subscription.phpsrc/Domain/Subscription/Model/UserBlacklist.phpsrc/Domain/Subscription/Model/UserBlacklistData.phpsrc/Migrations/AbstractPrefixedMigration.phpsrc/Migrations/Version20251028092901MySqlInit.phpsrc/Migrations/Version20251028092902MySqlUpdate.phpsrc/Migrations/Version20251031072945PostGreInit.phpsrc/Migrations/Version20260204094237.phpsrc/Migrations/_template_migration.php.tpltests/Unit/Domain/Configuration/Service/Provider/ConfigProviderTest.php
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
src/Domain/Identity/Command/ImportDefaultsCommand.php (3)
43-49: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick winReject whitespace-only configured passwords.
$this->defaultAdminPassword !== ''accepts values such as' 'and skips the prompt. The interactive path rejects the same value withtrim($password) === ''. Check the trimmed value before selecting the configured password, while preserving the original non-empty password.Proposed fix
- $password = $this->defaultAdminPassword !== '' ? $this->defaultAdminPassword : null; + $password = trim($this->defaultAdminPassword) !== '' + ? $this->defaultAdminPassword + : null;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/Domain/Identity/Command/ImportDefaultsCommand.php` around lines 43 - 49, Update the password selection in ImportDefaultsCommand so whitespace-only defaultAdminPassword values are treated as unset and trigger the existing prompt path. Check the trimmed configured value for emptiness, while preserving the original untrimmed password when it contains non-whitespace characters.
33-34: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick winMake
PHPLIST_DEFAULT_ADMIN_PASSWORDoptional or defaulted.
config/parameters.ymlrequiresPHPLIST_DEFAULT_ADMIN_PASSWORD, and.env.distdoes not define it. Symfony loads undefined%env(...)%values as failing beforeImportDefaultsCommandcan use the existing empty-string fallback, so an omitted variable can stop command startup. Add the variable to.env.distwith the intended fallback, or make the binding/property explicitly nullable/defaulted and wire that value into the prompt fallback.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/Domain/Identity/Command/ImportDefaultsCommand.php` around lines 33 - 34, Make the default admin password configuration optional by defining PHPLIST_DEFAULT_ADMIN_PASSWORD with its intended fallback in .env.dist, or by making the Autowire binding used by ImportDefaultsCommand explicitly nullable/defaulted. Ensure ImportDefaultsCommand continues using an empty value as the prompt fallback when the environment variable is omitted.
26-26: 🔒 Security & Privacy | 🟠 MajorPreserve the previous default login during upgrades.
When an existing installation still has the previous default user
test1, theadminlookup does not find it. The command can then create a second superuser with the default credential. Check bothadminandtest1before creating the account, or restrict this command to fresh installations.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/Domain/Identity/Command/ImportDefaultsCommand.php` at line 26, Update ImportDefaultsCommand to check for both the current DEFAULT_LOGIN value admin and the legacy login test1 before creating the default superuser, preventing duplicate accounts during upgrades while preserving creation for installations with neither login.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/Core/Bootstrap.php`:
- Line 181: Update configureApplicationKernel around Dotenv::loadEnv() to read
the resolved APP_ENV after dotenv loading, validate that it is a supported
environment, and assign it to $this->environment before creating the kernel.
Ensure the kernel receives this resolved value so environment-specific files and
runtime configuration remain aligned.
---
Outside diff comments:
In `@src/Domain/Identity/Command/ImportDefaultsCommand.php`:
- Around line 43-49: Update the password selection in ImportDefaultsCommand so
whitespace-only defaultAdminPassword values are treated as unset and trigger the
existing prompt path. Check the trimmed configured value for emptiness, while
preserving the original untrimmed password when it contains non-whitespace
characters.
- Around line 33-34: Make the default admin password configuration optional by
defining PHPLIST_DEFAULT_ADMIN_PASSWORD with its intended fallback in .env.dist,
or by making the Autowire binding used by ImportDefaultsCommand explicitly
nullable/defaulted. Ensure ImportDefaultsCommand continues using an empty value
as the prompt fallback when the environment variable is omitted.
- Line 26: Update ImportDefaultsCommand to check for both the current
DEFAULT_LOGIN value admin and the legacy login test1 before creating the default
superuser, preventing duplicate accounts during upgrades while preserving
creation for installations with neither login.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: eb0a38c7-772a-4869-b149-f9819c1bed63
📒 Files selected for processing (3)
src/Core/Bootstrap.phpsrc/Core/Doctrine/TablePrefixListener.phpsrc/Domain/Identity/Command/ImportDefaultsCommand.php
🚧 Files skipped from review as they are similar to previous changes (1)
- src/Core/Doctrine/TablePrefixListener.php
| ); | ||
| } | ||
|
|
||
| (new Dotenv())->loadEnv($dotenvPath, 'APP_ENV', $this->environment); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Locate relevant files"
fd -a 'Bootstrap.php|ApplicationKernel.php|Environment.php' . | sed 's#^\./##' | head -50
echo
echo "Search Dotenv/APP_ENV usages"
rg -n "loadEnv|APP_ENV|configureApplicationKernel|\$environment|ApplicationKernel|class Environment" src -S || true
echo
echo "Inspect Bootstrap outline/size"
for f in $(fd 'Bootstrap.php' .); do
echo "--- $f"
wc -l "$f"
ast-grep outline "$f" --view expanded || true
doneRepository: phpList/core
Length of output: 3189
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Read target Bootstrap around loadEnv/kernel creation"
for f in $(fd 'Bootstrap.php' .); do
echo "--- $f"
nl -ba "$f" | sed -n '140,210p'
done
echo
echo "Read ApplicationKernel and Environment relevant files"
for f in $(fd 'ApplicationKernel.php|Environment.php' .); do
echo "--- $f ($(wc -l < "$f") lines)"
nl -ba "$f" | sed -n '1,260p'
done
echo
echo "Check Symfony Dotenv dependency declaration"
for f in composer.json composer.lock; do
[ -f "$f" ] && { echo "--- $f"; rg -n '"symfony/dotenv"|symfony/dotenv|version|name' "$f" -A 4 -B 4 || true; }
doneRepository: phpList/core
Length of output: 272
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Bootstrap lines 160-240"
awk 'NR>=160 && NR<=245 { printf "%6d\t%s\n", NR, $0 }' src/Core/Bootstrap.php
echo
echo "Environment class"
awk '{ printf "%6d\t%s\n", NR, $0 }' src/Core/Environment.php
echo
echo "ApplicationKernel class"
awk '{ printf "%6d\t%s\n", NR, $0 }' src/Core/ApplicationKernel.php
echo
echo "Dotenv references"
for f in composer.json composer.lock; do
if [ -f "$f" ]; then
echo "--- $f"
rg -n '"symfony/dotenv"|symfony/dotenv|version' "$f" || true
fi
doneRepository: phpList/core
Length of output: 12253
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Bootstrap public API/constructor/init around environments"
awk 'NR>=30 && NR<=165 { printf "%6d\t%s\n", NR, $0 }' src/Core/Bootstrap.php
echo
echo "Bootstrap exact configureApplicationKernel"
awk 'NR>=240 && NR<=260 { printf "%6d\t%s\n", NR, $0 }' src/Core/Bootstrap.php
echo
echo "Composer lock dotenv exact"
python3 - <<'PY'
import json, pathlib
p=pathlib.Path('composer.lock')
if not p.exists():
raise SystemExit
data=json.loads(p.read_text())
for pkg in data.get('packages', []):
if pkg.get('name') == 'symfony/dotenv':
print({k:c for k,c in pkg.items() if k in ('name','version','type','source','dist')})
PYRepository: phpList/core
Length of output: 5964
🌐 Web query:
Symfony Dotenv loadEnv function sets default value if already defined
💡 Result:
In Symfony's Dotenv component, the default behavior of the loadEnv method is to not overwrite existing environment variables [1][2][3]. When loadEnv parses.env files, it only populates $_SERVER or $_ENV for variables that are not already defined in the system's environment [4][5][2]. If you need to force Symfony to overwrite existing environment variables with values from your.env files, you can use the overrideExistingVars parameter [6][1]. This parameter is available in the loadEnv, bootEnv, and populate methods [1]. To enable this, set the parameter to true in your code: $dotenv = new Dotenv; $dotenv->loadEnv(DIR.'/.env', overrideExistingVars: true); This approach ensures that variables defined in your.env files take precedence over system-defined environment variables, while still respecting the hierarchy of the.env files themselves (e.g.,.env.local overriding.env) [1][7].
Citations:
- 1: https://symfony.com/doc/current/configuration.html
- 2: https://symfony.com/doc/3.x/components/dotenv.html
- 3: https://symfony.com/blog/improvements-to-the-handling-of-env-files-for-all-symfony-versions
- 4: https://github.com/symfony/dotenv
- 5: https://github.com/symfony/dotenv/tree/8.0
- 6: https://github.com/symfony/dotenv/blob/8.1/CHANGELOG.md
- 7: [Dotenv] add loadEnv(), a smoother alternative to loadForEnv() symfony/symfony#29129
🌐 Web query:
symfony/dotenv 6.4 loadEnv signature default env argument overrides existing vars false
💡 Result:
Symfony\Component\Dotenv\Dotenv::loadEnv signature (Symfony/dotenv v6.4) is: public function loadEnv(string $path,?string $envKey = null, string $defaultEnv = 'dev', array $testEnvs = ['test'], bool $overrideExistingVars = false): void [1] Default env argument behavior: - The $defaultEnv parameter defaults to 'dev' and is used when the app-env key ($envKey or the component’s configured envKey) is not already set in $_SERVER or $_ENV. In that case, Dotenv populates that env key to $defaultEnv before loading the env-specific files. [2] Does overrideExistingVars=false override existing variables? - The parameter $overrideExistingVars defaults to false and is described as: “Whether existing environment variables set by system should be overridden”. [1] - Symfony docs also show that when you set overrideExistingVars: true you override environment variables defined by the system, implying the default (false) does not override system env vars. [3] - However, real-world behavior can be subtle: there is an open GitHub issue reporting that variables can appear overridden “even when override is disabled” when loading multiple dotenv files in a particular order (e.g.,.env.local vs.env). This indicates that “false” applies to overriding existing values, but file-loading priority/sequence can still lead to surprising results depending on what was already present and the loading order. [4] So in short: with overrideExistingVars=false (the default), Dotenv should not override existing env vars set by the system, and $defaultEnv defaults to 'dev' when APP_ENV (or your configured env key) isn’t set; but multiple-dotenv loading order can still produce unexpected effective values. [1][3][4]
Citations:
- 1: https://github.com/symfony/symfony/blob/8.0/src/Symfony/Component/Dotenv/Dotenv.php
- 2: https://github.com/symfony/dotenv/blob/783f12027c6b40ab0e93d6136d9f642d1d67cd6b/Dotenv.php
- 3: https://symfony.com/doc/current/configuration.html
- 4: env variable is being overriden even when override is disabled symfony/symfony#52073
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Check whether overrideExistingVar path exists in lockfile/vendor-like refs"
python3 - <<'PY'
from pathlib import Path
p = Path('composer.lock')
if p.exists():
import json
data=json.loads(p.read_text())
for target in ('packages','packages-dev'):
for pkg in data.get(target, []):
if pkg.get('name') == 'symfony/dotenv':
print(json.dumps({k: v for k, v in pkg.items() if k in ('name','version','lock-version','source','dist','require','autoload')}, indent=2))
PY
git ls-files | rg 'symfony/dotenv|dotenv' || true
echo
echo "Search loadEnv calls with overrideExistingVars"
rg -n "new Dotenv|loadEnv\\(" src -S || trueRepository: phpList/core
Length of output: 377
🌐 Web query:
Symfony Dotenv 6.4 src loadEnv $defaultEnv $overrideExistingVars code
💡 Result:
Symfony Dotenv’s Dotenv::loadEnv($path, $envKey = null, $defaultEnv = 'dev', $testEnvs = ['test'], bool $overrideExistingVars = false) signature includes the $overrideExistingVars parameter as the last argument (defaulting to false). [1] The effect of $overrideExistingVars is that when the component populates variables, it will not skip already-set variables only if overrideExistingVars is true; otherwise, already-present $_ENV values are left untouched. [2] Symfony’s documented behavior for using overrideExistingVars is: - Passing overrideExistingVars: true to loadEnv will override environment variables defined by the system, but it will not override environment variables defined inside the.env files. [3] loadEnv also decides which.env files to load based on the app env key ($envKey or the component’s configured envKey) and whether variables are set/resolve to 'local'. It loads in this general order: 1) $path (or $path.dist if $path doesn’t exist) [4] 2) If the app env key is not defined yet, it populates it with $defaultEnv (default 'dev') and honors $overrideExistingVars when populating that env var. [4] 3) If the env is not in the $testEnvs list and $path.local exists, it loads $path.local. [4] 4) If the resolved env is exactly 'local', it returns early (so it won’t load the env-specific files). [4] 5) Otherwise it loads $path.$env and then $path.$env.local when those files exist. [4] Example usage (named argument): use Symfony\Component\Dotenv\Dotenv; $dotenv = new Dotenv; $dotenv->loadEnv(DIR.'/.env', overrideExistingVars: true); This is the documented call pattern for overriding system env vars. [3]
Citations:
- 1: https://github.com/symfony/dotenv/blob/6.2/Dotenv.php
- 2: https://github.com/symfony/dotenv/blob/7.0/Dotenv.php
- 3: https://symfony.com/doc/current/configuration.html
- 4: https://github.com/symfony/symfony/blob/7.2/src/Symfony/Component/Dotenv/Dotenv.php
🌐 Web query:
Symfony 6.4 Dotenv loadEnv does not override already set variable signature code
💡 Result:
In Symfony 6.4, the Dotenv component provides the loadEnv() method with an optional boolean parameter, $overrideExistingVars, which controls whether environment variables already set by the system should be overridden [1][2][3]. The method signature is: public function loadEnv(string $path,?string $envKey = null, string $defaultEnv = 'dev', array $testEnvs = ['test'], bool $overrideExistingVars = false): void By default, $overrideExistingVars is set to false [3][4]. When this parameter is false, loadEnv() will not override "real" environment variables (those already present in the system environment, such as those set by your web server or shell) [5][2]. However, it is important to note a specific nuance in how Symfony Dotenv handles variables: 1. Real Environment Variables vs. Dotenv Variables: "Real" environment variables (system-level) take precedence and are protected from being overwritten by .env files unless $overrideExistingVars is explicitly set to true [6][5][2]. 2. Precedence Within Dotenv Files: Variables defined within the series of .env files (e.g., .env, .env.local, .env.prod) follow a specific loading order where later-loaded files override values set in previously-loaded files [6][7]. This behavior applies to the Dotenv-managed variables themselves; the component is designed to ensure that more specific configuration files (like .env.local) take precedence over base configuration files [5]. If you need to force loadEnv() to override system-level environment variables, you must explicitly pass true to the overrideExistingVars argument: $dotenv = new Dotenv; $dotenv->loadEnv(DIR.'/.env', overrideExistingVars: true); As stated in the official documentation, this configuration allows you to override variables defined by the system, but it will not change the fundamental behavior where .env files maintain their own internal overriding logic [2].
Citations:
- 1: https://github.com/symfony/dotenv/blob/v6.4.8/CHANGELOG.md
- 2: https://symfony.com/doc/current/configuration.html
- 3: https://github.com/symfony/symfony/blob/8.0/src/Symfony/Component/Dotenv/Dotenv.php
- 4: https://github.com/symfony/symfony/blob/7.4/src/Symfony/Component/Dotenv/Dotenv.php
- 5: https://symfony.com/blog/improvements-to-the-handling-of-env-files-for-all-symfony-versions
- 6: [DotEnv] loading priority and overriding symfony/symfony#31579
- 7: Problem of overload and load in Dotenv have no different result symfony/symfony#62660
🌐 Web query:
site:github.com/symfony/symfony v6.4 Dotenv.php loadEnv overrideExistingVars true defaultEnv
💡 Result:
In the context of the Symfony Dotenv component (v6.4 and others), the overrideExistingVars parameter in the loadEnv() method controls whether the component overrides environment variables that were already set by the system (e.g., in the web server or OS) before the Dotenv files were loaded [1][2][3]. It is important to understand that this flag does not control the behavior between multiple .env files [4]. Within the Symfony Dotenv component, variables defined in loaded .env files will always override variables defined in previously loaded .env files, regardless of the value set for overrideExistingVars [5][4]. The overrideExistingVars flag specifically dictates whether these values can overwrite "real" environment variables that were already present in the environment before loadEnv() was called [4]. Key points regarding loadEnv and overrideExistingVars: - Purpose: The flag determines if system-level environment variables (e.g., those set by putenv or the server environment) can be replaced by values found in .env files [4]. - Scope: It does not prevent one .env file from overriding another. The loading sequence (e.g., .env -> .env.local -> .env.app_env) defines the priority for file-based variables, where later files take precedence over earlier ones [1][2]. - Default: By default, overrideExistingVars is set to false, meaning system-level environment variables will take precedence over those defined in your .env files [1][3]. - Technical behavior: When set to false, if an environment variable already exists in $_ENV or $_SERVER, the Dotenv loader will skip overwriting it [6][5]. If you require the values in your .env files to override system-level variables, you must explicitly set overrideExistingVars to true [4][7].
Citations:
- 1: https://github.com/symfony/symfony/blob/8.1/src/Symfony/Component/Dotenv/Dotenv.php
- 2: https://github.com/symfony/symfony/blob/8.0/src/Symfony/Component/Dotenv/Dotenv.php
- 3: https://github.com/symfony/symfony/blob/7.4/src/Symfony/Component/Dotenv/Dotenv.php
- 4: [Dotenv] Update README with variable override note symfony/symfony#52090
- 5: Problem of overload and load in Dotenv have no different result symfony/symfony#62660
- 6: [Dotenv] Env variable is override with $overrideExistingVars set on false symfony/symfony#57910
- 7: [Runtime] Add dotenv_overload option to SymfonyRuntime to tell Dotenv to override existing vars symfony/symfony#41681
Keep the kernel environment aligned with APP_ENV.
Dotenv::loadEnv() uses APP_ENV to load environment-specific files, but configureApplicationKernel() still passes the current $this->environment. If .env sets a different APP_ENV, .env.* is loaded for that environment while the kernel runs as the old environment, which produces a mismatched config/cache/runtime state. Read and validate the resolved APP_ENV after loading dotenv, then assign it to $this->environment before kernel creation.
Proposed fix
(new Dotenv())->loadEnv($dotenvPath, 'APP_ENV', $this->environment);
+$environment = $_SERVER['APP_ENV'] ?? $_ENV['APP_ENV'] ?? $this->environment;
+Environment::validateEnvironment($environment);
+$this->environment = $environment;
+
$secret = $_SERVER['PHPLIST_SECRET'] ?? $_ENV['PHPLIST_SECRET'] ?? '';🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/Core/Bootstrap.php` at line 181, Update configureApplicationKernel around
Dotenv::loadEnv() to read the resolved APP_ENV after dotenv loading, validate
that it is a supported environment, and assign it to $this->environment before
creating the kernel. Ensure the kernel receives this resolved value so
environment-specific files and runtime configuration remain aligned.
22dec39 to
7ac0d03
Compare
…tory for filtering and sorting
…ImportDefaultsCommand
…sService and SubscriberRepository
7194e48 to
b675382
Compare
…n\Exception and update related usages
…ntity\Service namespace
Summary by CodeRabbit
New Features
.env-based configuration for database, mail, security, messaging, uploads, and other application settings..envfile with a secure secret.Documentation
Thanks for contributing to phpList!