0

I'm using Laravel 5.1.44, and even though I have both a .env.testing file setup with different values, as well as App::environment() returning 'testing', Laravel still seems to only be using values from the main .env file.

Is there something else I should be double-checking to make sure I didn't screw up or forget to set something?

miken32
  • 42,008
  • 16
  • 111
  • 154
  • you probably need to register it in the phpunit.xml – Sari Yono Sep 21 '16 at 20:45
  • It seems to already have it set: ```php ``` – SteveFromAccounting Sep 21 '16 at 22:08
  • I'm pretty sure you can only have the one .env file. U can define multiple configurations for each environment by using the config files in config directory, and then u can set the env through the .env or through the PHPUnit file – tam5 Sep 22 '16 at 00:48
  • have a look at https://laracasts.com/discuss/channels/testing/setting-testing-environment-variables – Sari Yono Sep 22 '16 at 01:38
  • Yeah, I saw that as well, and in that example they use a `.env.testing` file to define values for their `testing` environment. My issue is that when my environment is `testing`, it's not reading the values from `.env.testing`, only `.env`. Based on the documentation from the 'dotenv' library that Laravel is using, it should be as simple as creating another dot file for that environment, with the filename format of `.env.{{{environmentName}}}` – SteveFromAccounting Sep 22 '16 at 14:10

1 Answers1

2

The ability to use environment specific .env files (e.g. .env.testing) was not available until Laravel 5.2.13. Even then, it only works if you are not using config caching.

The easiest option is to just add all your testing specific environment variables to your phpunit.xml file. As you've mentioned, you've already got a few in there, it should be no issue to add any additional ones you need.

If you really want the environment specific .env file functionality in Laravel 5.1, you can try the following. Note, this is untested, and just an assumption of what should work based off of looking at the source code.

The .env file is loaded in a bootstrap class called DetectEnvironment. The idea is you create your own bootstrap class that modifies the filename of the .env file that DetectEnvironment will load, and then you update your Kernel files so that your new bootstrap class is called, and called before the DetectEnvironment bootstrapper.

So, first, create a new bootstrapper class (e.g. app\Bootstrap\CustomEnvironment.php):

<?php
namespace App\Bootstrap;

use Illuminate\Contracts\Foundation\Application;

class CustomEnvironment
{
    /**
     * Bootstrap the given application.
     *
     * @param  \Illuminate\Contracts\Foundation\Application  $app
     * @return void
     */
    public function bootstrap(Application $app)
    {
        // APP_ENV must already be set.
        // We must know which environment file to look for.
        if (! env('APP_ENV')) {
            return;
        }

        // Build the file name to look for (e.g. .env.testing)
        $file = $app->environmentFile().'.'.env('APP_ENV');

        // If the file exists, set the App to load from that file.
        // The actual loading will take place in DetectEnvironment
        if (file_exists($app->environmentPath().'/'.$file)) {
            $app->loadEnvironmentFrom($file);
        }
    }
}

Now that you have a bootstrap class to update the .env file to be loaded, you need to add it to your Kernel|s to make sure it is called before the DetectEnvironment bootstrap class.

Add the following property to your app/Console/Kernel.php file:

/**
 * The bootstrap classes for the application.
 *
 * @var array
 */
protected $bootstrappers = [
    'App\Bootstrap\CustomEnvironment',
    'Illuminate\Foundation\Bootstrap\DetectEnvironment',
    'Illuminate\Foundation\Bootstrap\LoadConfiguration',
    'Illuminate\Foundation\Bootstrap\ConfigureLogging',
    'Illuminate\Foundation\Bootstrap\HandleExceptions',
    'Illuminate\Foundation\Bootstrap\RegisterFacades',
    'Illuminate\Foundation\Bootstrap\SetRequestForConsole',
    'Illuminate\Foundation\Bootstrap\RegisterProviders',
    'Illuminate\Foundation\Bootstrap\BootProviders',
];

Add the following property to your app/Http/Kernel.php file:

/**
 * The bootstrap classes for the application.
 *
 * @var array
 */
protected $bootstrappers = [
    'App\Bootstrap\CustomEnvironment',
    'Illuminate\Foundation\Bootstrap\DetectEnvironment',
    'Illuminate\Foundation\Bootstrap\LoadConfiguration',
    'Illuminate\Foundation\Bootstrap\ConfigureLogging',
    'Illuminate\Foundation\Bootstrap\HandleExceptions',
    'Illuminate\Foundation\Bootstrap\RegisterFacades',
    'Illuminate\Foundation\Bootstrap\RegisterProviders',
    'Illuminate\Foundation\Bootstrap\BootProviders',
];

Note, they may look similar at first glance, but the bootstrappers are different between the Console and Http kernels (Console has one more bootstrapper). Don't just copy one of the above and add it to both files.

Edit

Another simpler way would be to setup a before listener for the DetectEnvironment bootstrapper, and set the file to load in an event closure.

So, for example, in your bootstrap\app.php file, add the following code before the return $app; statement:

$app->beforeBootstrapping(
    'Illuminate\Foundation\Bootstrap\DetectEnvironment',
    function($app) {
        // APP_ENV must already be set.
        // We must know which environment file to look for.
        if (! env('APP_ENV')) {
            return;
        }

        // Build the file name to look for (e.g. .env.testing)
        $file = $app->environmentFile().'.'.env('APP_ENV');

        // If the file exists, set the App to load from that file.
        // The actual loading will take place in DetectEnvironment
        if (file_exists($app->environmentPath().'/'.$file)) {
            $app->loadEnvironmentFrom($file);
        }
    }
);

Using the beforeBootstrapping() method, the Closure in the second parameter will be executed immediately before the bootstrapper in the first parameter is called. Now you don't have to worry about Kernels or extra classes or anything.

patricus
  • 59,488
  • 15
  • 143
  • 145
  • I've slowly discovered the fact that 5.1 only supports one `.env` myself over the past hour. Was so confused because personally, Laravel 5.2 was my first intro into the framework, but for a new client, I decided to go with the latest LTS version, which was 5.1. I did end up getting it working another way, using the method here (but with heavily modified Closure code) : http://developers.ph/laravel-framework/laravel-5/how-to-setup-multiple-environment-for-laravel-5-developers-way/, though your way is probably better. I'm just going to stick with the one `.env` file for now. – SteveFromAccounting Sep 22 '16 at 16:51
  • @SteveFromAccounting I've updated my answer with a much simpler solution. Again, not tested, but should work based on source code review. – patricus Sep 22 '16 at 18:28