Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

vars_prompt & Environment Variables

Keep on Learning!

If you liked what you've learned so far, dive in!
Subscribe to get access to this tutorial plus
video, code and script downloads.

Start your All-Access Pass
Buy just this tutorial for $10.00

We missed a deploy step! We're not clearing Symfony's cache. That sounds like a job for a new task! Call it "Clear Cache". It's easy: we just need to run a command: {{ symfony_console_path }} cache:clear --env=prod:

---
- hosts: vb
... lines 3 - 10
tasks:
... lines 12 - 188
- name: Clear cache
command: '{{ symfony_console_path }} cache:clear --env=prod'
... lines 191 - 206

Easy! Except... that --env=prod part is interesting. Sometimes I might want to deploy our app in the prod environment - like if we're deploying to production. But other times, like if we're deploying to some test machine, I might want to deploy our app in the dev environment.

What I'm saying is: I want that environment to be configurable. And actually, this is important in two places: here, and when installing the Composer dependencies.

Symfony Composer Deps in the prod Environment

Google for "Symfony deploy" to find a page on Symfony.com. Scroll down to a section about installing and updating your vendors. Ah, so it recommends that when you deploy, you use:

composer install --no-dev

That's actually what the composer module tried to do by default. But then we - via a no_dev option - told it to stop that nonsense!

---
- hosts: vb
... lines 3 - 10
tasks:
... lines 12 - 149
- name: Install Composer's dependencies
composer:
... line 152
no_dev: no
... lines 154 - 206

We had to do that because some of the Composer post-install commands in a Symfony app require the packages in the require-dev section.

In reality, this --no-dev flag is not a big deal. But, we can use it... as long as we set an environment variable: SYMFONY_ENV=prod. Yep, those problematic post-install commands are setup to look for this environment variable, and not to do certain things rely on the require-dev dependencies.

So this is our mission: make the environment configurable, use it in the "Clear Cache" task and set a new environment variable.

Prompting for Input?

How? Start at the top: add a new vars_prompt key with name set to symfony_env:

---
- hosts: vb
... lines 3 - 10
vars_prompt:
- name: symfony_env
... lines 13 - 221

Then, prompt: Enter the environment for your Symfony app (prod|dev|test):

---
- hosts: vb
... lines 3 - 10
vars_prompt:
- name: symfony_env
prompt: "Enter the environment for your Symfony app (prod|dev|test)"
... lines 14 - 221

As you're probably guessing, Ansible will now ask us what environment we want to use. Set a default value to prod and private: no - you can set that to yes to obscure passwords as you type them:

---
- hosts: vb
... lines 3 - 10
vars_prompt:
- name: symfony_env
prompt: "Enter the environment for your Symfony app (prod|dev|test)"
default: prod
private: no
... lines 16 - 221

Cool!

Setting an Environment Variable

Next question: how can we use this variable to set an environment variable? How about... an environment key! Yep, setting environment variables is a native task for Ansible. Set SYMFONY_ENV to {{ symfony_env|lower }}:

---
- hosts: vb
... lines 3 - 10
vars_prompt:
- name: symfony_env
... lines 13 - 16
environment:
SYMFONY_ENV: "{{ symfony_env|lower }}"
... lines 19 - 221

This uses the variable we just set... but pipes it through a lower filter... just in case we get crazy and use upper-case letters.

To see what this all looks like, at the top, let's debug some variables. First, debug one called ansible_env:

---
- hosts: vb
... lines 3 - 19
tasks:
- debug:
var: ansible_env
... lines 23 - 221

This is a built-in variable that has a lot of info about the "host" environment - meaning, the machine (or machines) that you're running Ansible against. It should also contain our environment variable.

Let's also debug the symfony_env variable that we set above:

---
- hosts: vb
... lines 3 - 19
tasks:
- debug:
var: ansible_env
- debug:
var: symfony_env
... lines 26 - 221

Oh, and down on the "Clear Cache" task, I forgot to add the tag for deploy:

---
- hosts: vb
... lines 3 - 19
tasks:
... lines 21 - 203
- name: Clear cache
command: '{{ symfony_console_path }} cache:clear --env=prod'
tags:
- deploy
... lines 208 - 221

Change over to your terminal and run the playbook - but take off the -t option so that everything runs:

ansible-playbook ansible/playbook.yml -i ansible/hosts.ini

Yes! Right at the start, it asks us for the environment. I'll leave it blank to use prod. Then, hit ctrl+c to quit: we can already see the variables!

First, it printed ansible_env... which has some pretty cool stuff! It has a HOME key for the home directory, PWD for the current directory and other goodies. AND, it has SYMFONY_ENV set to prod. Not surprisingly, the symfony_env variable also prints prod.

Try this again.. but be tricky... with an uppercase PROD:

ansible-playbook ansible/playbook.yml -i ansible/hosts.ini

Yep! The environment variable was lowercased, but not the symfony_env variable. That's no surprise... but if we want to guard against this, it will be a problem in a minute when we try to use this in more places... like down on my "Clear Cache" task:

---
- hosts: vb
... lines 3 - 19
tasks:
... lines 21 - 203
- name: Clear cache
command: '{{ symfony_console_path }} cache:clear --env=prod'
... lines 206 - 221

We could keep using the lower filter. But, there's a cooler way: a "pre task".

Leave a comment!

14
Login or Register to join the conversation

Hi!

I've a problem with environment the SYMFONY_ENV var. In my case I've called app_env instance of symfony_env. But when composer install --no-dev there is a error

TASK [Install Composer's dependencies] ***********************
\n An error occurred when executing the \"'cache:clear --no-warmup'\" command: \n PHP Fatal error: Uncaught ReflectionException: Class Doctrine\\Common\\DataFixtures\\AbstractFixture not found in /var/www/project/src/AppBundle/DataFixtures/ORM/LoadUserData.php:10

My playbook:


vars_prompt:
- name: app_env
prompt: "Enter the environment (prod|dev)"
default: prod
private: no

environment:
SYMFONY_ENV: "{{ app_env|lower }}"

pre_tasks:
- name: Convert entered App environment to lowercase
set_fact:
app_env: "{{ app_env|lower }}"
tags:
- always


- name: Install Composer's dependencies
composer:
working_dir: "{{ symfony_root_dir }}"
no_dev: "{{ 'yes' if ('prod' == app_env) else 'no' }}"
//I have also tried no_dev: "{{ 'True' if ('prod' == app_env) else 'False' }}"
tags:
- deploy
when: code_changed


My project use doctrine:fixtures:load. As the docs say, I register the bundle in:


if (in_array($this->getEnvironment(), ['dev', 'test'], true)) {
//default bundles
$bundles[] = new Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle();

if ('dev' === $this->getEnvironment()) {
//default bundles
}
}

Do you know any idea that it can be ...? 😞
thanks!

Reply

Hey Juan,

Hm, at the first sight, it's correct. Let's debug a bit more. Could you SSH to your server and run "composer install" manually? Do you have the same error? Also, you could try to always install dev deps with simply "no_dev: no". Does it fix the problem? Btw, could you try it manually locally? Are you sure you don't have the same problem and fixtures could be loaded successfully locally?

Cheers!

Reply

HeyVictor

En aws server with ssh:
When I try composer install (dev) is all ok.


[OK] All assets were successfully installed.

But when I try: composer install --no-dev


//- other bundles ok
- Installing willdurand/hateoas-bundle (1.3.0): Loading from cache
Generating autoload files
> Incenteev\ParameterHandler\ScriptHandler::buildParameters
Updating the "app/config/parameters.yml" file
> Sensio\Bundle\DistributionBundle\Composer\ScriptHandler::buildBootstrap
> Sensio\Bundle\DistributionBundle\Composer\ScriptHandler::clearCache
PHP Fatal error: Uncaught Symfony\Component\Debug\Exception\ClassNotFoundException: Attempted to load class "DoctrineFixturesBundle" from namespace "Doctrine\Bundle\FixturesBundle".
Did you forget a "use" statement for another namespace? in /var/www/project/app/AppKernel.php:30
Stack trace:
#0 /var/www/project/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Kernel.php(450): AppKernel->registerBundles()
#1 /var/www/project/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Kernel.php(116): Symfony\Component\HttpKernel\Kernel->initializeBundles()
#2 /var/www/project/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Console/Application.php(137): Symfony\Component\HttpKernel\Kernel->boot()
#3 /var/www/project/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Console/Application.php(124): Symfony\Bundle\FrameworkBundle\Console\Application->registerCommands()
#4 /var/www/project/vendor/symfony/symfony/src/Symfony/Component/Console/Application.php(90): Symfony\Bundle\FrameworkBundle\Console\Applica in /var/www/project/app/AppKernel.php on line 30
Script Sensio\Bundle\DistributionBundle\Composer\ScriptHandler::clearCache handling the symfony-scripts event terminated with an exception


[RuntimeException]
An error occurred when executing the "'cache:clear --no-warmup'" command:
PHP Fatal error: Uncaught Symfony\Component\Debug\Exception\ClassNotFoundException: Attempted to load class "DoctrineFixturesBundle" from namespace "Doctrine\Bundle\FixturesBundle".
Did you forget a "use" statement for another namespace? in /var/www/project/app/AppKernel.php:30
Stack trace:
#0 /var/www/project/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Kernel.php(450): AppKernel->registerBundles()
#1 /var/www/project/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Kernel.php(116): Symfony\Component\HttpKernel\Kernel->initializeBundles()
#2 /var/www/project/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Console/Application.php(137): Symfony\Component\HttpKernel\Kernel->boot()
#3 /var/www/project/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Console/Application.php(124): Symfony\Bundle\FrameworkBundle\Console\Application->registerCommands()
#4 /var/www/project/vendor/symfony/symfony/src/Symfony/Component/Console/Application.php(90): Symfony\Bundle\FrameworkBundle\Console\Applica in /var/www/project/app/AppKernel.php on line 30


install [--prefer-source] [--prefer-dist] [--dry-run] [--dev] [--no-dev] [--no-custom-installers] [--no-autoloader] [--no-scripts] [--no-progress] [--no-suggest] [-v|vv|vvv|--verbose] [-o|--optimize-autoloader] [-a|--classmap-authoritative] [--apcu-autoloader] [--ignore-platform-reqs] [--] [<packages>]...

Thanks!

Reply

More info:
In my LoadUser.php

When I installed composer with --no-dev the namespaces next are wrong, because not exits Doctrine\Common\DataFixtures.

use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;

Reply

Yes, this sounds correct if you register DoctrineFixturesBundle in AppKernel only for dev/test environments.

Cheers!

Reply

victor First I want to thank you for all your help, I have solved the error

The installation and configuration were right, but in DoctrineFixtures classes I was using a OrderedFixtureInterface old, at the current version is different....


//https://symfony.com/doc/master/bundles/DoctrineFixturesBundle/index.html
public function getDependencies()
{
return array(
UserFixtures::class,
);
}

I'm really grateful to you

I will edit the first comment to report that the error is to another different problem than this lesson . Or if you wish, I can delete it so as not to confuse.

Thanks!

Reply

Hey Juan,

Don't worry too much about your previous comments, we'll keep them ;)

Hm, it's a bit weird that fixtures broke your prod environment even when you do not use fixtures in prod at all. But I really glad you got it working!

Cheers!

Reply

Hey Juan,

Hm, are you sure you include DoctrineFixturesBundle namespace in AppKernel for dev/test environment only? And what about your local machine? Does it work locally when you execute "composer install --no-dev"?

UPD: I can suggest you to try to upgrade Composer dependencies with "composer update". It will pull latest versions and regenerate composer.lock. Then, try to execute "composer install --no-dev" again.

Cheers!

Reply

Also, let's see SYMFONY_ENV works well, try to follow a few steps:
- SSH to AWS server
- cd /to/project/dir
- try again to install deps without importing SYMFONY_ENV, just execute: "composer install --no-dev"
- On this step you should see the error you reported, right?
- Now let's export prod environment var by executing: "export SYMFONY_ENV=prod"
- And in the same terminal tab you exported SYMFONY_ENV, execute again: "composer install --no-dev"

Do you still have that error? Or, does it work now?

Cheers!

Reply

HI victor ,
In local:
- SYMFONY_ENV:
In local I have defined SYMFONY_ENV=prod


#~/.zshrc
export SYMFONY_ENV="prod"


When I run in my terminal$ echo $SYMFONY_ENV return prod

- composer install --no-dev [local] ..... BUUM!!!!

...
PHP Fatal error: Uncaught ReflectionException: Class Doctrine\Common\DataFixtures\AbstractFixture not found in /Users/juanluisgarciaborrego/Sites/project/src/AppBundle/DataFixtures/ORM/LoadUserData.php:10
...

Fatal error: Uncaught ReflectionException: Class Doctrine\Common\DataFixtures\AbstractFixture not found in /Users/juanluisgarciaborrego/Sites/project/vendor/symfony/symfony/src/Symfony/Component/Config/Loader/FileLoader.php on line 179
...

[RuntimeException]
An error occurred when executing the "'cache:clear --no-warmup'" command:
Fatal error: Uncaught ReflectionException: Class Doctrine\Common\DataFixtures\AbstractFixture not found in /Users/juanluisgarciaborrego/Sites/project vendor/symfony/symfony/src/Symfony/Component/Config/Loader/FileLoader.php on line 179
Symfony\Component\Config\Exception\FileLoaderLoadException: Class Doctrine\Common\DataFixtures\AbstractFixture not found in /Users/juanluisgarciaborrego/Sites/project/app/config/services.yml (which is being imported from "/Users/juanluisg
arciaborrego/Sites/project/app/config/config.yml"). in /Users/juanluisgarciaborrego/Sites/project/vendor/symfony/symfony/src/Symfony/Component/Config/Loader/FileLoader.php on line 179


=(

Thanks!!!

Reply

Victor,
I'm trying and I think
It's all ok.

First I run ansible-playbook -i ......... with environment DEV, so it installs :
- create BD
- schema update
- fixtures load

That is good, the next, I run with environment PROD, I ansible is happy and skypped Load data fixtures and Warmup cache.

But, this I think not is the workflow correct.

Reply

Hey Juan,

I agree, that sounds not quite right workflow. In prod environment you really need to skip loading fixtures, but you still need to clear/warm up the cache, but this time with "--env=prod" option. Also, for production you won't just update schema with bin/console doctrine:schema:update, you need to run migrations instead to prevent loosing data.

Cheers!

Reply
Default user avatar
Default user avatar toporovvv | posted 4 years ago

On prod environment I got this error:

fatal: [192.168.50.8]: FAILED! => {"changed": false, "cmd": ["/var/www/project/bin/console", "hautelook_alice:doctrine:fixtures:load", "--no-interaction"], "delta": "0:00:00.080143", "end": "2018-05-10 10:27:36.079665", "msg": "non-zero return code", "rc": 1, "start": "2018-05-10 10:27:35.999522", "stderr": "\n \n [Symfony\\Component\\Console\\Exception\\CommandNotFoundException] \n There are no commands defined in the \"hautelook_alice:doctrine:fixtures\" namespace. \n Did you mean this? \n generate:doctrine

Thats because of dev dependencies in composer.json, I believe. With commented SYMFONY_ENV: "{{ symfony_env|lower }}" or dev as environment in prompt everything works fine.

NB: this error will be removed by conditional logic in a next chapter.

Reply

Hey toporovvv ,

Yes, most probably so... but to be sure you can open config/bundles.php file (app/AppKernel.php) and make sure this fixtures bundle is loaded in dev/test env only (not in prod). Actually, it's a best practice to not load fixtures in production which makes sense because you can accidentally overwrite prod data.

Cheers!

2 Reply
Cat in space

"Houston: no signs of life"
Start the conversation!

This tutorial is built using an older version of Symfony, but the core concepts of Ansible are still valid. New versions of Ansible may contain some features that we don't use here.

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=5.5.9",
        "symfony/symfony": "3.1.*", // v3.1.4
        "doctrine/orm": "^2.5", // v2.7.2
        "doctrine/doctrine-bundle": "^1.6", // 1.6.4
        "doctrine/doctrine-cache-bundle": "^1.2", // 1.3.0
        "symfony/swiftmailer-bundle": "^2.3", // v2.3.11
        "symfony/monolog-bundle": "^2.8", // 2.11.1
        "symfony/polyfill-apcu": "^1.0", // v1.2.0
        "sensio/distribution-bundle": "^5.0", // v5.0.12
        "sensio/framework-extra-bundle": "^3.0.2", // v3.0.16
        "incenteev/composer-parameter-handler": "^2.0", // v2.1.2
        "doctrine/doctrine-migrations-bundle": "^1.2", // v1.2.0
        "snc/redis-bundle": "^2.0", // 2.0.0
        "predis/predis": "^1.1", // v1.1.1
        "composer/package-versions-deprecated": "^1.11" // 1.11.99
    },
    "require-dev": {
        "sensio/generator-bundle": "^3.0", // v3.0.8
        "symfony/phpunit-bridge": "^3.0", // v3.1.4
        "doctrine/data-fixtures": "^1.1", // 1.3.3
        "hautelook/alice-bundle": "^1.3" // v1.4.1
    }
}