CsaGuzzleBundle icon indicating copy to clipboard operation
CsaGuzzleBundle copied to clipboard

Add documentation for making autowireable Guzzle client with custom class

Open rvanlaak opened this issue 5 years ago • 7 comments

Another use case to document; changing the client's class, and how to autowire that to another own service definition.

Possible content

The bundle can get used as "a factory" to create an autowireable class. That way the bundle puts the middleware (like logging / error reporting / timing) in place.

<?php

namespace Acme\Infra\Shopping;

class Client extends \GuzzleHttp\Client
{
}

csa_guzzle:
    clients:
        shopping:
            class: 'Acme\Infra\Shopping\Client'
            config:
                base_uri: '%shopping.base_uri%'

When someone wants to autowire that class in their own service definition:

services:
    Acme\Application\Shopping\Cart:
        arguments: ['@Acme\Infra\Shopping\Client']   

Important note:

For controller action argument autowiring this works perfectly, but for resolving service arguments on container compilation this would unfortunately give a "service not found" exception because the bundle would register the client to the container after it resolved the rest of the services.

A way the container can resolve / autowire is by aliasing the service this bundle creates:

services:
    Acme\Infra\Shopping\Client:
        alias: 'csa_guzzle.client.shopping'

Probably a solution that wouldn't need this additional service alias, is by somewhere changing compilation priorities. Can bundles do their work several steps earlier in the compilation process?

rvanlaak avatar Aug 22 '18 13:08 rvanlaak

Thanks for the suggestion! I definitely agree, we should provide documentation for such use case.

In any case, if you wish to provide a doc PR, feel free to fork the project, and change the files in the src/Resources/doc folder :)

One thing though: is there any specific reason for extending the client, instead of wrapping it in a decorator class?

csarrazi avatar Aug 24 '18 09:08 csarrazi

Hi @csarrazi. Is there some documentation about this?

micayael avatar Apr 05 '19 01:04 micayael

Hy @micayael not yet. I'm still waiting for someone to make a PR for this, as I am a bit short on time, these days.

csarrazi avatar Apr 08 '19 14:04 csarrazi

Thanks for reply @csarrazi.

Do you know if this is posible? I am trying multiple things but without success. if you could give me a little light on this I could help with the documentation

micayael avatar Apr 08 '19 16:04 micayael

The main reason for that I wish to encourage composition instead of inheritance. Meaning that instead of extending the Guzzle client, it would be better to wrap the client in a class exposing only business logic.

csarrazi avatar Apr 10 '19 07:04 csarrazi

@csarrazi I think I've accomplished with your explanation

I configure the client with own configuration in csa_guzzle.yaml or config.yml

csa_guzzle:
    profiler: '%kernel.debug%'
    clients:
        client1:
            config:
                base_uri: http://localhost:8000
                timeout: 3.0
                headers:
                    "Content-Type": application/json

I create a Symfony service wrapping my client in services.yaml

services:

    App\MyOwnClient:
        arguments: ['@csa_guzzle.client.client1']

My Symfony service use the internal client in MyOwnClient.php

<?php

namespace App;

use GuzzleHttp\Client;

class RulerClient
{
    private $client;

    public function __construct(Client $client)
    {
        $this->client = $client;
    }
    
    public function ownMethod(string $path, array $data)
    {
        $response = $this->client->post($path, [
            'json' => $data
        ]);
        
        return $response;
    }
}

Now I can use it and I have the symfony profile functional

micayael avatar Apr 12 '19 14:04 micayael

👍

csarrazi avatar Apr 12 '19 15:04 csarrazi