在 Laravel 6、Lighthouse 5、nwidart/laravel-modules 7 中,报错:Illuminate\Contracts\Container\BindingResolutionException : Target [Interface] is not instantiable while building [Resolver]. 要延迟加载提供者,未实现 provides 方法所导致

1、在 Lighthouse 5 中,报错:Illuminate\Contracts\Container\BindingResolutionException : Target [Interface] is not instantiable while building [Resolver].。如图1

图1

PS E:\wwwroot\object> php artisan lighthouse:ide-helper
Wrote schema directive definitions to E:\wwwroot\object/schema-directives.graphql.

   Illuminate\Contracts\Container\BindingResolutionException  : Target [Modules\ThemeStoreGraphQl\ThemeSetting\Schema\TemplateSchemaLoaderInterface] is not instantiable while building [Modules\ThemeStoreGraphQl\Resolver\OnlineStoreTheme\TemplateSettingsDataResolver].

  at E:\wwwroot\object\vendor\laravel\framework\src\Illuminate\Container\Container.php:978
    974|         } else {
    975|             $message = "Target [$concrete] is not instantiable.";
    976|         }
    977|
  > 978|         throw new BindingResolutionException($message);
    979|     }
    980|
    981|     /**
    982|      * Throw an exception for an unresolvable primitive.

  Exception trace:

  1   Illuminate\Container\Container::notInstantiable("Modules\ThemeStoreGraphQl\ThemeSetting\Schema\TemplateSchemaLoaderInterface")
      E:\wwwroot\object\vendor\laravel\framework\src\Illuminate\Container\Container.php:812

  2   Illuminate\Container\Container::build("Modules\ThemeStoreGraphQl\ThemeSetting\Schema\TemplateSchemaLoaderInterface")
      E:\wwwroot\object\vendor\laravel\framework\src\Illuminate\Container\Container.php:681

  Please use the argument -v to see more details.

2、编辑 ThemeStoreGraphQl/Resources/graphql/theme_setting.graphql ,注释掉:templateSettingsData(basename: String!): [ThemeSection] @field(resolver: “Modules\\ThemeStoreGraphQl\\Resolver\\OnlineStoreTheme\\TemplateSettingsDataResolver”)。则不再报错。

    # "获取主题页面的配置"
    # templateSettingsData(basename: String!): [ThemeSection] @field(resolver: "Modules\\ThemeStoreGraphQl\\Resolver\\OnlineStoreTheme\\TemplateSettingsDataResolver")

3、取消注释后,查看 ThemeStoreGraphQl/Resolver/OnlineStoreTheme/TemplateSettingsDataResolver.php 。TemplateSchemaLoaderInterface 被做为构造函数的参数传入。

    private TemplateSchemaLoaderInterface $templateSchemaLoader;

    public function __construct(TemplateSchemaLoaderInterface $templateSchemaLoader)
    {
        $this->templateSchemaLoader = $templateSchemaLoader;
    }

4、查看此模块的服务提供者类,确定是有注册相应的实例的。但是并未执行 register() 。因为未输出 graphql。

    public function register()
    {
        echo 'graphql';
        exit;

        $this->app->singleton(TemplateSchemaLoaderInterface::class, function($app) {
            if ($this->app['config']['theme_store.view_storage'] == 'database') {
                return new DbTemplateSchemaLoader($app->make(ViewStorageInterface::class), $app->make(TemplateBuilder::class));
            } else {
                return new FileTemplateSchemaLoader($app->make('igaster.themes'), $app->make(TemplateBuilder::class));
            }
        });

        $this->app->singleton(TemplateSettingsDataResolver::class, function($app){
            return new TemplateSettingsDataResolver($app->make(TemplateSchemaLoaderInterface::class));
        });

    }

5、查看模块列表,其 Name 为 ThemeStoreGraphQL,Path 为 E:\wwwroot\object\Modules/ThemeStoreGraphQl。如图2

图2

6、查看 /Modules/ThemeStoreGraphQl/composer.json,其路径 ThemeStoreGraphQL 与实际目录名 ThemeStoreGraphQl 不匹配。调整为与实际目录名一致。如图3

图3

{

    "extra": {
        "laravel": {
            "providers": [
                "Modules\\ThemeStoreGraphQL\\Providers\\GraphQlResolverServiceProvider"
            ],
            "aliases": {

            }
        }
    },
    "autoload": {
        "psr-4": {
            "Modules\\ThemeStoreGraphQL\\": ""
        }
    }

}

7、重命名目录名为:ThemeStoreGraphQL,然后批量替换 ThemeStoreGraphQl 为 ThemeStoreGraphQL。在 PhpStorm 中重命名失败,提示:java.io.IOException: 无法将 ‘E:\wwwroot\object\Modules\ThemeStoreGraphQl’重命名为 ThemeStoreGraphQL。如图4

图4

8、在操作系统目录中重命名。如图5

图5

9、批量替换后,执行 composer install。仍然报错:Illuminate\Contracts\Container\BindingResolutionException : Target [Modules\ThemeStoreGraphQL\ThemeSetting\Schema\TemplateSchemaLoaderInterface] is not instantiable while building [Modules\ThemeStoreGraphQL\Resolver\OnlineStoreTheme\TemplateSettingsDataResolver].

10、查看 /bootstrap/cache/services.php,GraphQlResolverServiceProvider 在数组键 ‘providers’ 中存在,在数组键 ‘eager’ 中不存在。

<?php return array (
  'providers' => 
  array (
    90 => 'Modules\\ThemeStoreDB\\Providers\\ThemeStoreDBServiceProvider',
    91 => 'Modules\\ThemeLocalization\\Providers\\ThemeLocalizationServiceProvider',
    92 => 'Modules\\ThemeAsset\\Providers\\ThemeAssetServiceProvider',
    93 => 'Modules\\ThemeSetting\\Providers\\ThemeSettingServiceProvider',
    94 => 'Modules\\Theme\\Providers\\ThemeServiceProvider',
    95 => 'Modules\\ThemeStoreGraphQL\\Providers\\GraphQlResolverServiceProvider',
  ),
  'eager' => 
  array (
    74 => 'Modules\\ThemeStoreDB\\Providers\\ThemeStoreDBServiceProvider',
    75 => 'Modules\\ThemeLocalization\\Providers\\ThemeLocalizationServiceProvider',
    76 => 'Modules\\ThemeAsset\\Providers\\ThemeAssetServiceProvider',
    77 => 'Modules\\ThemeSetting\\Providers\\ThemeSettingServiceProvider',
    78 => 'Modules\\Theme\\Providers\\ThemeServiceProvider',
  ),
);

11、编辑 /Modules/ThemeStoreGraphQL/Providers/GraphQlResolverServiceProvider.php,删除掉 implements DeferrableProvider 后,查看 /bootstrap/cache/services.php 的 GraphQlResolverServiceProvider 在数组键 ‘eager’ 中存在,且程序运行不再报错。

use Illuminate\Contracts\Support\DeferrableProvider;

class GraphQlResolverServiceProvider extends ServiceProvider implements DeferrableProvider

12、要延迟加载提供者,需要实现 \Illuminate\Contracts\Support\DeferrableProvider 接口并置一个 provides 方法。这个 provides 方法返回该提供者注册的服务容器绑定

use Illuminate\Contracts\Support\DeferrableProvider;

class GraphQlResolverServiceProvider extends ServiceProvider implements DeferrableProvider
{
    /**
     * 获取由提供者提供的服务。
     *
     * @return array
     */    public function provides()
    {
        return [TemplateSchemaLoaderInterface::class, TemplateSettingsDataResolver::class, SettingPersisterInterface::class];
    }
}

13、查看 /bootstrap/cache/services.php 的 GraphQlResolverServiceProvider 在数组键 ‘eager’ 中不存在,运行时不再报错。如图6

图6

PS E:\wwwroot\object> php artisan lighthouse:ide-helper
Wrote schema directive definitions to E:\wwwroot\object/schema-directives.graphql.
Wrote definitions for programmatically registered types to E:\wwwroot\object/programmatic-types.graphql.
Wrote PHP definitions to E:\wwwroot\object/_lighthouse_ide_helper.php.

It is recommended to add them to your .gitignore file.
永夜