I've to deploy several instances of a Laravel app to a unique server. Each instance requires a different database configuration. The default Laravel's environment configuration based on hostnames doesn't work for me because all the apps are going to be on the same server, so there's no way to tell which config fiel to use. Here is my bootstrap/start.php file:
$env = $app->detectEnvironment(array(
'development' => array('Ariels-MacBook-Pro.local'),
'server' => array('srv-hostname'),
));
It would be great that I can define the environment based upon a domain (because my apps area gonna be on diferent domains), so in this way I can define a different config for each domain (hosted on the same server)
Any ideas?
Laravel's detectEnvironment method has a nify feature where you can progamatically determine the current enviornment with a closure. For example, this would configure Laravel to always use the local enviornment.
$env = $app->detectEnvironment(function()
{
return 'local';
});
The domain name should be somewhere in $_SERVER, so something like this untested pseudo-code should get you what you want.
$env = $app->detectEnvironment(function()
{
switch($_SERVER['HTTP_HOST'])
{
case: 'example.com':
return 'production';
case: 'another.example.xom':
return 'production';
default:
return 'local'; //default to local
}
});
My option, in file app/config/database.php add this line at the end
'enviorement' => 'local',
// 'enviorement' => 'development', // this is for dev
// 'enviorement' => 'production', // this is for production
and then access from your controller with this
$env = Config::get('database.enviorement');
echo $env;
database.php file is different, you have for ur local another for developemet server and another for producction because there is the "database conection" so i used it to implicit write the enviorement.
Have fun.
Related
I am starting the program with Laravel and I have in my ".env" file my access data to the server:
USER_SERVER=user
PASSWORD_SERVER=123456789
I have my role in my controller:
public function connectServer()
{
$connection=ssh2_connect(172.17.2.33, 22);
ssh2_auth_password($connection, USER_SERVER, PASSWORD_SERVER);
$stream=ssh2_exec($connection, "df -h");
$errorStream = ssh2_fetch_stream($stream, SSH2_STREAM_STDERR);
}
My role above has problems. What is the correct way to call the user and password of my ".env" file for my function?
You should use the configuration system for these values. You can add to a current configuration file in the config folder or create your own that returns an associative array. We will use the env() helper to pull the values you set in the .env file:
<?php
return [
...
'server' => [
'user' => env('USER_SERVER', 'some default value if you would like'),
'password' => env('PASSWORD_SERVER', ...),
],
...
];
If you added this key to the services.php file in the config folder you would then access this configuration value via the Config facade or the config() helper function:
// if we want a value from the services.php file
Config::get('services.server.user');
config('services.server.user');
// if you want all of them for that server array
$config = config('services.server');
echo $config['user'];
Using the configuration system this way allows you to use the "config caching" that Laravel provides, as you will not have any env() calls in your application, except for in the config files, which can be cached. [When configuration caching is in place it doesn't load the env]
"If you execute the config:cache command during your deployment process, you should be sure that you are only calling the env function from within your configuration files. Once the configuration has been cached, the .env file will not be loaded and all calls to the env function will return null." - Laravel 7.x Docs - Configuration - Configuration Caching
Laravel 7.x Docs - Configuration - Accessing Configuration Values config()
Laravel 7.x Docs - Configuraiton - Retrieving Environmental Configuration env()
How can I change the app environment at run time?
I have some classes that only bind in the service provider in production. I'd like to assert with a unit test that they are properly bound. For other environment variables, I can set them with the config helper and then simply call resetApplication in tearDown but for some reason the variable set by APP_ENV doesn't change.
dump(app()->environment()); // "testing"
config(['app.env' => 'production']);
dump(app()->environment()); // "testing"
What can I do to get app()->environment() to return production at run time?
app()->environment() reads directly from the variables specified in your .env file rather than the configuration files.
You could take two approaches to solve your problem.
1. Read the environment variables from the config file rather than the .env file.
dump(config('app.env')); // "testing"
config(['app.env' => 'production']);
dump(config('app.env')); // "production"
2. Change the value of 'env' in the current app instance by changing the value of app()['env'].
dump(app()->environment()); // "testing"
app()['env'] = 'production';
dump(app()->environment()); // "production"
I've noticed that above answer can be a bit dangerous: You might be overwriting the 'env' key, without truly switching environments. Suddenly your app says that you are in testing, while your DB connection is still set to production.
Normally you just want to really stick to the Laravel best practice of defining ONE environment for each literal environment, but for my use case I needed to temporarily & programmatically switch between multiple environments within a single artisan script.
My solution (works in Laravel 5.8+ with DotEnv3) would be to really reboot the application:
<?php
$basepath = app()->basePath();
$env = app()->basePath('.env.alternative');
$boot = app()->basePath('bootstrap/app.php');
// Overwrite webserver env
(new Dotenv($basepath,'.env.alternative'))->overload();
// Reboot the application
(require $boot)
->loadEnvironmentFrom($env)
->make(Kernel::class)
->bootstrap();
// This returns 'mysql_alternative', as defined in .env.alternative
dd(DB::connection()->getName())
Disclaimer: I've only tested this to the extend of my own code.
From a testing point of view, then in the setUp() method:
$this->app['env'] = 'production';
But remember, only do this in a test class, specifically testing production runs. Otherwise, do it at the top of the test method, remembering to set it back to testing at the end.
If you adjust the setUp() method, remember your tearDown() method and change it to testing. By altering the $this->app['env'], you are directly changing the Applications environment, which is why it's so important to remember to set it back as it will produce side effects, also only do this in testing .
We have a Laravel 4.2 site based in the US that we're looking to whitelabel in Canada then the UK. I have a local and test environment for both (staging vs canada_staging, etc), and the problem I have with production is we have a lot of if conditions that checks if the environment is production (if (App::environment() === 'production') for instance). I could use production for both, but each site has its own specific configuration and language files (for instance they have provinces instead of states). Is there an easy way to overcome this situation?
Yes, you can create file app/bootstrap/environment.php on each server and define env.:
<?php
return 'production-us;
In app/bootstrap/start.php in detect env. section add this:
$env = $app->detectEnvironment(function ()
{
return require __DIR__.'/environment.php';
});
You will have unique env. on each server in the easiest way.
Related post here.
I want custom environment detection. I know how the existing Laravel environment detection works, but I want a more dynamic way. I want to EXPORT a variable in my Ubuntu env, suggesting it's 'development' or 'production', as opposed to using host names and IP addresses.
Any help would be great, thanks.
What I do in my projects is I create a file "app/bootstrap/environment.php"
environment.php
<?php
//Get the environment
$environment = getenv('ENV');
//Check if the environment has been set
if(is_string($environment) && ($environment != '')){
//Return the environment
return $environment;
}else{
//On default return production environment
return 'production';
}
Then in "app/bootstrap/start.php"
start.php
$env = $app->detectEnvironment(function()
{
//Return the environment we're currently using
return require __DIR__.'/environment.php';
});
Works perfect for me.
Laravel 4.1 removed the feature to use the domain for detecting what environment the app is running in. Reading the docs they now suggest using host names. However, to me that seems cumbersome if you are working in a team. Should everyone change the bootstrap/start.php file and add their own host name to be able to run the app in a dev environment? Also, what if you want to have two different environments on the same machine?
How to best detect the environment if you are working in a team in Laravel 4.1+?
Here is my settings from bootstrap/start.php file:
$env = $app->detectEnvironment(function() use($app) {
return getenv('ENV') ?: ($app->runningInConsole() ? 'local' : 'production');
});
Instead of default array, this method in my case is returning closure with ternary. That way I got more flexibility in choosing desired environment. You can use switch statement also. Laravel will read return value and configure itself.
With getenv native function, I am just listening for a given environment. If my app is on the server, then it will "pick" server configurations. If locally, then it will pick local (or development)
And don't forget to create custom directories for you environemnts in app/config
There is also testing env, which is choosen automatically, every time you are unit testing app.
Laravel makes working with environments really fun.
UPDATE:
With environments we are mostly cencerned about db credentials.
For production I use Fortrabbit, so when configuring new app on server, fortrabbit is generating those values for me. I just need to declare them. e.g. DB of just database or db... Or DB_HOST or HOST ...
Locally, those values are the one you use for your localhost/mysql settings.
Update:
In Laravel 5.0 environment detection is no longer needed in the same way. In the .env file you can simply have a variable for which environment the app should run in.
Old answer for Laravel <= 4.2
What I ended up doing is very close to what carousel suggested. Anyway, thought I would share it. Here is the relevant part of our bootstrap/start.php file:
$env = $app->detectEnvironment(function ()
{
if($app->runningInConsole())
return "development";
$validEnvironments = array("development", "staging", "production");
if (in_array(getenv('APP_ENV'), $validEnvironments)) {
return getenv('APP_ENV');
}
throw new Exception("Environment variable not set or is not valid. See developer manual for further information.");
});
This way all team members have to declare an environment variable somewhere. I haven't really decided if throwing an exception if the environment variable is not set or just default to production is the best thing. However, with the above, it's easy to change.
For me, I just use 'dev' => '*.local' and it works. I haven't 100% tested in a team situation but I think it'd work (big assumption alert:) assuming you're on OSX and get the default Alexs-iMac.local-like hostname.
As for faking an environment, I'm not sure it's really supported. It'll be doable, but in general the whole point of environments is that dev has entirely different needs to production and the two are mutually exclusive. Having the ability to switch on one physical environment seems counter to that goal.
Laravel 4.1 and 4.2 detects the environments through the machine names specified in the "bootstrap/start.php" file.
For example, in my case the config becomes:
$env = $app->detectEnvironment(array(
'local' => array('Victor.local', 'Victor-PC'),
));
This means that Laravel will use the 'local' environment settings for both machines: 'Victor.local' (a Mac) and 'Victor-PC' (Windows).
This way you can regsiter several machines to work as local environment. Other environments can be registered too.
In order to know the current machine name, you can use the following PHP code:
<?php echo gethostname(); ?>
Hope it helps!
You can use something like this:
$env = $app->detectEnvironment(function(){
if($_SERVER['HTTP_HOST'] == 'youdomain_local')
{
return 'local';
}elseif($_SERVER['HTTP_HOST'] == 'youdomain_team')
{
return 'team';
}else{
return 'production';
}
});
what i did is, make dir app/config/local and use code
$env = $app->detectEnvironment(function(){
return $_SERVER['HTTP_HOST']=="localhost"?"local":"production";
});
For localhost and online.
I didn't like that production was default, so I made it anything other than live server will go to local configs:
in bootstrap/start.php :
$env = $app->detectEnvironment(function(){
if (gethostname() !== 'live_server_hostname'){
return 'local';
} else {
return 'production';
}
});
In bootstrap/start.php define this:
$env = $app->detectEnvironment(function() use($app) {
$enviromentsHosts = [
'localhost',
'local',
];
if ($app->runningInConsole() || in_array($app['request']->getHost(), $enviromentsHosts)) {
return 'local';
} else {
return 'production';
}
});
I believe it is better to use only the resources of Laravel 4