Why Laravel uses wrong database file after setting environment? - laravel

In bootstrap/start.php I have the following:
$env = $app->detectEnvironment(function()
{
if($myenv = getenv('APPLICATION_ENV')):
return $myenv;
else:
return 'local';
endif;
});
Ok so I setup a local folder and put in a database.php file with my local connections.
Just to make sure its picking up the correct environment I put in the template: {{ App::environment(); }} which outputs local.
But when making a DB call its giving me error: Undefined index: DB1_HOST
My base (production) database.php file has:
'host' => $_SERVER["DB1_HOST"],
'database' => $_SERVER["DB1_NAME"],
'username' => $_SERVER["DB1_USER"],
'password' => $_SERVER["DB1_PASS"],
Why is it looking at the production database file?

Laravel also stores the config information in
bootstrap/cache/config.php
In some cases it's not updated which may result in wrong database information. Deleting the file should resolve the issue.

If you are trying to use artisan in your terminal and you want to set the environment variable once and for all, you can do :
export APPLICATION_ENV=local
And check you current environment using php artisan env

Production config files are loaded first and then merged with overrides from other environments. If the production file generates an error (e.g. undefined index) the config loading will bail early without loading the overrides. In the production config file, check the value is set before attempting to use it and the local config file will then load correctly.

Clean the config cache as it may affect
php artisan config:cache

Related

CodeIgniter 4 plus Myth/Auth throws error when running Migrations via php spark migrate -all

I have discovered some wired behavior, I have that one CI4 project i am working on since a couple of weeks. everything is working just fine, but until now i have just been working with the project on my local machine. When i wanted to run the project on my Laptop in ran into an error when i tried to run the migrations with php spark migrate -all
CodeIgniter CLI Tool - Version 4.0.4 - Server-Time: 2020-07-20 06:16:02am
Running all new migrations...
An uncaught Exception was encountered
Type:        CodeIgniter\Database\Exceptions\DatabaseException
Message:     Unable to connect to the database.
Filename:    /opt/lampp/htdocs/sms/vendor/codeigniter4/framework/system/Database/BaseConnection.php
Line Number: 425
The project includes Myth/auth, so i tried just to run "my" migration with php spark migrate . That just worked fine, no problem at all, the tables are there, no errors. Just for fun, i moved my Math/auth migrations from the vendor folder to the "normal" Database/Migrations folder and was able to migrate them that way.
That's very wired, especially since everything is working just fine on the PC I have been using before. There I am able to run the migrations using php spark migrate -all without any errors, when is set up a fresh MySQL/MariahDB database. But somehow only there.
I was able to reproduce the error on my laptop on my Manjaro partition, my Windows 10 partition and on my iMac.
So if you want to reproduce the error do the following:
composer create-project codeigniter4/appstarter whatever
rename the env to .env
set CI_ENVIRONMENT = development and obviously uncomment that line
configure and uncomment your database setting in the .env
create a sample migration like the one from the docs using > php spark migrate:create AddBlog
add the following content to the new migration and save the file:
forge->addField([
'blog_id' => [
'type' => 'INT',
'constraint' => 5,
'unsigned' => true,
'auto_increment' => true,
],
'blog_title' => [
'type' => 'VARCHAR',
'constraint' => '100',
],
'blog_description' => [
'type' => 'TEXT',
'null' => true,
],
]);
$this->forge->addKey('blog_id', true);
$this->forge->createTable('blog');
}
public function down()
{
$this->forge->dropTable('blog');
}
}
run > composer require myth/auth
Edit app/Config/Email.php and verify that a fromName and fromEmail are set as that is used when sending emails for password reset, etc.
Edit app/Config/Validation.php and add the following value to the ruleSets array: \Myth\Auth\Authentication\Passwords\ValidationRules::class
Ensure your database is setup correctly, then run the Auth migrations: php spark migrate -all
As a result you will also have the above error. I was not able to
get around that error, except for the system in was working with at
first.
If you just use php spark migrate it will migrate the sample migration without any errors
I am running CI 4.04 on Kubuntu 18.04 LTS, running apache2.4.29 and PHP 7.4.9
The short answer is...
Using php spark migrate -all searches everywhere it knows about for Database/Migrations Folders and files.
There just so happens to be a such folder/file under
tests/_support/Database/Migrations/2020-02-22-222222_example_migration.php
The bits added to make the short answer longer
So the Database error we are seeing is due to not having set up Database credentials for $tests in /app/Config/Database.php
All it's doing is looking to connect to the DB set up under $tests, but appears not to actually run as we don't want it to.
That appears to be enabled when ENVIRONMENT is set to "testing".
So 3 options for the time being...
Ignore the error. But that always leaves you wondering what's really happening.
Setup the credentials for the $tests Database. (Not really warranted.) OR
Delete/Rename the tests folder if you are not using it. (Stop it finding it.)
Would be to use the -n switch/option and specify the namespace to use (but not sure that's working.)
Changing DB hostname to '127.0.0.1' from localhost in your .env file usually solves the problem of running any migrations from the command line.
Open your PHP.ini file, find this :
;extension=sqlite3
and remove the semicolon to activate sqlite3. You need this library in Codeigniter 4 in order to use FORGE.

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.

Laravel Project is Serving without .env file

If .env is removed on my Laravel project the command
$ php artisan key:generate
Causes this error
ErrorException : file_get_contents(/folder/projectlocation/.env): failed to open stream: No such file or directory at //folder/projectlocation/vendor/laravel/framework/src/Illuminate/Foundation/Console/KeyGenerateCommand.php:96
{
file_put_contents(
$this->laravel->environmentFilePath(),
preg_replace(
$this->keyReplacementPattern(),
'APP_KEY='.$key,
file_get_contents($this->laravel->environmentFilePath())
));
}
However the php artisan serve command works "Laravel development server started: <http://127.0.0.1:8000>"
I have cleared all the Laravel caches. Why will it serve but not fetch the .env file configuration?
That is correct. All application config comes from the config files in the config/ folder. Each of the options in here is configured to take either the value from the .env file or a default value.
For example, the application key in the config/app.php file:
'key' => env('APP_KEY'),
So when no value is set for APP_KEY in .env, the application key will be null (not recommended!).

Laravel can't change config value

I found the problem, i'll try to use a homestead or docker.
if i restart php artisan serve the changed values are applied.
Same my post: Laravel can't change config value
I make route
Route::get('/config', function () {
return dd(config('app'));
});
And cant change my config/app.php, for example i want to change
'url' => env('APP_URL', 'test'),
'client_url' => env('APP_CLIENT_URL', 'test'),
I set
APP_CLIENT_URL=str1
APP_URL=str2
and there is something inexplicable:
My "url" => "http://127.0.0.1:8000" !!! not default 'test' or from .env, I did not set such a value.
My client_url contains the old value, after I cached the config.
This is not production, i accidentally run config:cache, but after i remove all cache from bootsrap/cache, storage/framework/cache and running cache:clear, config:clear.
After running config:cache values from the .env were put in config, but I do not want to constantly change cache in development and it is not recommended in the documentation.
How can I easily change .env in in developing?

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)

Resources