Laravel - Load different .env file - php

I need to load a different .env file, named .env.test under certain conditions.
I attempted to do that through a middleware by adding
app()->loadEnvironmentFrom('.env.test');
Dotenv::create(base_path(), '.env.test')->overload();
to the bootstrap() method of Kernel.php. I also tried to create a dedicated middleware for this and load it as the first one in the web middleware group. But either way, it is loading the standard .env file.
It works if I do it in the /bootstrap/app.php file but I really don't want to put it there.

I just figured it out: The default .env file is being loaded inside of the bootstrap() method of LoadEnvironmentVariables.php.
To use the .env.test file I had to restructure my initial bootstrap() method inside of the App/Http/Kernel.php file to look like this:
public function bootstrap()
{
app()->loadEnvironmentFrom('.env.test');
parent::bootstrap();
}
So the essential part was to move the parent::bootstrap() call below the loadEnvironmentFrom() call.

Instead of doing any code change, you can use export command create a file called .env.test, you want to sue this as .env file use terminal
APP_ENV=local
php artisan config:cache
php artisan key:generate
This below edit is to explain how .env file is getting set
In Illuminate\Foundation\Application class has method loadEnvironmentFrom which is taking the file as parameter and setting it,
you can use bootstrap/app.php after you are getting $app
$app = new Illuminate\Foundation\Application(
$_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
);
here you will be having instance of Illuminate\Foundation\Application
you can just call the loadEnvironmentFrom function like
$app->loadEnvironmentFrom('.env.local');
May be it is better to use Kernel.php instead of this, I do not think either of bootstrap/app.php or kernel.php will get overridden with composer update, so make more calculation while using it. I have added this, so that it will help you understand the stuffs.

You can load a different environment file using APP_ENV
For example if APP_ENV=test then .env.test can be loaded.
More info: https://github.com/laravel/framework/blob/6.x/src/Illuminate/Foundation/Bootstrap/LoadEnvironmentVariables.php#L41

Related

Where should I keep my constants in lumen?

I am writing a web service using Lumen and need to store some constants, specifically error values, but also other configuration parameters. Where would it be most appropriate to put these?
Here is how I did it.
I made a const.php file within bootstrap folder where I have defined some error codes.
<?php
define('VALIDATION_EXCEPTION',422);
I included the const.php file in app.php using require_once.
<?php
require_once __DIR__.'./const.php';
Now I can call VALIDATION_EXCEPTION from anywhere. for instance.
$router->get('/test',function(){
return VALIDATION_EXCEPTION;
});
That's it!
Create a file constants.php inside config/ and put your settings in an array:
<?php
return [
'CONTACT_NAME' => 'Admin'
];
Then in your controllers you can get the value by using Config Facade:
echo Config::get('constants.CONTACT_NAME');
This solution was from this link
.env is intended for per-environment configuration and sensitive credentials.
You can maintain a config with this type of data. There is no default config for Lumen like there is for Laravel, so you need to add the required config directory, and tell Lumen to use it:
$ mkdir config
$ touch config/app.php
In the app.php file, you can return an array with the config:
// config/app.php
<?php
return [
'order_by' => 'whatever'
// and so on
];
Then tell Lumen to load the config from app.php inside bootstrap/app.php, by adding (after $app has been initialised):
$app->configure('app');
Finally, you can use the config() helper method to get the configuration:
config('app.order_by') // whatever
1.Create New Directory Helpers under App Directory.
2.Create New php file ErrorCodes.php under Helpers directory
3.Put your constants in that file
<?php define('VALIDATION_ERROR', 'E001'); define('EXCEPTION', 'E002'); define('CUSTOM','E003'); ?>
4.Add this ErrorCodes file under autoload section of composer.json
"files" : [
"app/Helpers/ErrorCodes.php"
]
5.Run composer autoload command in your artisan terminal
composer dumpautoload
And you are all set to use your constants anywhere in your lumen App.
Seems like you are talking about two different things here. For configuration values the only correct location is the .env file (as already mentioned in the comments).
https://lumen.laravel.com/docs/5.5/configuration#environment-configuration
This is where you put all environmental specific configuration values (e.g. API keys, debug mode, etc. etc.). If you have a strong wish for it you can put the env-variables into constants during the bootstrap process e.g.:
define('APP_DEBUG',env('APP_DEBUG', true));
For defining simple constants there should be multiple possibiilties.
You could do this either during the bootstrap process or define a class (e.g. a model):
class Error
{
const FATAL = 1;
const WARNING = 2;
}
use Error;
....
Error::FATAL;
...

Laravel File equivalent in Lumen

I can access the list of files in a directory in Laravel using this:
use File;
....
$files = File::files($path);
However, I get this error in lumen:
Class 'File' not found
Any idea how I can access list of files in a folder in lumen.
File is only avaiable in Laravel by default. Although you can still used it on Lumen Framework by doing the following.
Enable the facade in boostrap/app.php by uncommenting the following code.
$app->withFacades();
After that, you will be able to access the File class in any of your controller by adding it as:
use Illuminate\Http\File;
or you can use the Facade Class.
use Illuminate\Support\Facades\File;
Please do a composer dump-autoload to update autoload.

Laravel 5 load env file based on .env.master?

I'm planing to do something like, specifying what env file to load during application bootstrap time by creating a variable in .env.master such as ENV_VER = dev.env
This is because I have several branches such as development, release-1.1 and etc. Thus by loading the env file based on the name specified in a master env file, developers no longer have to copy and paste new variables into their local copy of .env and instead, just specify what version of env file to load in the master env file. By the way, I have several env files such as dev.env, 1.6.env etc.
Is it possible?
Definitely, me myself I tend to "bend" a framework little bit everytime and there's always a way, not always the best solution though. I'm not giving a whole implementation here, just pointing you in some direction, that might work for you.
You can extend Laravel's base application class Illuminate\Foundation\Application, which contains $environmentFile variable storing environment file loaded during appplication bootstrap or possibly override function loadEnvironmentFrom($file) or environmentFile(). The whole logic is up to you.
So basically all you need to do in order to be able to "play" with .env loading is...
Create a new application class extending Laravel's one:
namespace MyNamespace;
...
use Illuminate\Foundation\Application as App;
/**
* I'm doing alots of magic with .env in this class
*/
class Application extends App
{
...
/**
* The environment file to load during bootstrapping.
*
* #var string
*/
protected $environmentFile = '.env.main';
...
}
And now, because we have a new bootstraping class, we have to tell Laravel we want to use it. So you'll have to modify bootstrap/app.php file in point where a new instance is being created:
...
$app = new MyNamespace\Application(
realpath(__DIR__.'/../')
);
...
Note: For inspiration I recommend you to really look at Illuminate\Foundation\Application class.
In laravel 5.5+ you can, maybe earlier, you can set your server have a APP_ENV environment or server variable that the process can see (apache, command line...)
this will allow you to use a suffix or file extension on your .env files for auto loading those files...
APP_ENV=dev :: .env.dev
APP_ENV=production :: .env.production
much easier than other solutions.
If you want to look into how this is done, it starts with
1. application bootstrappers
protected $bootstrappers = [
\Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,
\Illuminate\Foundation\Bootstrap\LoadConfiguration::class,
\Illuminate\Foundation\Bootstrap\HandleExceptions::class,
\Illuminate\Foundation\Bootstrap\RegisterFacades::class,
\Illuminate\Foundation\Bootstrap\SetRequestForConsole::class,
\Illuminate\Foundation\Bootstrap\RegisterProviders::class,
\Illuminate\Foundation\Bootstrap\BootProviders::class,
];
2. LoadEnvironmentVariables
first the environment is determined…
\Illuminate\Foundation\Bootstrap\LoadConfiguration::bootstrap calls
\Illuminate\Foundation\Application::detectEnvironment
If
--env={env} for CLI then it will use that for APP_ENV.
Else
\Illuminate\Foundation\EnvironmentDetector::detectWebEnvironment
is called which uses a callback…
function () use ($config) {
return $config->get('app.env', 'production');
}
where app.env defaults to env('APP_ENV', 'production')
3 LoadConfiguration
\Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::bootstrap calls...
\Illuminate\Foundation\Application::afterLoadingEnvironment
which eventually gets to
\Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::checkForSpecificEnvironmentFile
which sets the environment file based on app env IF the file exists.
$this->setEnvironmentFilePath(
$app, $app->environmentFile().'.'.env('APP_ENV')
);
allowing it to load the .env.{APP_ENV} instead of .env
NOTE: Testing.
when running php unit tests. the Illuminate/Foundation will try to load the .env.testing file for configurations!

PHP Notice: Constant FLD_EMAIL already defined laravel

I have created a file called db-constant.php in conifg directory in laravel , this file contains my constants,then i added this line require_once 'db-constants.php'; in app.php ,the problem is where i type php artisan cache:clear or any command this message will appear
PHP Notice: Constant FLD_EMAIL already defined in /var/www/html/test/config/db-constants.php on line 1
how can i fix this ?
If you use Laravel, you don't have to use require_once or it's counterparts. composer's autoloading is used for everything, and configuration files are loaded automatically. What you have to do is read the docs about configuration, place the file in config/ directory and return an array with configuration values.
Now, what it seems (to me at) is that for some odd reason you want to use constants instead of Laravel's mechanism for accessing configuration values. In that case, you:
1.) DON'T place anything in config/ directory
2.) DON'T manually require_once anything
3.) DO use Composer's autoloading capabilities
How to load a file with constants in Laravel
1.) create app/MyConstants directory.
2.) create your file, let's call it constants.php. Path is:
app/MyConstants/constants.php
3.) Add your define code
4.) Open composer.json
5.) Find "autoload"
6.) Look for "files" under "autoload". If it doesn't exist, create it.
7.) Add the list of files you want to include automatically
Your "autoload" in composer.json should look like this:
"autoload": {
"files": ["app/MyConstants/constants.php"]
}
In terminal, type composer du or composer dump-autoload. It will re-create autoloader and automatically include the file with your constants.
Remove bootstrap/cache so you can use artisan again.
Now you can:
1.) Have a place where you can define constants
2.) Avoid manually requiring files
Personally, I don't see a reason for this, but then again - I'm just a human, I've no clue about anything in the grand scheme :)
You need to read this docs first https://laravel.com/docs/5.4/configuration. As well as the rest of the documentation for Laravel. How to use config files:
Create your own file db-constant.php in config directory.
Fill it as you need. For example
return [
'FLD_EMAIL' => 'your-field-here',
];
Use it wherever you need
$email = config('db-constant.FLD_EMAIL');
It's all.

Laravel phpunit not getting right url

I've changed the app.url config value to the correct url (http://testing.local) for testing locally, however when I run my phpunit tests and try to call(), it is trying to query http://localhost instead of the value of app.url. What do I need to do to get phpunit to call the right path?
I know that it is not actually calling the url, just processing it as if it was, but I can't seem to get it to actually work. Could it have something to do with testing.local directly linking to /public instead of /?
If you want to statically specify a root URL for your tests, add this to phpunit.xml:
<env name="APP_URL" value="http://testing.local"/>
Instead, if you want to change the URL dinamically during your tests, from Laravel 5.4 the $baseUrl method doesn't work anymore.
Also, trying to set the url dinamically with \Config:set('app.url', 'http://testing.local') doesn't work either, as it seems that Laravel caches the root url
You can set dynamically a custom URL with:
\URL::forceRootUrl('http://testing.local');
To change testing url of PHPUnit:
Go to /tests/TestCase.php in your Laravel project.
Change next line to url you need:
// The base URL to use while testing the application.
protected $baseUrl = 'http://newurl.com';
Done.
As stated above, you can use Config::get('app.url') anywhere in your laravel code, including your unit-test.
Note: it is recommended to set this value in your .env file so that it can be set specifically for each environment.
When working with config and .env variables, remember to clear the cache for these with the following commands:
php artisan cache:clear
php artisan config:cache
Laravel has a few functions to get url: (1) url()->current() (2) request()->url()
Both of them are using the same source.
In case of phpunit, tests are setting data there from the config
config('app.url')
and config is getting data from .env record APP_URL.
So you have a few options
1)
to set APP_URL in .env file or in phpunit.xml file - in both cases, a the value is only used in unit tests.
BUT you would have only one URL for all your unit tests.
2)
set APP_URL in runtime
but, you need to do it before function setUp() in Tests\TestCase
public function setUp(): void
{
$_ENV['APP_URL'] = 'example.com';
parent::setUp();
}
Because all the initialisation is hidden in setUp function you CANNOT use
config()->set('app.url',.... Before parent::setUp(); would be too early, and after it - would be too late.
BUT you would have only one URL per unit test file.
3)
request()->headers->set('HOST', 'example.com');
you can set it anywhere after setUp() function and it will overwrite .env and config()
No 'BUTs'.
I think the best way is to set the test app url in phpunit.xml configuration file:
<env name="APP_URL" value="some-url.test"/>
To the best of my understanding, Laravel is supposed to use the 'testing' environment variables when you run PHPUnit. However, I am having the same issue that you are. To get it to work I manually set the app url.
$test_url = Config::get('app.url');
Hope this helps anyone who comes across the same issue.

Categories