2

So I've created a new Symfony 4.1 project last week and have been working on it without any issues. Until yesterday when I started using some third party dependencies. I installed the Guzzle Client by using the composer require guzzlehttp/guzzle. This installed the package just fine as far as I can see.

However, when I then try to inject this service into a constructor in my code (an event or command), I get the error message: Cannot autowire service "App\xxx\Command\testCommand": argument "$client" of method "__construct()" references class "GuzzleHttp\Client" but no such service exists.

The Guzzle service is not the only one that doesn't work, this is just an example. The weird thing to me is that there are a lot of dependencies that I have that work just fine like the Doctrine DocumentManager, JMS serializer and NelmioApiDocBundle.

What I've tried so far (and actually semi-solves the problem) is adding the service name to my services.yaml file:

services:
    # default configuration for services in *this* file
    _defaults:
        autowire: true      # Automatically injects dependencies in your services.
        autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
        public: false       # Allows optimizing the container by removing unused services; this also means
                        # fetching services directly from the container via $container->get() won't work.
                        # The best practice is to be explicit about your dependencies anyway.   

    GuzzleHttp\Client:  <-- Adding this makes it work flawlessly.

The problem I have with this solution is that I would end up adding hundreds of services to my services.yaml file just to get them to work. It seems to me like this is not the optimal solution.

So my question is how I could resolve this in the most elegant way. Is this something I'm doing wrong in my project? Is it something that has to be resolved on the vendors side? And if so, how could it be made to work with Symfony 4.1?

Dirk Scholten
  • 1,013
  • 10
  • 19
  • Hundreds of services? Seems like a big number. Services are defined by bundles not the raw component library. So you need to find an up to date bundle that defines a service for the guzzle client. Or just live with one extra line in services.yaml. – Cerad Jul 11 '18 at 13:05
  • @Cerad Thanks for your reply. Hundreds might have been a slight exaggeration, but I would end up having to use loads. Mainly for my own project that I required. Is there something special I have to do when registering a bundle to make the services inside my bundle auto-wirable? I use my own bundle (github.com/comsave/salesforce-outbound-message-bundle) inside my current project but it doesn't autowire the services inside that bundle. When I try to locate my service with `bin/console debug:container` it shows me .errored..service_locator(followed by the service name here). – Dirk Scholten Jul 11 '18 at 13:46
  • As a rule, third party bundles themselves don't use autowire. Your own message bundle is a bit of a gray area. I assume the plan is to use the bundle in multiple applications? You can tweak the bundle configuration to use autowire. [My answer here](https://stackoverflow.com/questions/49134340/symfony-4-3rd-party-bundle-commands-are-no-longer-automatically-discovered/49135730#49135730) is an example. Different version and all but hopefully you get the idea. – Cerad Jul 11 '18 at 13:53
  • But overall, autowire is really intended to be used at the application level. You might be better off just gritting your teeth and making the services manually in your shared bundles. – Cerad Jul 11 '18 at 13:53
  • That is indeed the plan! Thanks for your help. I understand where I went wrong and will fix things now. – Dirk Scholten Jul 11 '18 at 14:30

2 Answers2

1

composer require GuzzleHttp\Client

It seems like you are trying to require a class, not a package. I was not aware composer is smart enough to recognize a package by it's provided classes, so I checked... it can't, only gives package name suggestions.

Make sure you understand what is a composer package.

The Guzzle service is not the only one that doesn't work, this is just an example.

You don't have a Guzzle service. You only have the guzzle library with it's classes. Services require a service definition, like the one you wrote.

The other services like Doctrine you mentioned are working, because they are bundles, which provide service definitions.

Either you use a bundle, or you use a library, and hook it up yourself.

In the case of guzzle, I would not use a bundle. Then again, I would not use guzzle directly anymore, but HTTPlug. (bundle: https://github.com/php-http/HttplugBundle, library: https://github.com/php-http/httplug)

Padam87
  • 1,013
  • 1
  • 6
  • 7
  • Thanks for your reply! I noticed that I made a typo in my original post. I did actually use `composer require guzzlehttp/guzzle`. Your explanation clears up a lot for me though. I will have a look at the HTTPlug bundle! I have another question about my own bundle that I use in this project. I registered this project as a bundle but it doesn't let me autowire the services inside it either. The bundle is located here: https://github.com/comsave/salesforce-outbound-message-bundle Do I have to register the services inside my project in the bundle so it can be used by other projects? – Dirk Scholten Jul 11 '18 at 13:39
  • The 2 services in your config require parameters, those cannot be autowired. Symfony 4.1 introduced a parameter bag service, but it only works in 4.1 and controversial. https://symfony.com/blog/new-in-symfony-4-1-getting-container-parameters-as-a-service I would use it in my projects, but not in a public bundle. – Padam87 Jul 11 '18 at 14:07
  • Oh, BTW your bundle is marked proprietary in composer.json. – Padam87 Jul 11 '18 at 14:10
  • I understand where I went wrong now. Thanks a lot for the help! I'll do some more reading and upgrade my other project. – Dirk Scholten Jul 11 '18 at 14:29
  • @DirkScholten Just a suggestion, use `eightpoints/guzzle-bundle` so you'll get normal configuration files for your guzzle clients and you won't need to write your own implementation. – Nikita Leshchev Jul 12 '18 at 06:41
0

In my case, I just needed to re-generate the optimized autoload files.

So using composer dump-autoload solved the issue for me.

Farhan
  • 61
  • 8