Environment driven database settings in Laravel?

I am moving over the the Laravel framework, but I am having trouble with the database settings,

Specifically, I have my environments setup, and they are working fine for the application.php config file, however the database.php config file seems to have no effect.

Even if I have a database.php config file in my environments folder it is never loaded, I put a bunch of invalid characters (keyboard mash) into the file to get php to throw an error, but it is never hit.

Does Laravel not support environment based database settings? or am I doing this wrong?


Solution 1:

You can definitely set database settings (and any other config setting) by environment.

For Laravel 3 (for Laravel 4 and Laravel 5 see below):

Firstly - you need to define $environments in your paths.php and set it to something like this:

$environments = array(
  'development' => array('*.dev'),
  'production' => array('*.com'),
);

Laravel will automatically look for this variable, and if set, will use the associated configuration.

Normally you have a config folder, with settings such as database.php and auth.php

Now just create a new folder for each Laravel_Env you plan to use (such as Development). You'll end up with a folder structure like this;

/application
  /config
    /development
      database.php
    /production
      database.php
    application.php
    config.php
    database.php
    ...
    user_agents.php

You'll note I've only included database.php in each subfolder. Laravel will always load the default config settings first, then override them with any custom configs from the environments setting.

Finally, in your development/database file, you would have something like this;

<?php
 return array(
'default' => 'mysql'
 );

p.s. I just tested this on the current 3.2.12 build of Laravel - and it definitely works.

Bonus Tip: You can also automatically set an environment for Artisan, so you do not have to include the environment manually on each command line! To do this:

  1. You need to know your 'hostname' that you are running Artisan on. To find out - temporarily edit the artisan.php in your root folder, and add var_dump(gethostname()); to line 2 (i.e. above everything).

  2. Run php artisan from the command line. You will get a string dump with your hostname. In my case its "TSE-Win7";

  3. Remove the changes to the artisan.php file

  4. Add your hostname (i.e. "TSE-Win7") to the environments.

You should end up with something like this:

$environments = array(
  'development' => array('*.dev', 'TSE-Win7'),
  'production' => array('*.com'),
);

Artisan will now run using your development environment. If you deploy to a live server - re-run these steps to get the hostname() for the server, and you can configure a specific artisan config just for the server!

For Laravel 4:

The default environment is always production. But in your start.php file you can define additional environments.

 $env = $app->detectEnvironment(array(
   'local' => array('your-machine-name'),
));

On Linux and Mac, you may determine your hostname by type hostname in your terminal - it will output the name of your computer. On Windows put dd(gethostname()); at the beginning of your routes.php file - and run the website once - it will show you the current hostname of your computer.

To get the current environment as a variable in your application - read this SO answer here. Laravel 4: how can I get the environment value?

For Laravel 5:

There is single configuration file, called .env in your root directory. Watch this laracast, config explained fully.

Solution 2:

if you are using the artisan ( command line for laravel ) every command you need to add

artisan bla bla bla --env=Development 

or

artisan bla bla bla --env=Production

Solution 3:

Heres how I have it setup for my needs.

I personally need 4 different configurations:

  1. localhost (Mac OSX) - /Library/WebServer/Documents/www/my-domain.com/development/
  2. dev.my-domain.com (VPS) - /var/www/my-domain.com/development/
  3. test.my-domain.com (VPS) - /var/www/my-domain.com/test/
  4. my-domain.com (VPS) - /var/www/my-domain.com/web/

Since all 4 of my environments have distinctive directory structure, I can use php's magic constant __DIR__ to fetch the app directory and then use the strpos() function to do a simple check and return the appropriate environment. It will take care of Artisan environment as well, no need to manually type the environment, or add any machine names.

Inside the

bootstrap/start.php

Add a callback function

$env = $app->detectEnvironment(function(){

  $haystack = __DIR__; // Catch the directory path

  // Set the booleans (remove the first '/', else strpos() will return 0)
  $isLocal       = strpos($haystack, 'Library/WebServer/Documents/www/my-domain.com/development/');
  $isDevelopment = strpos($haystack, 'var/www/my-domain.com/development/');
  $isTest        = strpos($haystack, 'var/www/my-domain.com/test/');
  $isProduction  = strpos($haystack, 'var/www/my-domain.com/web/');

  // Set the environments
  if ($isLocal)       $environment = "local";
  if ($isDevelopment) $environment = "development";
  if ($isTest)        $environment = "test";
  if ($isProduction)  $environment = "production";

  // Return the appropriate environment
  return $environment
});

Another alternative

We can also set and grab all the values at once into an array, and run a foreach loop.

Tip: Since we using the strpos() function, which checks position of the first occurrence of the given value against the $haystack, and returns the position number. We don't really have to supply the entire path, we can simply add a distinctive value from each path to get the job done.

// Check the boolean, if true set to given value, else set NULL
$environments[] = strpos($haystack, "Library") ? 'local'      : NULL;
$environments[] = strpos($haystack, "develop") ? 'development': NULL;
$environments[] = strpos($haystack, "test")    ? 'test'       : NULL;
$environments[] = strpos($haystack, "web")     ? 'production' : NULL;

// Loop through each, if not null then we have our environment
foreach ($environments as $environment) {
     if(!is_null($environment))
     return $environment;
}

Whether we work on one machine or multiple, the chances of having the same path to different environments is very slim.

Or so I think. :)