Creating Drupal settings from .env files

In the first article of this series, I shared my basic recipe for handling Drupal 8 deployments. In this post, I'll dive into the creation of settings from .env. files. It is the kind of setup that you only have to do once, but I guess it is worthy of automation when dealing with a lot of sites or server environments.

We start by installing Symfony's dotenv:

 composer global require symfony/dotenv:"^3"

After, we add a function to deploy.php to parse the .env file especified in the hosts.yml that we created in the previous post and define a variable to hold the location of the settings template file:

function loadenv() {
    $env_file = get('env_file');
    $environment = file_get_contents($env_file);
    $dotenv = new \Symfony\Component\Dotenv\Dotenv();
    $data = $dotenv->parse($environment);
    return $data;
};

set('settings_template', './templates/settings.local.php.template');

For Drupal 8, our settings.local.php.template will look like this:

<?php

$databases['default']['default'] = array (
    'database' => '{{DATABASE_NAME}}',
    'driver' => 'mysql',
    'host' => '{{DATABASE_HOST}}',
    'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql',
    'password' => '{{DATABASE_PASSWORD}}',
    'port' => 3306,
    'prefix' => '',
    'username' => '{{DATABASE_USER}}',
);

And our .env.staging file will be:

DATABASE_HOST=localhostorwhateverhostnameyouhave
DATABASE_NAME=dbname
DATABASE_USER=dbusername
DATABASE_PASSWORD=theverysecretpassword

Finally, we'll use the task in the Drupal 7 Deployer recipe. This task creates the settings.local.php file, uploads it to the server and you are good to go!

task('drupal:settings', function () {
    if (askConfirmation('Are you sure to generate and upload settings.local.php file?')) {
        //Get template
        $template = get('settings_template');

        //Import secrets from .env file
        $secrets = loadenv();

        //Prepare replacement variables
        $iterator = new \RecursiveIteratorIterator(
            new \RecursiveArrayIterator($secrets)
        );
        $replacements = [];
        foreach ($iterator as $key => $value) {
            $keys = [];
            for ($i = $iterator->getDepth(); $i > 0; $i --) {
                $keys[] = $iterator->getSubIterator($i - 1)->key();
            }
            $keys[] = $key;
            $replacements['{{' . implode('.', $keys) . '}}'] = $value;
        }

        //Create settings from template
        $settings = file_get_contents($template);
        $settings = strtr($settings, $replacements);
        writeln('settings.local.php created succesfuly');
        $tmpFilename = 'local.settings.tmp';

        // Upload file to server
        file_put_contents($tmpFilename, $settings);
        upload($tmpFilename, '{{release_path}}/web/sites/default/settings.local.php', ['options'=> ['--inplace']]);

        // Delete local temporary file
        unlink($tmpFilename);
    }
});