(Laravel) Dynamic dependency injection for interface, based on user input

后端 未结 4 993
醉话见心
醉话见心 2021-01-30 17:31

I am currently facing a very interesting dilemma with my architecture and implementation.

I have an interface called ServiceInterface which have a method ca

4条回答
  •  逝去的感伤
    2021-01-30 18:13

    It's an interesting problem. I'm currently using Laravel 5.5 and have been mulling it over. I also want my service provider to return a specific class (implementing an interface) based upon user input. I think it's better to manually pass the input from the controller so it's easier to see what's going on. I would also store the possible values of the class names in the config. So based upon the Service classes and interface you've defined above i came up with this:

    /config/services.php

    return [
        'classes': [
            'service1' => 'Service1',
            'service2' => 'Service2',
        ]
    ]
    

    /app/Http/Controllers/MainController.php

    public function index(ServiceRequest $request)
    {
        $service = app()->makeWith(ServiceInterface::class, ['service'=>$request->get('service)]);
        // ... do something with your service
    }
    

    /app/Http/Requests/ServiceRequest.php

    public function rules(): array
        $availableServices = array_keys(config('services.classes'));
        return [
            'service' => [
                'required',
                Rule::in($availableServices)
            ]
        ];
    }
    

    /app/Providers/CustomServiceProvider.php

    class CustomServiceProvider extends ServiceProvider
    {
        public function boot() {}
    
        public function register()
        {
            // Parameters are passed from the controller action
            $this->app->bind(
                ServiceInterface::class,
                function($app, $parameters) {
                    $serviceConfigKey = $parameters['service'];
                    $className = '\\App\\Services\\' . config('services.classes.' . $serviceConfigKey);
                    return new $className;
                }
            );
        }
    }
    

    This way we can validate the input to ensure we are passing a valid service, then the controller handles passing the input from the Request object into the ServiceProvider. I just think when it comes to maintaining this code it will be clear what is going on as opposed to using the request object directly in the ServiceProvider. PS Remember to register the CustomServiceProvider!

提交回复
热议问题