46

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?

Hailwood
  • 89,623
  • 107
  • 270
  • 423
  • its my first time hearing about environment based database settings. How do you set those up? and what's the advantage of using it?. I've also started learning laravel a few weeks ago, I've also played around with the database classes like fluent and eloquent but never encountered this. – Wern Ancheta Dec 13 '12 at 14:05
  • It is based on environments, the [docs](http://laravel.com/docs/install#environments) and it should work for any configuration file, not sure what's the problem. – TLGreg Dec 13 '12 at 15:46
  • Are you sure that the database.php file in the config folder is being loaded? Have you tried throwing errors from there? – J.T. Grimes Dec 13 '12 at 18:57
  • Also, have you made sure that other configs in your environment folders are being loaded? Perhaps Laravel just doesn't know you're in test or dev or production? – J.T. Grimes Dec 13 '12 at 18:58

10 Answers10

64

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.

Community
  • 1
  • 1
Laurence
  • 58,936
  • 21
  • 171
  • 212
  • 1
    credit also goes to "JoelLarson" and "Kindari" from Laravel IRC who helped develop artisan solution. – Laurence Dec 15 '12 at 14:33
  • thx for the artisan tipp! I love using artisan for cronjob tasks, and this makes it even easier! – aebersold Dec 18 '12 at 11:17
  • The issue I was having was that I was running artisan, and I was not aware it loaded it's own config like that, so your artisan tip is the fix :) – Hailwood Feb 13 '13 at 07:48
  • I'm using MAMP on port 8888, and *.dev wasn't being recognized - using your artisan trick solved the issue - tx! – ptim Apr 03 '13 at 07:54
  • 1
    I was able to set the local environment as default passing $app->detectEnvironment(array( 'production' => array('my-production-hostname'), 'local' => array('*') )); – guigouz Jun 26 '14 at 21:51
8

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
Knight
  • 484
  • 4
  • 10
  • You are correct - but actually there is a way around it to automate the process. I've editted my answer to show the required steps. – Laurence Dec 15 '12 at 14:32
4

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. :)

2

How to setup environment specific configuration is now in the official Laravel docs. I would recommend using their method instead of the accepted answer:

It is often helpful to have different configuration values based on the environment the application is running in. For example, you may wish to use a different cache driver on your local development machine than on the production server. It is easy to accomplish this using environment based configuration.

Simply create a folder within the config directory that matches your environment name, such as local. Next, create the configuration files you wish to override and specify the options for that environment. For example, to override the cache driver for the local environment, you would create a cache.php file in app/config/local with the following content:

<?php    
return array(    
    'driver' => 'file',    
);

Note: Do not use 'testing' as an environment name. This is reserved for unit testing. Notice that you do not have to specify every option that is in the base configuration file, but only the options you wish to override. The environment configuration files will "cascade" over the base files.

Next, we need to instruct the framework how to determine which environment it is running in. The default environment is always production. However, you may setup other environments within the bootstrap/start.php file at the root of your installation. In this file you will find an $app->detectEnvironment call. The array passed to this method is used to determine the current environment. You may add other environments and machine names to the array as needed.

<?php

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

In this example, 'local' is the name of the environment and 'your-machine-name' is the hostname of your server. On Linux and Mac, you may determine your hostname using the hostname terminal command.

If you need more flexible environment detection, you may pass a Closure to the detectEnvironment method, allowing you to implement environment detection however you wish:

$env = $app->detectEnvironment(function()
{ 
    $domain = explode('.', $_SERVER['HTTP_HOST']);
    switch($domain[0])
    {
        case 'localhost':
        case 'localhost:8080':                
        case 'dev':
            return 'development';
            break;
        case 'mysite':
        default:
            return 'production';
            break;
    }
});

You may access the current application environment via the environment method:

Accessing The Current Application Environment

$environment = App::environment();

You may also pass arguments to the environment method to check if the environment matches a given value:

if (App::environment('local'))
{
    // The environment is local
}

if (App::environment('local', 'staging'))
{
    // The environment is either local OR staging...
}
Justin
  • 26,443
  • 16
  • 111
  • 128
  • Justin: I have added new environment in start.php. $env = $app->detectEnvironment(array('local' => array('localhost'),)); After that, I did like below. $envname = App::environment(); echo $envname; It return production. Please advice. How to get local env name? Thanks in advance. :) – user2003356 Apr 08 '14 at 09:29
  • If you pass an array to `$app->detectEnvironment()` it expects your machine name as the second value. Your machine name is definately not `localhost` as you have used. Search google for how to find your real machine name OR pass a function instead of an array to get the environment based on URL... I'll add an example of that. – Justin Apr 08 '14 at 16:39
2

Laravel 5

Use the DotEnv approach detailed in the Laravel docs here.

Laravel 4

We are using the method Jeffrey Way recommended in this Laracasts lesson.

  • Create config directories for each environment.

    /app
        /config
            /local
                database.php
            /production
                database.php
    
  • Set an environment variable on your production server. Google for the best approach on your production platform. For example, here are great suggestions for Ubuntu, Dreamhost, and Heroku. We added a single line to /etc/environment:

    ENV=production
    
  • Add this closure to /bootstrap/start.php. With this setup, any server missing the ENV environment variable will default to the local environment config.

    $env = $app->detectEnvironment(
        function () {
            return getenv('ENV') ? : 'local';
        }
    );
    
Community
  • 1
  • 1
Troy Harvey
  • 2,331
  • 1
  • 20
  • 18
1

I've been working away on this today, struggling to work out how best to do environmental settings for a database. In the end, after trying several methods, I fully agree with @troy-harvey that Jeffrey Way's recommendation of doing this is the best (for me at least). One thing I will add to this, and its what held me up so much today is (and correct me if I'm wrong) that you need to access the settings you are trying to over-ride in your environmental settings file by their corresponding array keys. I started out returning a simple array:

return [
    'database' => '<db_name>',
    'username' => '<db_user>',
    'password' => '<db_pass>',
]; 

within an app/config/staging/database.php. This had no effect and after much head scratching realised that you need to access the array as it is presented in app/config/database.php, like so:

<?php

return [
'connections' => [
    'mysql' => [
        'database' => '<db_name>',
        'username' => '<db_user>',
        'password' => '<db_pass>'
    ]
  ]
];

At least this is how I finally managed to get my settings being picked up.

Adding this here in case anyone else is struggling to work this out. Upon realisation I understood how obvious a mistake I was making.

Edited 01 July 2014

An additional comment to this is that since 4.1 Laravel ships with an append_config() helper function for appending environmental configurations to the main config array.

This would look like this for the example given above:

<?php

return append_config([
     'connections' => [
        'mysql' => [
             'database' => '<db_name>',
             'username' => '<db_user>',
             'password' => '<db_pass>'
        ]
      ]
   ]);

Schneidey
  • 51
  • 6
  • You can also simply copy the database.php file (located in app/config/) directly into you environment folder (for example in the app/config/local directory) and simply edit this file with your local database settings. – Iam Zesh Oct 08 '14 at 10:46
0

In Laravel 3 to detect the environment it was:

Request:env()

Which would return whatever was identified in the environments array found in the paths.php file.

As mentioned before in Laravel 4 it is now:

App:: environment()
Robert Brisita
  • 5,461
  • 3
  • 36
  • 35
0

My way of doing it!

$env = $app->detectEnvironment( function() {
    if ( file_exists('../.env.local.php') ) {
        return 'local';
    }
    if ( file_exists('../.env.beta.php') ) {
        return 'beta';
    }
    return 'production';
} );
Abi Xalmon
  • 101
  • 1
  • 1
  • 4
0

If you're trying to use Laravel in a Windows environment, check out the settings in file .env in the top level folder for your Laravel project - these will override whatever database settings you have in config/database.php

0

If you are on Laravel 4 here is a gist that will take you through the process step by step. Credits to @"The Shift Exchange"'s answer for guiding me to create it.

Timothy
  • 4,198
  • 6
  • 49
  • 59