7

I am using Laravel 6.x for client's project wherein I have built an API in the Artisan Command for syncing data.

Now client wants the configuration to be discreet, out of main source code and without any fallback values as possible. That means I must define the configs in the .env file and use the env() method without any fallback default values.

This must be possible inside Laravel Artisan command class files, but it is not working as intended when I use the env method in the code as below:

[siteroot]\.env:

APP_ENV=local

[siteroot]\app\Console\Commands\SyncSomeData.php:

use Illuminate\Console\Command;

class SyncSomeData extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'sync:some-data';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        exit(env('APP_ENV','staging1'));
    }
}

This always prints staging1 in console and if I use this instead of the given env method, then it prints nothing:

exit(env('APP_ENV'));

As I know and can trust that Laravel is most secure, there must be way to have env method work without fallback value in the command file, can anyone help fulfilling this ?

Vicky Dev
  • 1,893
  • 2
  • 27
  • 62
  • 1
    Can you try config('app.env'), please? And run php artisan config:cache first? I believe in newer versions of laravel, this is the recommended approach, I don't think you can access env() like you used to. – Kurt Friars Jul 09 '20 at 17:29
  • Wow, that did actually work, even though didn't expected it. Can you please format this in an answer with some extra info and references to look up and the reason why we need to `config` instead of `env` ? Because the other SO links aren't good enough to guide well on this specific topic... Appreciate it... – Vicky Dev Jul 09 '20 at 17:32
  • My comment isn't fully correct, but I suspected it was the issue. I will do my best in the answer below. – Kurt Friars Jul 09 '20 at 17:36
  • Also what about if I have defined my custom `env` variables like `API_SOAP_URL`, how do I print those. I just tried with `config('api.soap.url')` but that printed blank... So please cover this into your answer as well, thanks.. I am now clearing the cache everytime I change the `.env` file, so that's not the issue mostly... – Vicky Dev Jul 09 '20 at 17:37
  • Let me know if my answer is missing anything. Your last comment is likely from not running php artisan config:cache after adding or modifying the value. – Kurt Friars Jul 09 '20 at 17:50
  • Ok let me make couple things clear, after I read your answer, which in my opinion is very informative, I closely observed the `config:cache` scenario and it's syncing from `.env` file. You know what, it doesn't at all caches any custom declared config variables like `API_SOAP_URL`. I saw the cache file and it only list out the `APP.` config variables, so the ultimate question, how do I mandate/force Laravel to cache whatever custom variable/value I provide in `.env` along with running the `php artisan config:cache` and also if needed `php artisan config:clear` command ? – Vicky Dev Jul 09 '20 at 17:58
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/217555/discussion-between-vicky-dev-and-kurt-friars). – Vicky Dev Jul 09 '20 at 17:59

1 Answers1

10

There are a couple parts to this answer.

  1. Caching Config

The issue in this question is only present if you have cached your config on your local environment. If you have ever run php artisan config:cache or php artisan optimize, you have cached your config.

As a result, laravel will no longer read your .env file and load all values for config and .env from cache.

It is best practice, to not use env() throughout your application but create config files for these values. This will speed up your application in production. If you want to take advantage of config cache, you CAN NOT use env() anywhere but in your config files.

In your local environment, the documentation recommends you should not be caching your configuration, since it will be updated frequently. I think this is good advice with one caveat: env(). If you aren't caching your config on local, but are in production, you won't come across errors like the one that was the impetus for this post in local. If you have a ci pipeline and good testing practices than this hurdle is overcome.

If you stick with cache config in local, every time you update your config files or your .env file you will need to run php artisan config:cache.

  1. Disabling config cache

By running php artisan config:clear or removing /bootstrap/cache/config.php laravel will no longer to attempt to read config from cache, and .env will work outside of config files. If you do this, as I stated in (1) make sure there is a part of your pipeline that will catch these errors, if you are caching config in production.

After more discussion with OP, I will make one more thing clear:

Cache config does not automatically just cache your .env keys so you can access them like config('SOME_CUSTOM_DOT_ENV_KEY'). When using cache config, if you need to access environment variables inside of your application, you must reference them in a config file.

Again, once config cache is enabled,.env becomes useless, but it is used to build the cache.

So if you in .env say:

GOOGLE_API_TOKEN=xxxx

You would maybe create a config file like:

google.php

return [
    'api_token' => env('GOOGLE_API_TOKEN', 'some-default-value'),
];

And in your application, you will only reference config('google.api_token') and never env('GOOGLE_API_TOKEN').

Kurt Friars
  • 3,625
  • 2
  • 16
  • 29