Symfony 4 - .env Variables Not Available - php

I'm running in to a brick wall here. Everything so far with Symfony 4 has been sunshine and daisies but now I can't seem to add any environment variables to my project.
In my project root there is the default .env file populated with the usual APP_ENV, APP_SECRET and DATABASE_URL; that's all great. However, adding any custom variable there doesn't seem to actually do anything! If I add in ANOTHER_VAR=hello_world, for example, and then run bin/console debug:container --env-vars, it only dumps the APP_SECRET and DATABASE_URL variables. If I run bin/console about, however, it shows me all of the variables inside .env.
I thought it might be a cached variable issue but if I change the value of APP_SECRET and run the console command again, it dumps the changed value but still not my custom variables.
I suspect that the env vars are not available to the container by default but that doesn't seem right to me (plus it seems somewhat contradictory to what the Symfony docs themselves say).
What do I need to do to register these variables so I can access them inside a Controller, for example?

As is typical of me, I stumble across the answer within half an hour of getting frustrated and asking for help.
Contrary to how the documentation reads, simply adding a variable to the .env file does not make it available inside the Container (and so not listed when you run bin/console debug:container --env-vars nor available inside a Controller using $this->getParameter('env(VAR)')). And thinking about it now, this kinda makes sense because you wouldn't want all of your protected variables available to everything that runs from the Container.
In order to access an env var you need to parameterise it first and this way you can limit access to it as well.
Any env vars that you want available to all of your services you can set within the config/services.yaml file like so (assuming autowiring is enabled):
parameters:
variable_a: '%env(VAR_A)%'
If you would prefer to restrict the env var to just a few services, then you can inject it in to your service as an argument within config/services.yaml like so:
services:
App\Service\Foo:
arguments:
$bar: '%env(BAZ)%'
With the parameter set up like the above, I can now access that env var inside my Controller with $this->getParameter('variable_a'). Running bin/console debug:container --env-vars also outputs it.
It's a bit of a pain since I assumed that simply calling $this->getParameter('env(BAZ)') would do the trick but I suppose it makes sense (there is actually no parameter called env(BAZ)).
Hopefully this helps someone else struggling to wrap their head around this.

Related

realpath() doesnt show realpath GitLab ci runner

the code is stored in /var/www/abc -- "CodePath"
when running gitlab-ci (runner), the code is called via /home/gitlab-runner/builds/4v8bC1n9/0/_gitlabgroup_/_gitprojectname_/abc -- "RealPath"
I'm using a local runner and a shell execution.
when I use the realpath() function in my php code, it still shows the "CodePath" when using gitlab ci runner, instead of "RealPath".
How can I get the "RealPath" integrated in my code, or reconfig GitLab to use the "CodePath" instead?
The runner cli options are documented here: https://docs.gitlab.com/runner/executors/shell.html#overview
The path where the job is run and your sources are cloned into is available in the environment variable:
CI_PROJECT_DIR
The full path where the repository is cloned and where the job is run. If the GitLab Runner builds_dir parameter is set, this variable is set relative to the value of builds_dir. For more information, see Advanced configuration for GitLab Runner.
You did no state how you use realpath(path)...
Whilst a path must be supplied, the value can be an empty string. In this case, the value is interpreted as the current directory.
So maybe you hardcode chdir('/var/www/abc'); somewhere?
When you do chdir(getenv('CI_PROJECT_DIR')); before you call realpath() - it should use the CI directory. Assuming you use realpath without a parameter.
Also: maybe you can make some changes and use one of the the built in constants for the current directory: https://www.php.net/manual/en/language.constants.predefined.php
Thanks to madflow's mentioning of the variable I managed to figure out the following:
runners specific configuration files exist and can be configured as described here
I needed to do these things:
specify enable the [runners.custom_build_dir] section in the config.toml
[[runners]]
builds_dir = "/var/www/abc"
[runners.custom_build_dir]
enabled = true
(boolean not in quotes)
specify a variable in my yml
variables:
GIT_CLONE_PATH: $CI_BUILDS_DIR/
on os level there was some privilege setting for the dir required, where I went for quick and dirty 777 on my local machine

Symfony 4, .env files and production

.env files are very handy with docker, kubernetes, etc
But what if I have simple nginx server without any orchestration and a pack of cron workers and a pack of daemons(systemd/supervisord/etc)?
I can write these env variables to nginx server section, but I have to set up hundreds of env variables to each cron worker or daemon.
I found a quick solution: using symfony/dotenv component in production.
But it seems to me dirty. Who can suggest better solution?
First of all, not all variables need to be specified using environment variables. Keep variables that do not differ per system in a separate yaml file.
When you have just one environment per server you can specify the environment variables globally in /etc/environment. (Might be different depending on your Linux flavour)
Personally I find that using DotEnv poses more difficulties than solutions when you run multiple environments on the same server. Specifying the variables in a global configuration like /etc/environment doesn't work in that case.
Specifying the environment variables in nginx isn't a solution either since, as you mentioned, they won't be picked up by cron, supervisor, the console, etc. For me, this was the reason to completely remove DotEnv and work with the good old parameters.yaml file again. Nothing will stop you from doing that.
Another solution however is to keep using DotEnv in your development environment and to include a separate parameters.yaml in production. You can then define the environment variables as follows:
parameters:
env(APP_ENV): prod
env(APP_SECRET): 3d05afda019ed4e3faaf936e3ce393ba
...
A way to include this file is to put the following in your services.yaml file:
imports:
- { resource: parameters.yaml, ignore_errors: true }
This way, the import will be ignored when no parameters.yaml file exists. Another solution is to add a line to configureContainer() in your Kernel class:
$loader->load($confDir.'/parameters'.self::CONFIG_EXTS, 'glob');
if you want to centralize your environment variables for cli and fpm you can define them once in your system. And then reference them all in your php-fpm.conf:
....
[www]
env[APP_VAR1] = $APP_VAR1
env[APP_VAR2] = $APP_VAR2
...
In that way you can avoid using DotEnv in production which is encouraged by best practices.
Hope this helps.

Is DotEnv module in Laravel framework going to overwrite existing ENV var in my system?

I'd like to be sure if given a defined ENV variable on my system:
e.g.
$export TEST_VAR=hello
Then installing my laravel application having in .env file
TEST_VAR=goodbye
What would be then the expected behaviour if I try to print
<?php echo $_ENV['TEST_VAR']
I performed some tests and it seems like the .env file definition is not going to override the system defined ENV var. But I'm not sure if it's going to be always like that.
I see on :
https://github.com/vlucas/phpdotenv
on Immutability paragraph that:
"By default, Dotenv will NOT overwrite existing environment variables that are already set in the environment.
If you want Dotenv to overwrite existing environment variables, use overload instead of load"
Didn't find so far, where exactly Laravel framework invokes DOtEnv package in order to load/overload env var....
In short, "No, It doesn't overload/overwrite your existing ENV variables by default". By default, the immutable is set to false.
But, if you want to overwrite your existing ENV variables, here is the possible workaround.

Symfony2 Where to save Environment Variables

I've seen plenty of tutorials on configuring an Apache2 virtual host with environment variables and using those variables as a parameter within the site. However, the issue I'm having is when I run php app/console cache:clear or reload my data fixtures, I get the following error:
You have requested a non-existent parameter ...
If I first export the parameter prior to reloading my fixtures, the error goes away as the environment variable is set. Which makes sense as that function isn't using Apache to execute and needs the environment variable set. But this doesn't fix my issue when I clear my cache manually.
So my question is, where do I actually want to save those environment variables?
I would like to store site specific information that's dependent on which virtual host is used.
I could store them in my ~/.profile bash file, but that doesn't really make sense and all of the documentation I've read simply says store with the virtual host (for Apache). But none of those docs mention executing scripts outside of a web browser accessing the site such as reloading fixtures, running migrations, or clearing cache, which is only an issue when I deploy my source.
Thanks a lot for any help.
You can put application variables in app/config/config.yml. You can put there:
parameters:
your.parameter.1: value1
your.parameter.2: value2
If you use any kind of version control system you can exclude those variables to separate file and ignore this file in version control repository. You also should include this file in config.yml. For example if you put the above variables in app/config/example.yml then you should add in app/config/config.yml:
imports:
- { resource: example.yml }
EDIT
You can always put parameters as follows:
parameters:
domain1:
param1: value1
param2: value2
domain2:
param1: value1
param2: value2
domain3:
param1: value1
param2: value2
and then read these variables in places where you want to use them according to the current domain or you can also set service that sets common variables according to current domain. For command line you can use default values.
So just because this is situation is a pet peeve of mine I urge you not to put environment specific information in the config file. So what is needed are two files that must stay in sync. One file will be for command line and one for Apache (or HTTP server of your choice) environment variables
CL: /var/www/applications/coolapp/coolapp.sh
Apache: /var/www/applications/coolapp/coolapp.apache.conf
Usage
For the command line, any time I run a Symfony command I source my environment (this example is for bash shell)
$ . ./coolapp.sh
$ app/console cache:clear
In the Apache config for the site I add an include such as
/etc/httpd/conf.d/coolapp.local.conf
<VirtualHost coolapp.local:443>
...
Include /var/www/applications/coolapp/coolapp.apache.conf
...
</VirtualHost>
What is in these files?
coolapp.sh would contain something like
export SYMFONY__APP_USER = foo
export SYMFONY__APP_PASS = foobar01
and coolapp.conf would have
SetEnv SYMFONY__APP_USER fop
SetEnv SYMFONY__APP_PASS foobar01
So each one of my environments (production, qa, stage, test, dev, localdev) would have these two files. And they can be changed whenever without going into the code.
Within Symfony you would access these variable like
%app_user%
%app_pass%

Laravel Config::get() from particular environment (not current)

I'm trying to get a config value from another (not current) environment. I would like to get it calling something like:
$value = Config::get('app.locale', 'default', 'my_environment');
Obviuosly Config::get() takes only 2 params by default, but are there any other functions to get config in neat way, to get what I want? I can't find anything in the API.
An answer to this question How to get config data in laravel in a subfolder happens to be a solution for me as well.
Rather than passing some other parameters to Config::get(), you can pass a path to file in the first parameter. So calls like:
Config::get('local/app.locale');
Config::get('dev/app.locale');
will get config from local, dev, etc. environments, no matter what's your current working environment.
Laravel environments, are for seperating configurations from develop machine and production machine.
If you want on all env. the same config you can use the global config files in app/config/* for individual configuration per env. you use the app/config/<YOUR ENVIRONMENT>.
so to get your app.locale in all environment the same use the app/config/app.php file

Categories