Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Installing Composer Deps

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

Ok, let's install our Composer dependencies already! Go back to the Ansible composer module for reference. Then, find your playbook and add a new task with a poetic and flowery name: "Install Composer's dependencies":

---
- hosts: vb
... lines 3 - 6
tasks:
... lines 8 - 109
- name: Install Composer's dependencies
... lines 111 - 113

Ok, boring name, but clear! Use the composer module, and set the one required option - working_dir - to {{ symfony_root_dir }}:

---
- hosts: vb
... lines 3 - 6
tasks:
... lines 8 - 109
- name: Install Composer's dependencies
composer:
working_dir: "{{ symfony_root_dir }}"

Hey, that variable is coming in handy!

Run that playbook!

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

It's running... running, installing Composer's dependencies and... explosion! Ah! So much red! Run!

Then... come back. Let's see what's going on. It looks like it was downloading stuff... if we move to /var/www/project on the VM and ls vendor/, yep, it was populated.

The problem was later - when one of Symfony's post-install tasks ran:

Fatal error: Uncaught exception, SensioGeneratorBundle does not exist.

Oh yea. By default, the composer module runs composer like this:

composer install --no-dev

This means that your require-dev dependencies from composer.json are not installed:

78 lines composer.json
{
... lines 2 - 35
"require-dev": {
"sensio/generator-bundle": "^3.0",
"symfony/phpunit-bridge": "^3.0",
"doctrine/data-fixtures": "^1.1",
"hautelook/alice-bundle": "^1.3"
},
... lines 43 - 76
}

If you're deploying to production, you may want that: it gives you a slight performance boost. But in a Symfony 3 application, it makes things blow up! You can fix this by setting an environment variable... and we will do that later.

But, since this is a development machine, we probably do want the dev dependencies. To fix that, in the playbook, set no_dev to no:

---
- hosts: vb
... lines 3 - 6
tasks:
... lines 8 - 109
- name: Install Composer's dependencies
composer:
working_dir: "{{ symfony_root_dir }}"
no_dev: no

Try the playbook now.

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

This time, I personally guarantee it'll work. In fact, I'm so confident, that if it doesn't work this time, I'll buy you a beer or your drink of choice if we meet in person. Yep, it's definitely going to work - I've never been so sure of anything in my entire life.

Ah! No! It blew up again! Find the culprit!

Attempted to load class "DOMDocument" from the global namespace.

Uh oh. I skipped past something I shouldn't have. When you download a new Symfony project, you can make sure your system is setup by running:

php bin/symfony_requirements

Your system is not ready to run Symfony projects.

Duh! The message - about the SimpleXML extension - means that we're missing an extension! In our playbook, find the task where we install PHP. Add another extension: php7.1-xml:

---
- hosts: vb
... lines 3 - 6
tasks:
... lines 8 - 55
- name: Install PHP packages
... lines 57 - 60
with_items:
... lines 62 - 66
- php7.1-xml
... lines 68 - 115

Run that playbook - hopefully - one last time:

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

Ya know, this is the great thing about Ansible. Sure, we might have forgotten to install an extension. But instead of installing it manually and forgetting all about it next time, it now lives permanently in our playbook. We'll never forget it again.

Phew! It worked! Go back to the VM and check out requirements again:

php bin/symfony_requirements

We're good! And most importantly, we can boot up our Symfony app via the console:

php bin/console

Our app is working! And there's just one last big step to get things running: configure NGINX with PHP-FPM and point it at our project. Let's go!

Leave a comment!

23
Login or Register to join the conversation
ITHouseMeister Avatar
ITHouseMeister Avatar ITHouseMeister | posted 2 years ago | edited

Hi there,

I've found this screencast and testing around with Ubuntu Focal and Bionic... and I also have issues with "Install Composer's dependencies". On both systems ansible stops with nothing... no error, no output and no process (viewed in htop)...

`
TASK [Download Composer] ***********************************
changed: [192.168.19.146]

TASK [Move Composer globally] **********************************
changed: [192.168.19.146]

TASK [Set permissions on Composer] *********************************
ok: [192.168.19.146]

TASK [Install Composer's dependencies] *****************************

`

Any ideas what happend at this point?
Thank you a lot... take care!

Reply
ITHouseMeister Avatar
ITHouseMeister Avatar ITHouseMeister | ITHouseMeister | posted 2 years ago | edited

sorry: in htop I've found an processes:
<br />/usr/bin/python3 ~/.ansible/tmp/ansible-tmp-1603580969.8799226-12682-259632965674037/AnsiballZ_composer.py<br />/usr/bin/php /usr/local/bin/composer help install --format=json<br />

Reply
ITHouseMeister Avatar
ITHouseMeister Avatar ITHouseMeister | ITHouseMeister | posted 2 years ago | edited

Ahhh, found the solution by killing the process. In the background was a hint "avoid running Composer as super-user/root".
I used become: true globally and not like you provide in every task.

Reply

Hey Axel,

Yeah, looks like on your system the Composer is running under root privileges and so yes, become true should do the trick, nice catch :) An alternative but more complex solution would be to fix permissions and make it be run without root privileges. One of possible reasons why it requires root is that it might be installed via root. Anyway, I'm glad you were able to find the working solution for you!

Cheers!

Reply
Default user avatar
Default user avatar gstanto | posted 5 years ago

Not sure why but I get an error running the composer install the second time.
Uncaught TypeError: Argument 1 passed to Composer\\Autoload\\ClassLoader::addClassMap() must be of the type array, integer given

Error goes away only when 'optimize_autoloader' is disabled

- name: Install Composer Dependencies
composer:
working_dir: "{{ symfony_root_dir }}"
no_dev: no
optimize_autoloader: false

Reply

Hey gstanto ,

Hm, difficult to say why without debugging, probably it's a bug in Composer, I'd recommend to you to upgrade your composer to the latest available version and try again.

Btw, sometimes problems could be due to the PHP version difference, e.g. when you use different PHP versions locally (where you lock dependencies in composer.lock) and on the server where you're trying to run this script.

UPD: Actually, I found a similar issue in Composer repo: https://github.com/composer... try to follow some instructions from there. Probably the easy fix is to upgrade/downgrade Composer, maybe you just have a bad version.

Let us know if a solution from the issue works for you.

Cheers!

Reply
Default user avatar

I can't get it to run. I deleted composer.lock, vendor dir, and deleted all cache files, and everything resolved. But only the first run. Same thing happened with previous version install. If I find a solution, I'll post it here. Thank you very much for the timely response btw.

Reply

Hm, I just double checked the downloaded course code from both start/ and finish/ directories and it works for me well when I run both "composer install" and "composer install --optimize-autoloader" commands several times locally, i.e. I don't see the error you mentioned. Btw, could you try to install dependencies by yourself, i.e. not via Ansible but directly in your console as I did. Do you also see this error?

Cheers!

Reply
Default user avatar

Thanks Victor. I did as you said, no errors in console when I was direct on Vagrant. Ran a second time was still fine. Deleted everything, ran and still fine. Changed everything to work for Symfony4, still fine! Must have been me.
sorry for the hassle and thanks for the help. This tutorial was extremely helpful, btw.

Reply

Glad it was helpful for you!

Cheers!

Reply
Default user avatar
Default user avatar jian su | posted 5 years ago

If I made mistakes like you, and I rerun the playbook again. Does that mean I re-download php7.1 mysql and composer......over again??

Reply

Yo jian su!

Yes and no :). This depends on your task, and it's something we talk about later, in fact in the next chapter to be released: https://knpuniversity.com/screencast/ansible/faster-smarter-playbook

When you use the apt module, it's basically running apt-get install php7.1. And apt is smart enough to not re-download and re-install something if it's already there (however, if you use the "latest" state, then it will upgrade the package if there is a new version). So for apt the answer is mostly no: the packages are not redownloaded and reinstalled.

But for Composer, the answer (until the later chapter), is YES! This is because we're simply telling Ansible to run some commands (which download Composer), so it simply runs those commands every time. That's not a big deal, but it is wasteful. So, we fix it later.

Cheers!

Reply
Default user avatar

Awesome. Thank you!

Reply
Default user avatar
Default user avatar jian su | posted 5 years ago

Hi Guys:

After running this task and have problem

- name: Install Composer's dependencies
composer:
working_dir: "{{ symfony_root_dir }}"
no_dev: no

Need help, I have the following error

[Symfony\Component\Config\Exception\FileLoaderLoadException]
The configuration key "exclude" is unsupported for definition "AppBundle\" in "/var/www/project/app/config/services.yml". Allowed configuration key
s are "resource", "parent", "shared", "lazy", "public", "abstract", "deprecated", "factory", "arguments", "properties", "configurator", "calls", "t
ags", "autowire", "autoconfigure" in /var/www/project/app/config/services.yml (which is being imported from "/var/www/project/app/config/config.yml
").

Reply

Hey jian su!

Ah, ha! This is related to Symfony! Are you trying to use the new Symfony 3.3 dependency injection features? The exclude key is pretty new (only a few days old), so you likely need to update to the absolute latest commit of Symfony on the master branch. I hope you enjoy those features - I've been personally working very hard on them (along with other people).

Cheers!

Reply
Default user avatar

Ah I see. So I just need download previous version then I should be fine

Reply

Yeah, give it a try and let us know if you encounter to any problem :)

Reply
Default user avatar
Default user avatar Nia Kathoni | posted 5 years ago

The Install Composer's dependencies is failing for me with
TASK [Install Composer's dependencies] *****************************************
fatal: [192.168.33.10]: FAILED! => {"changed": false, "failed": true, "module_stderr": "Shared connection to 192.168.33.10 closed.\r\n", "module_stdout": "Traceback (most recent call last):\r\n File \"/tmp/ansible_c3hnjciv/ansible_module_composer.py\", line 233, in <module>\r\n main()\r\n File \"/tmp/ansible_c3hnjciv/ansible_module_composer.py\", line 212, in main\r\n for param, option in option_params.iteritems():\r\nAttributeError: 'dict' object has no attribute 'iteritems'\r\n", "msg": "MODULE FAILURE"}
as output. The error seems to be related to the version of python but I am not sure if it's the local version or the guest os one.

Reply

Hey Nia,

Hm, you can try to run "composer install --no-ansi --no-interaction --no-progress" manually, do you see any errors in the output? If not, then there's some bug in Ansible's Composer module. Btw, do you have the latest Composer version? Do you have any other extra Composer parameters in your task?

Cheers!

Reply
Default user avatar
Default user avatar Nia Kathoni | Victor | posted 5 years ago

Hi Victor,

Running "composer install --no-ansi --no-interaction --no-progress" manually didn't yield any errors and by googling the error it looks like it something related to the composer module.
> Btw, do you have the latest Composer version?
The latest version on the guest or host OS? If guest I using the script at https://getcomposer.org/doc... to download it and install it as suggested in the screencast.

> Do you have any other extra Composer parameters in your task?
No extras parameters in the task.
- name: Install Composer's dependencies
composer:
working_dir: "/var/www/project"
no_dev: no
Also using "ubuntu/xenial64" for vagrant box.

Thanks for the quick reply and feedback.

Reply

Hey Nia,

> The latest version on the guest or host OS?
I meant that OS on which you run that composer install task and see that error.

So if you run "composer install" manually and it works fine without any errors but failed with Ansible - most probably related to the Composer module. If you have a detailed steps to reproduce, I think you can report an issue in Ansible's repository if nobody did it already.

So there're a few possible solutions:
1. Try to downgrade your composer.phar file to a lower version with which this task worked fine. But for this one your need to know what version worked fine for you before.
2. Wait for the fix, but you need to be sure that this bug is reported and confirmed, so someone will fix it.
3. Or temporarily write a custom composer task using "command" module to install composer dependencies. You can even play with "changed_when" based on the output to make this task green if nothing was done by Composer.

If first 2 cases are not an option for you - I think the 3rd should be good and easy to implement.

Cheers!

Reply
Default user avatar
Default user avatar Nia Kathoni | Victor | posted 5 years ago

Went with the 3rd option and added
register: composer_dependencies_installed
changed_when: "composer_no_update not in composer_dependencies_installed.stdout_lines"
with
vars:
composer_no_update: "Nothing to install or update"
Thanks again, I will try to make the composer module work in the future.

Reply

Hey Nia,

Thanks for sharing your temporary solution with others! Most of the times I just hardcode strings in "changed_when" statements, it makes sense to create a var only when you need to use that string in a few places. But yeah, good work!

Cheers!

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
    }
}
userVoice