Symfony4 use external class library as a service
Asked Answered
T

3

9

I have a little external library that expose many classes.

Into my symfony4 project I would like to declare my class from vendor, as a service with autowire and public. So I have include my library with composer and add psr configuration like this into composer.json:

"autoload": {
        "psr-4": {
            "App\\": "src/",
            "ExternalLibrary\\": "vendor/external-library/api/src/"
        }
    }

After that I have tried to change my services.yaml into symfony like this:

ExternalLibrary\:
    resource: '../vendor/external-library/api/src/*'
    public: true
    autowire: true

If I launch tests or run the application returns me this error:

Cannot autowire service "App\Domain\Service\MyService": argument "$repository" of method "__construct()" references interface "ExternalLibrary\Domain\Model\Repository" but no such service exists. You should maybe alias this interface to the existing "App\Infrastructure\Domain\Model\MysqlRepository" service.

If I declare into services.yaml the interface this works fine:

ExternalLibrary\Domain\Model\Lotto\Repository:
    class: '../vendor/external-library/api/src/Domain/Model/Repository.php'
    public: true
    autowire: true

But I have many classes and I don't want to declare each class, how can I fix services.yaml without declare every single service?

Thanks

Thornburg answered 4/9, 2018 at 10:45 Comment(6)
Not sure if loading a whole directory is a good idea. this can have a impact on the container building process. Anyway, for each interface in your constructor arguments, you'll need to declare a class or an alias by hand.Johst
Ok, can you please make an example of you think it should be solved? Thanks @FabienPapetThornburg
Seems like your first approach should have worked. Go back to it then run "bin/console debug:container" and see if you have any ExternalLibrary services at all. You may have to comment out the lines for the App namespace just to get past your original error.Upshaw
@Upshaw the problem is that I'm autowiring an interface and sould be declared with an alias for exampleThornburg
And I'm pretty sure you will need to make the interface ExternalLibrary\Domain\Model\Repository an alias of ExternalLibrary\Domain\Model\Lotto\Repository. Our comments crossed. autowire does not help much with interfaces. See the last part of the answer below as an example.Upshaw
Yes that was the point of the problem @UpshawThornburg
J
6

You need to create services by hand: I did not test it but it should look like this

services.yaml

Some\Vendor\:
    resource: '../vendor/external-library/api/src/*'
    public: true # should be false

Some\Vendor\FooInterface:
    alias: Some\Vendor\Foo # Interface implementation

Some\Vendor\Bar:
    class: Some\Vendor\Bar
    autowire: true

php

<?php

namespace Some\Vendor;

class Foo implements FooInterface
{

}

class Bar
{
    public function __construct(FooInterface $foo)
    {

    }
}

To be more precise you should have something like

ExternalLibrary\Domain\Model\Repository:
    alias: App\Infrastructure\Domain\Model\MysqlRepository
Johst answered 4/9, 2018 at 12:9 Comment(0)
G
5

Let's take Dompdf as an example :

When you try to add type-hint Dompdf in your action controller or service method , an error will be occurred saying that auto-wiring isn't possible because Dompdf is an external PHP library

So to solve this problem we'll make a little change in our services.yaml file by adding this short config

Dompdf\: #Add the global namespace
   resource: '../vendor/dompdf/dompdf/src/*' #Where can we find your external lib ?
   autowire: true  #Turn autowire to true

Apply the above example to all external PHP libs :)

That's all !

Gardie answered 27/5, 2019 at 3:14 Comment(0)
S
1

I had the same problem and someone gave me this solution, which works fine for me:

Use an external repository with symfony4 trouble with autoload and parameters

I copy the other solution by user @DasBen here just in case:

I think that you don't have to import each service separately. Your are already doing that with the "Puc\SapClient" part.

The problem could be that you are importing your models, which should not be imported.

In the symfony example project there is this part vor "services.yaml":

# makes classes in src/ available to be used as services
  # this creates a service per class whose id is the fully-qualified class name
  App\:
    resource: '../src/*'
    exclude: '../src/{Bundle,DependencyInjection,Entity,Model,Migrations,Tests,Kernel.php}'

Then your part would be:

# makes classes in src/ available to be used as services
  # this creates a service per class whose id is the fully-qualified class name
  Puc\SapClient\:
    resource: '../vendor/puc/sap-client/src/*'
    exclude: ''../vendor/puc/sap-client/src/{Entity,Model,"etc."}'

"etc." Would be everything that is not needed as service.

Smalltime answered 10/7, 2020 at 7:36 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.