Laravel - Get current .env() Value - laravel

I am working on a Laravel project. I often change the database connection between Mysql and Sqlite during development. In a php artisan Laravel command I have an import routine. Because I don't want to write the data into the wrong database, I want to set an if condition before the import. But unfortunately it doesn't work quite as I imagined.
if ( env('DB_CONNECTION', null ) === 'sqlite') {
// Import to sqlite
} else if (env('DB_CONNECTION') === 'mysql') {
// Import to mysql
} else {
// no database in env DB_CONNECTION
}
In my .env file currrently the DB_CONNECTION is set on sqlite. But env('DB_CONNECTION', null) returns null.
What do I have to do to find out the current connection? Maybe using env() is not the right choice at this point?

For all those who will have the same problem in the future. Always! But really always, after you have modified the .env variable, you should execute the following "cleaning" commands:
php artisan config:cache
php artisan config:clear
If you still don't get a value, ask SO.

You should not use env() function anywhere except config files. Instead, use config('database.default'), because when configuration is cached, the env is empty for security reasons.
You may create multiple database connections in config/database.php and switch between them manually using facade: DB::connection('sqlite'), or DB::connection('mysql') and avoid this ugly if - else if tree.

Related

What could explain why env() randomly returns null, and changing it to config() seem to fix it? [duplicate]

This question already has answers here:
What is difference between use env('APP_ENV'), config('app.env') or App::environment() to get app environment?
(6 answers)
Closed 16 hours ago.
In some parts of the code I was using env() to read data from the .env file. It would randomly return null instead of the actual value and cause errors. (The values in question do not have quotes around them but they do not contain spaces, only special characters)
Then I came across this post: https://stackoverflow.com/a/42393294/18178584
So, I moved everything that was using env() to a config file, then replaced the code that was using env() with config() and looks like it solved the random null issue.
The post above does mention that it can cause problems in production. However, in my case, the issue happens in development environment as well, and I'm not sure anyone ran the caching commands
Is there a reason for that?
its not random, the env will return null when use anywhere outside the config file if there is a config cache present in bootstrap/cache/config.php
you can do some test
Route::get('test-envi', function() {
return [
'env' => env('APP_NAME'),
'config' => config('app.name')
];
});
without config cache (file dont exist bootstrap/cache/config.php), which you can delete running php artisan config:clear
the result would be
https://yoursite.com/test-envi
{
env: "YourAppName",
config: "YourAppName"
}
with config cache (file exist bootstrap/cache/config.php), which you add running php artisan config:cache or php artisan optimize
the result would be
https://yoursite.com/test-envi
{
env: null,
config: "YourAppName"
}
So; if you're getting null values calling env() function even if the key is present in .env file, that simply means your config was cached

Laravel - How to clear config:cache on each request

I am working on a project which will have 50 subdomains and I found a solution to load separate .env file based on a domain name and everything is working fine... now my problem is
I have to run command config:cache to clear the cache so sytem can load relevant .env file, otherwise, it keeps loading the older .env file. How can i ask system to do cache clear on each load in bootstrap/app.php file???
My Code to load .env files in bootstrap/app.php
$domain = '';
if(isset($_SERVER['HTTP_HOST']) && !empty($_SERVER['HTTP_HOST'])){
$domain = $_SERVER['HTTP_HOST'];
}
if ($domain) {
$dotenv = \Dotenv\Dotenv::create(base_path(), '.env.'.$domain.'.env');
try {
$dotenv->overload();
} catch (\Dotenv\Exception\InvalidPathException $e) {
// No custom .env file found for this domain
}
}
I would advise against doing that because things WILL break.
However, to answer your question, you can use Artisan::call('config:clear') inside a middleware that you can call on each request.
But instead of doing that, you could build a middleware that detects the subdomain you're getting the request from and then call the command instead, just to avoid that extra load.
I used another way to solve this on my project. It is setting the config dynamically according to the request. The config is only valid for the current request. If the count of the dynamic config is less you can use
Config::set('myConfig.hostName', $hostName);
Before doing that you must use the package
use Illuminate\Support\Facades\Config;

Laravel after upgrade, .env variable Undefined index

I'm upgrading Laravel to 5.2 from 5.1. When i refere to variable API_DOMAIN in .env file using $_ENV
$_ENV['API_DOMAIN']
I get an error saying Undefined index: API_DOMAIN". Am I missing something here? should i do something after composer update?
Try using the env helper instead, env('API_DOMAIN')
Run the below commands after making changes in env file. It will flush and repopulate all the env variable.
php artisan config:cache //flush all cached env variable
php artisan config:clear //repopulate all the env variable
php artisan cache:clear //flush all the cached content
You should not directly work with environment values in your application, I would create a new configuration file or use an existing one and add the value there, this way you can cache the configuration.
Lets use your API_DOMAIN as an example:
.env file
API_DOMAIN=www.mydomain.com
Config file
config/api.php for example
<?php
return [
'domain' => env('API_DOMAIN'),
];
Now you can use the config helper to use this variable in your application:
$value = config('api.domain');
You should never use the env() helper outside of config files, because when you cache your config, env() will return null.

What is difference between use env('APP_ENV'), config('app.env') or App::environment() to get app environment?

What is difference between use env('APP_ENV'), config('app.env') or App::environment() to get app environment?
I know that the env('APP_ENV') will to $_ENV, config('app.env') reads the configuration and App::environment() is an abstraction of all. And in my opinion the advantage is even this. Abstraction.
I do not know if there are other differences, such as the level of performance or security
In Short & up-to-date 2022:
use env() only in config files
use App::environment() for checking the environment (APP_ENV in .env).
use config('app.var') for all other env variables, ex: config('app.debug')
create own config files for your own ENV variables. Example:
In your .env:
MY_VALUE=foo
example config/myconfig.php
return [
'myvalue' => env('MY_VALUE', 'bar'), // 'bar' is default if MY_VALUE is missing in .env
];
Access in your code:
config('myconfig.myvalue') // will result in 'foo'
Explanation & History:
I just felt over it. When you cache your config file, env() will (sometimes?) not work right. So what I found out:
Laravel recommends only to use env() within the config files. Use the config() helper in your code instead of env(). For example you can call config('app.env') in your code.
When you use php artisan config:cache all the configuration strings are cached by the framework and any changes you make to your .env file will not be active until you run the php artisan config:cache command again.
From this article on Laracast:
UPDATE:
env() calls work as long as you don't use php artisan config:cache. So it's very dangerous because it will often work while development but will fail on production. See upgrade guide
Caching And Env
If you are using the config:cache command during deployment, you must
make sure that you are only calling the env function from within your
configuration files, and not from anywhere else in your application.
If you are calling env from within your application, it is strongly
recommended you add proper configuration values to your configuration
files and call env from that location instead, allowing you to convert
your env calls to config calls.
UPDATE Laravel 5.6:
Laravel now recommends in its documentation to use
$environment = App::environment();
// or check on an array of environments:
if (App::environment(['local', 'staging'])) {
// The environment is either local OR staging...
}
and describes that env() is just to retrieve values from .env in config files, like config('app.env') or config('app.debug').
You have two equally good options
if (\App::environment('production')) {...}
or
if (app()->environment('production')) {...}
app()->environment() is actually used by Bugsnag, look in documentation here it says
By default, we’ll automatically detect the app environment by calling the environment() function on Laravel’s application instance.
Now, differences:
1) env(...) function returns null after caching config. It happens on production a lot.
2) you can change config parameters inside unit tests, it gives you flexibility while testing.
One thing to consider is perhaps the convenience factor of passing string to app()->environment() in order validate your current environment.
// or App:: whichever you prefer.
if (app()->environment('local', 'staging')) {
logger("We are not live yet!");
Seeder::seedThemAll();
} else {
logger("We are LIVE!");
}
2023 Updated Answer
env() helper works when there is no config.php inside bootstrap/cache directory
config() helper works both in case if the file config.php is present or not. If the file is not present then if will parse the variables at runtime, but if it does find one; it uses the cached version instead.
In production environment the artisan commands we run to add/remove the config file.php becomes of paramount importance in context of how env() and config() behave.
Consider the following example to understand the concept:
Route::get('/', function () {
// to experiment: set APP_ENV=production in your .env file
echo 'Via env(): ' . env('APP_ENV') . '<br/>'; // production
echo 'Via config(): ' . config('app.env'); // production
/*
|--------------------------------------------------------------------------
| run: php artisan config:cache
|--------------------------------------------------------------------------
|
| The config:cache command will generate a configuration cache file (config.php) in the bootstrap/cache directory.
| At this point, the env() helper will no longer work as all ENV variables will be flushed in favor of the cached config.php file.
|
*/
echo '<hr/>';
echo 'Via env(): ' . env('APP_ENV') . '<br/>'; // null
echo 'Via config(): ' . config('app.env'); // production
/*
|--------------------------------------------------------------------------
| run: php artisan config:clear
|--------------------------------------------------------------------------
|
| The config:clear command will remove (config.php) configuration cache file from the bootstrap/cache directory.
| At this point, the env() helper will work again as framework doesn't find a cached configuration file.
|
*/
echo '<hr/>';
echo 'Via env(): ' . env('APP_ENV') . '<br/>'; // production
echo 'Via config(): ' . config('app.env'); // production
});
So general rule of thumb is to always use config() helper inside your code files; in this way your code does not explode if cached configuration file is available or not.
Now getting the environment is so important and common; Laravel gives us a handful ways we can accomplish the same:
// APP_ENV=production inside .env file
App::environment(); // production
app()->environment(); // production
App::environment('production'); // returns boolean: true
app()->environment('production'); // return boolean: true
Keep in mind you are using App facade or app() helper they all will be using config helper under the hood.
If you are using the config:cache command during deployment, you must make sure that you are only calling the env function from within your configuration files, and not from anywhere else in your application.
If you are calling env from within your application, it is strongly recommended you add proper configuration values to your configuration files and call env from that location instead, allowing you to convert your env calls to config calls.
Add an env configuration option to your app.php configuration file that looks like the following:
'env' => env('APP_ENV', 'production'),
More: https://laravel.com/docs/5.2/upgrade#upgrade-5.2.0
In 12factor methodology application contains two types of configuration values:
internal which not vary between deploys and are stored in laravel ./config/ folder. In this type we usually store some technical optimal/good values used in application which should not be changed by users over time e.g. optimal image compression level, connection timeout, session expiration time etc.
external which vary between deploys and are stored in .env file (but should not be stored in git repo, however .env.example with example values with detail info can be stored in repo). In this type we store usually some important/protected values which depends on local environment e.g. passwords, debug mode, db address etc.
Laravel proposes handy approach for this
in regular code we use only config(...) helper (so on this level programmer do not need to know which configuration value is internal and which is external)
in configuration code external config values should be set using env(...) helper e.g. in config/app.php 'debug' => env('APP_DEBUG', false)

How to create a mysql db with Laravel

I'm using Laravel 5.2. I've setup my first migrations and I want to run them. From the video tutorial it doesn't explain how to create a mysql db. I know I can do this manually in phpmyadmin but is there a Laravel way to do it?
This will install the migrations table:
php artisan migrate:install
Is there a similar command that will create the DB?
I'm thinking the process should be:
php artisan DB:install (or similar command)
Install the migrations table:
php artisan migrate:install
Run the migrations:
php artisan migrate
and to rollback the migrations:
php artisan migrate:rollback
Nothing provided out of the box but you could make your own command that could do this for you:
php artisan make:console CreateDatabase
// Note, in 5.3 this is make:command
Then in app/Console/Commands you'll find CreateDatabase.php. Open that sucker up and let's make a few changes:
protected $name = "make:database";
// in Laravel 5.3 + it's protected $signature
Then down below in your file we need a new function:
protected function getArguments()
{
return [
['name', InputArgument::REQUIRED, 'The name of the database'],
];
}
Then we'll make another function called fire() which will be called upon invocation of the command:
public function fire()
{
DB::getConnection()->statement('CREATE DATABASE :schema', ['schema' => $this->argument('name')]);
}
And now you can just do this:
php artisan make:database newdb
Now you'll get a newdb database created for you based on your connection configuration.
Edit Forgot the most important part - you need to tell app\Console\Commands\Kernel.php about your new comand, make sure to add it to the protected $commands[] array.
protected $commands = [
///...,
App\Console\Commands\CreateDatabase::class
];
This answer might be useful if you are using different mysql connection also. I am writing code in laravel 5.5
Step:1 Create command
php artisan make:command CreateDatabaseCommand
Step:2 In app/Console/Kernel.php register the command
protected $commands = [
CreateDatabaseCommand::class
];
Step:3 Write logic in your CreateDatabaseCommand.php file
protected $signature = 'make:database {dbname} {connection?}';
public function handle()
{
try{
$dbname = $this->argument('dbname');
$connection = $this->hasArgument('connection') && $this->argument('connection') ? $this->argument('connection'): DB::connection()->getPDO()->getAttribute(PDO::ATTR_DRIVER_NAME);
$hasDb = DB::connection($connection)->select("SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = "."'".$dbname."'");
if(empty($hasDb)) {
DB::connection($connection)->select('CREATE DATABASE '. $dbname);
$this->info("Database '$dbname' created for '$connection' connection");
}
else {
$this->info("Database $dbname already exists for $connection connection");
}
}
catch (\Exception $e){
$this->error($e->getMessage());
}
}
That's all. Now run your command
php artisan make:database {your-database-name} {your-connection-name}:
Note :: You should use second argument only if you want to create database in any different connection from default mysql connection otherwise command will automatically take the default db connection
Hope this will help someone :)
If you're not going to use a Vagrant box or virtual machine for local development then you're going to have to install your database driver of choice and then create a new database.
To do that with MySQL from the command line run:
$ mysql -uroot -p
mysql> create database yourDatabaseName;
Then cp .env.example .env and update your database creds.
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=yourDatabaseName
DB_USERNAME=root
DB_PASSWORD=root
You'll have set up the username and password to your database when you first installed the driver. After this you may have to php artisan key:generate and/or 'php artisan config:clearbutphp artisan migrate` should work. Below are some tutorial resources you may find helpful:
Initial database creation and seeding with Laravel 5
How to install MySQL on OSX
Vikash's response worked. (in Laravel 5.8)
Based on the response of Vikash:
How to create a mysql db with Laravel
I have created the following command which creates a MySQL database with the collation that you assign.
I have uploaded it to this GitHub repository
I hope it helps other developers.
You should create the DB, and set the connection parameters to it. Then, Laravel will access the DB and will run the migrations (make the tables) and the seeders.
You can found the parameters for php artisan migrate here: https://laravel.com/docs/5.2/migrations#running-migrations
You can create the database using Laravel Tinker. First configure the right DB_ settings in your .env file.
Then run the following commands:
php artisan tinker
$pdo = new PDO('mysql:host=' . env('DB_HOST'), env('DB_USERNAME'), env('DB_PASSWORD')));
$pdo->exec('CREATE DATABASE ' . env('DB_DATABASE'));
exit
As a one liner it looks like this:
php artisan tinker --execute="(new PDO('mysql:host=' . env('DB_HOST'), env('DB_USERNAME'), env('DB_PASSWORD')))->exec('CREATE DATABASE ' . env('DB_DATABASE'))"
you have to make your modal first and make its migration table also in order to make a database.
you should use: php artisan make:model -m command to make model and migration table. after that open your migration table in any texteditor to add the columns in your database table and then, use this command to migrate:
php artisan migrate

Resources