How to swap out dependency in laravel container

十年热恋 提交于 2019-12-11 15:04:52

问题


I have registered a Paypal service provider:

App\Providers\PaypalHelperServiceProvider::class,

and, when I type hint it in my controller it properly resolves:

public function refund(Request $request, PaypalHelper $paypal) {...

Here is my provider class:

class PaypalHelperServiceProvider extends ServiceProvider
{
  protected $defer = true;

  public function register()
  {
      $this->app->bind('App\Helpers\PaypalHelper', function() {
          $test = 'test';
          return new PaypalHelper();
      });
    }

    public function provides()
    {
      $test = 'test';
      return [App\Helpers\PaypalHelper::class];
    }
  }

Everything works as expected. Now I wanted to be able to modify controller to take a PayPal interface. I would then update my service provider to conditionally pass in either the real class or a mock one for testing, using the APP_ENV variable to determine which one to use. I put some debuggers into the service provider class and could not get it to ever go in. I thought perhaps that it only loads them on need, so I put a breakpoint inside my controller. The class did resolve, but it still never went into the service provider class! Can someone explain to me why this is the case? Even when I modified the code to pass in a different class type it did not pick up.

EDIT:

Here is the code flow I see when I debug this: ControllerDispatcher -> resolveClassMethodDependencies -> resolveMethodDependencies -> transformDependency. At this point we have the following laravel code in the RouteDependencyResolveerTrait:

 protected function transformDependency(ReflectionParameter $parameter, $parameters, $originalParameters)
{
    $class = $parameter->getClass();

    // If the parameter has a type-hinted class, we will check to see if it is already in
    // the list of parameters. If it is we will just skip it as it is probably a model
    // binding and we do not want to mess with those; otherwise, we resolve it here.
    if ($class && ! $this->alreadyInParameters($class->name, $parameters)) {
        return $this->container->make($class->name);
    }
}

Since getClass() always resolves to the interface name, when we call container->make(), it always fails with

Target [App\Helpers\PaypalHelperInterface] is not instantiable.

回答1:


Change

      $this->app->bind('App\Helpers\PaypalHelper', function() {
          $test = 'test';
          return new PaypalHelper();
      });

To

if (app()->environment('testing')) {
    $this->app->bind(
        PaypalHelperInterface::class,
        FakePaypalHelper::class
    )
} else {
    $this->app->bind(
        PaypalHelperInterface::class,
        PaypalHelper::class
    );
}



回答2:


I finally found out the issue. My problem was that my provider wasn't being picked up at all. Here was the solution

composer dumpautoload
php artisan cache:clear

https://laravel.io/forum/02-08-2015-laravel-5-service-provider-not-working



来源:https://stackoverflow.com/questions/57828025/how-to-swap-out-dependency-in-laravel-container

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!