Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

bfj5889's avatar

Bind Method not being called in Service Provider

I have a service provider that creates an instance of a class with a Guzzle Client injected into it but the bind method is never called and I am not sure why or how to debug it.

BaseServiceProvider.php

<?php


namespace App\Providers;

use GuzzleHttp\Client;
use Illuminate\Support\ServiceProvider;
use App\Services\BaseService;
use Illuminate\Support\Facades\Log;

class BaseServiceProvider extends ServiceProvider
{
    public function register()
    {
        Log::info('In register 1');
        $this->app->bind(BaseService::class, function ($app) {
            Log::info('In binding');
            return new BaseService(
                new Client(
                    [
                        'base_uri' => config('api.url')
                    ]
                )
            );
        });
    }
}

<?php

namespace App\Services;

use Illuminate\Http\JsonResponse;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;

class UserService extends BaseService
{
    public function show(string $id) : JsonResponse
    {
        try {
            return $this->request('GET', "users/{$id}");
        } catch (\Exception $error) {
            return response()->json([
                'error' => true,
                'msg' => 'There was an error.',
            ], 500);
        }
    }
}
<?php

namespace App\Services;

use GuzzleHttp\Client;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Cache;

class BaseService
{
    /**
     * @var Client
     */
    protected $client;

    /**
     * The baseService constructor.
     *
     * @param Client $client The guzzleHTTP client.
     * @return void
     */
    public function __construct(Client $client)
    {
        $this->client = $client;
    }

    /**
     * Sends a request.
     * @param string   $method        The method.
     * @param string   $url           The url, not including the base uri.
     * @param array    $payload       Optional array of params to send.
     * @param boolean  $decodePayload Optional array of params to send.
     * @return \Illuminate\Http\JsonResponse
     * @throws \GuzzleHttp\Exception\GuzzleException Throws a guzzle error.
     */
    public function request(
        string $method,
        string $url,
        array $payload = []
    ) {
        try {
            $response = $this->client->request(
                strtoupper($method),
                $url,
                [
                    'json' => $payload,
                    'headers' => [
                        'Authorization' => 'Bearer 123',
                        'Cache-Control' => 'no-cache',
                        'Content-Type' => 'application/json',
                        'accept' => 'application/json',
                    ],
                ]
            );
        } catch (\Exception $e) {
            Log::error($e->getMessage());

            return response()->json([
                'error' => true,
                'msg' => $e->getMessage(),
            ], $e->getCode() ?: 500);
        }

        if ($response->getStatusCode() >= 400) {
            Log::error('Request could not be made.');
        }

        return response()->json(
            $response->getBody()->getContents(),
            $response->getStatusCode()
        );
    }

I am debugging a class that I use the BaseService in. When I try to use the Guzzle client I receive a Curl exception because it is not creating the uri with the base uri due to it not binding the class.

Log

testing.INFO: In register 1  
testing.INFO: In register 2
testing.ERROR: cURL error 6: Could not resolve host: token (see http://curl.haxx.se/libcurl/c/libcurl-errors.html) 

The host should be https://mybaseuri/token not token. I have logged the api.url config and it returns the correct base uri. I am using Guzzle 6.3.

0 likes
9 replies
lostdreamer_nl's avatar

Might be a silly question, but have you added the provider to you config/app.php ?


    'providers' => [

        /*
         * Laravel Framework Service Providers...
         */
        Illuminate\Auth\AuthServiceProvider::class,
        [....]
        Illuminate\View\ViewServiceProvider::class,

        /*
         * Package Service Providers...
         */

        /*
         * Application Service Providers...
         */
        App\Providers\AppServiceProvider::class,
        App\Providers\AuthServiceProvider::class,
        App\Providers\EventServiceProvider::class,
        App\Providers\RouteServiceProvider::class,
        App\Providers\BaseServiceProvider::class,

    ],

Also, you should make sure the class name and the filename match: BaseServiceProvider.php - class BaseServiceProvider extends ServiceProvider

Or it wont be found

Talinon's avatar

You won't be able to debug what you've bound into the container until you try to resolve it out of the container. For example, if you try dd(resolve(BaseService::class)); your logging code should execute.

bfj5889's avatar

@LOSTDREAMER_NL - Yup I have added it to the config/app.php file. It is definitely hitting the service provider because it is printing out the 'In register' statements.

bfj5889's avatar

@TALINON - The Log code is what is currently being executed. What it should look like though is something along the lines of this:

testing.INFO: In register 1  
testing.INFO: In binding
testing.INFO: In register 2
bfj5889's avatar

So I did some more debugging and I don't think it is an issue with the Service Provider but an issue with Guzzle Client being created with a base_uri. If I add the base uri to all my request in my BaseService they go through without an issue.

I must be instantiating the Client incorrectly.

Talinon's avatar

What I'm trying to tell you is that that code you place within the Closure will not execute until you explicitly ask for it (resolve it) out of the Container.

   public function register()
    {
        Log::info('In register 1');
        $this->app->bind(BaseService::class, function ($app) {
            Log::info('In binding');
            return new BaseService(
                new Client(
                    [
                        'base_uri' => config('api.url'),
                    ]
                )
            );
        });

    // will resolve your binding out of the container and execute the code within the closure, including your Log
    dd(resolve(BaseService::class));

    }
bfj5889's avatar

OOhhh I see, so does that mean I have to have the resolve at the end of the service provider or will Laravel resolve it automatically?

I have another class that is making a request and it extends the BaseService. Do/How would I resolve the class if it is an extension and should be run by default?

I am going to update the original question so you can better see the code I am working with.

Talinon's avatar

The short answer to your question - no, you don't resolve it at the end of the Service Provider; I just placed that there as an example on why your debug code wasn't firing.

When you bind something into the container, you're essentially making it globally accessible from anywhere in your app, along with the dependencies. Each time you need it, you can resolve it out of the container. If you want the same instance resolved each time, you will want to bind a singleton, otherwise, it will instantiate a new instance of your binding upon each request.

bfj5889's avatar
bfj5889
OP
Best Answer
Level 2

Found the solution.

The service provider is not called when the class is used as an extension (ie UserService extends BaseService). So the BaseServiceProvider was never being called because it is not resolved from the container (ie.resolve(BaseService) or app(BaseService), which is why the URI was never being added as the base. The solution is to just add the base of the URI to the functions in the BaseService that make requests.

Old BaseService request method

try {
            $response = $this->client->request(
                strtoupper($method),
                $url,
                [
                    'json' => $payload,
                    'headers' => [
                        'Authorization' => 'Bearer 123',
                        'Cache-Control' => 'no-cache',
                        'Content-Type' => 'application/json',
                        'accept' => 'application/json',
                    ],
                ]
            );
        }

New BaseService request method

try {
            $response = $this->client->request(
                strtoupper($method),
                config('api.url') . $url,
                [
                    'json' => $payload,
                    'headers' => [
                        'Authorization' => 'Bearer 123',
                        'Cache-Control' => 'no-cache',
                        'Content-Type' => 'application/json',
                        'accept' => 'application/json',
                    ],
                ]
            );
        }

The Service Provider can be removed completely and a Guzzle Client instance will be injected automatically by Laravel.

Please or to participate in this conversation.