nWidart / laravel-modules

Module Management In Laravel
https://docs.laravelmodules.com
MIT License
5.54k stars 962 forks source link

ModuleServiceProvider register singleton issue #1761

Open xavi7th opened 7 months ago

xavi7th commented 7 months ago

I am having a weird issue with one of my Module service providers.

In the register method of my ModuleServiceProvider I have this code

$this->app->singleton(GateContract::class, function ($app) {
      return new ModifiedGate($app, function () use ($app) {
        return call_user_func($app['auth']->userResolver());
      });
    });

My ModifiedGate class has the Conditionable trait.

In one of my codes I am using the conditionable when method on the Gate Facade like this.

Gate::when($this->user, fn($gate) => $gate->forUser($this->user))->inspect('policy', 'class')->allowed();

Now, before I updated to Laravel 10, everything worked perfectly. However after upgrading to Laravel 10, I am having an issue with the when method. I get this error Call to undefined method Illuminate\Auth\Access\Gate::when().

After hours of debugging I believe that the singleton bind in my ModuleServiceProvider is somehow not working. What is weird though is that I can verify that the code is being run. If I place a dd() inside the singleton bind, or before it, my code hits it. That tells me that at least Laravel is running the code to bind it. But it somehow does not stick as Laravel still resolves the original GateContract instead of my ModifiedGate.

After debugging further, I noticed that if I place the bind code in the register method of the default AppServiceProvider class, everything works fine. That means Laravel properly binds the singleton from the default AppServiceProvider class.

Another weird observation is this. If I manually add my ModuleServiceProvider class into the providers array of the app config file like the example below, it also works perfectly. Laravel recognises the singleton bind.

'providers' => ServiceProvider::defaultProviders()->merge([
    /*
     * Application Service Providers...
     */
    App\Providers\AppServiceProvider::class,
    . . .
    ModuleNameSpace\ModuleServiceProvider::class, // if this is added it works
  ])->toArray(),

This is weird because I thought Laravel auto-discovered Module ServiceProviders and there should be no need to manually register them. The fact that Laravel executes the singleton bind code even without the manual registration suggests to me that that is the case, so I can't figure out why I need the manual registration before Laravel accepts the singleton bind.

I have cleared the compiled files in bootstrap/cache folder. I have tried running artisan compile (and curious enough the ModuleServiceProviders are not listed in the compiled providers array🤔). I have tried adding the service provider to the extra laravel key of the Modules composer.json file (to force Laravel to auto-discover it). I have also tried removing it. All to no avail.

The only thing that works for now is doing the binding in the AppServiceProvider's register method, or keeping the code in my ModuleServiceProvider and manually registering my ModuleServiceProvider in app config providers array.

Any ideas what I could be doing wrong? If it will help, I can provide a link to the flareapp.io error.

Thank you for your time.

dcblogdev commented 7 months ago

thanks for the detailed post, this will help me to dig into it further