Skip to content

Commit

Permalink
Support .env.local config override (#594)
Browse files Browse the repository at this point in the history
If `.env.local` exists, any values will override and take precedence
over those in `.env`.

This is meant for local development only.
  • Loading branch information
swalkinshaw authored May 29, 2021
1 parent 28374de commit b2781b8
Show file tree
Hide file tree
Showing 2 changed files with 3 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
### HEAD
* Support `.env.local` config override ([#594](https://github.com/roots/bedrock/pull/594))
* Use Bedrock disallow indexing package ([#521](https://github.com/roots/bedrock/pull/521))

### 1.15.4: 2021-05-19
Expand Down
3 changes: 2 additions & 1 deletion config/application.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@

/**
* Use Dotenv to set required environment variables and load .env file in root
* .env.local will override .env if it exists
*/
$dotenv = Dotenv\Dotenv::createUnsafeImmutable($root_dir);
$dotenv = Dotenv\Dotenv::createUnsafeImmutable($root_dir, ['.env', '.env.local'], false);
if (file_exists($root_dir . '/.env')) {
$dotenv->load();
$dotenv->required(['WP_HOME', 'WP_SITEURL']);
Expand Down

4 comments on commit b2781b8

@sandrowuermli
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get a PHP error, if the file .env.local doesn't exist.
Maybe this could be handled by something like this?

if ( file_exists( $root_dir . '/.env' ) ) {
    $names = [ '.env' ];

    if ( file_exists( $root_dir . '/.env.local' ) ) {
        $names[] = '.env.local';
    }

    $dotenv = Dotenv\Dotenv::createUnsafeImmutable( $root_dir, $names, false );
    $dotenv->load();
    $dotenv->required( [ 'WP_HOME', 'WP_SITEURL' ] );
    if ( ! env( 'DATABASE_URL' ) ) {
        $dotenv->required( [ 'DB_NAME', 'DB_USER', 'DB_PASSWORD' ] );
    }
}

@swalkinshaw
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's strange. phpdotenv just ignores files it can't read: https://github.com/vlucas/phpdotenv/blob/b740396414a95cbe868bf7f168f997fe16d970d6/src/Store/File/Reader.php#L33

Though you do need at least one working env file. Are you missing the main .env file? Without any, you'll see Fatal error: Uncaught Dotenv\Exception\InvalidPathException: Unable to read any of the environment file(s)

I just tried out a minimal test script and it worked as expected as well:

<?php

require_once dirname(__DIR__) . '/vendor/autoload.php';

use Roots\WPConfig\Config;
use function Env\env;

$root_dir = dirname(__DIR__);

$dotenv = Dotenv\Dotenv::createUnsafeImmutable($root_dir, ['.env', '.env.local'], false);
if (file_exists($root_dir . '/.env')) {
    $dotenv->load();
    $dotenv->required(['WP_HOME', 'WP_SITEURL']);
    if (!env('DATABASE_URL')) {
        $dotenv->required(['DB_NAME', 'DB_USER', 'DB_PASSWORD']);
    }
}
var_dump($_ENV);

Worked with and without .env.local and overrode the values as expected.

@sandrowuermli
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, my bad. It's not an error, it's just a warning.
PHP Warning

Everything will work as it should, but anyway, I don't like warnings which I can avoid.
Thank you for getting into it, I really appreciate your support!

@fab120
Copy link
Contributor

@fab120 fab120 commented on b2781b8 Jul 30, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@swalkinshaw I found what cause the error.

Just a few lines in the file you linked, phpdotenv uses file_get_contents with error suppressor.
https://github.com/vlucas/phpdotenv/blob/b740396414a95cbe868bf7f168f997fe16d970d6/src/Store/File/Reader.php#L73

If a file is not found, file_get_contents generates an E_WARNING.

After that, WordPress checks if there was any error in admin-header.php with error_get_last function that returns the E_WARNING:
https://github.com/WordPress/WordPress/blob/81f62198c388a0e0619d8dcb2f1e34b2f07e2bfb/wp-admin/admin-header.php#L199

A .php-error class is added to admin body that adds a margin under the admin bar and the user doesn't see any error because the output was suppressed.

IMHO i would adopt a solution like that

/**
 * Use Dotenv to set required environment variables and load .env file in root
 * .env.local will override .env if it exists
 */
$env_files = file_exists($root_dir . '/.env.local')
    ? ['.env', '.env.local']
    : ['.env'];

$dotenv = Dotenv\Dotenv::createUnsafeImmutable($root_dir, $env_files, false);
$dotenv->load();
$dotenv->required(['WP_HOME', 'WP_SITEURL']);
if (!env('DATABASE_URL')) {
    $dotenv->required(['DB_NAME', 'DB_USER', 'DB_PASSWORD']);
}

I also removed if (file_exists($root_dir . '/.env')) { check because in my opinion if a configuration file is not provided a fatal error must be raised.

Please sign in to comment.