(Laravel)基于用户输入的接口动态依赖注入 [英] (Laravel) Dynamic dependency injection for interface, based on user input

查看:168
本文介绍了(Laravel)基于用户输入的接口动态依赖注入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前在我的体系结构和实现方面面临一个非常有趣的难题.

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

我有一个名为ServiceInterface的接口,该接口有一个名为execute()

I have an interface called ServiceInterface which have a method called execute()

然后我对此接口有两种不同的实现:Service1Service2,它们可以正确实现execute方法.

Then I have two different implementations for this interface: Service1 and Service2, which implements the execute method properly.

我有一个名为MainController的控制器,该控制器具有ServiceInterface(依赖项注入)的类型提示",这意味着Service1Service2 ,可以称为该依赖项注入的解决方案.

I have a controller called MainController and this controller has a "type-hint" for the ServiceInterface (dependency injection), it means that both, Service1 and Service2, can be called as resolution for that dependency injection.

现在有趣的部分:

我不知道要使用哪个实现(Service1Service2),因为我只知道根据上一步的用户输入,是否可以使用一个或其他.

I do not know which of those implementations to use (Service1 or Service2) because I just know if I can use one or other based on a user input from a previous step.

这意味着用户选择一种服务,并基于该值,我知道a可以使用Service1还是Service2.

It means the user choose a service and based on that value I know if a can use Service1 or Service2.

我目前正在使用会话值来解决依赖项注入,因此根据我返回一个实例或其他实例的值,但是我真的认为这不是一个好方法.

I am currently solving the dependency injection using a session value, so depending of the value I return an instance or other, BUT I really think that it is not a good way to do it.

请让我知道您是否遇到过类似的事情,如何解决它,或者我该怎么做才能以正确的方式实现这一目标.

Please, let me know if you faced something similar and, how do you solve it, or what can I do to achieve this in the right way.

先谢谢了.请让我知道是否需要进一步的信息.

Thanks in advance. Please let me know if further information is required.

推荐答案

最后,经过几天的研究和思考,我终于使用Laravel解决了最佳方法.

Finally after some days researching and thinking alot about the best approach for this, using Laravel I finally solved.

我不得不说这在Laravel 5.2中特别困难,因为在此版本中, Session 中间件仅在路由中使用的控制器中执行,这意味着使用了一个控制器(未链接到死记硬背),并试图访问该会话,这是不可能的.

I have to say that this was specially difficult in Laravel 5.2, because in this version the Session middleware only is executed in the controllers used in a route, it means that if for some reason I used a controller (not linked for a rote) and try to get access to the session it is not going to be possible.

因此,由于我无法使用我决定使用URL参数的会话,因此这里有解决方案的方法,希望你们中的一些人发现它有用.

So, because I can not use the session I decided to use URL parameters, here you have the solution approach, I hope some of you found it useful.

所以,您有一个界面:

interface Service
{
    public function execute();
}

然后是该接口的几种实现方式:

Then a couple of implementations for the interface:

服务一:

class ServiceOne implements Service
{
    public function execute()
    {
        .......
    }
}

服务二.

class ServiceTwo implements Service
{
    public function execute()
    {
        .......
    }
}

现在有趣的部分:有一个控制器,该控制器的功能与Service接口有关,但我需要在使用输入中将其解析为ServiceOne或ServiceTwo.所以:

Now the interesting part: have a controller with a function that have a dependency with the Service interface BUT I need to resolve it dinamically to ServiceOne or ServiceTwo based in a use input. So:

控制器

class MyController extends Controller
{
    public function index(Service $service, ServiceRequest $request)
    {
        $service->execute();
        .......
    }
}

请注意,ServiceRequest已验证该请求已具有解析依赖关系所需的参数(将其称为'service_name')

Please note that ServiceRequest, validated that the request already have the parameter that we need to resolve the dependency (call it 'service_name')

现在,在AppServiceProvider中,我们可以通过以下方式解决依赖关系:

Now, in the AppServiceProvider we can resolve the dependency in this way:

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {

    }

    public function register()
    {
        //This specific dependency is going to be resolved only if
        //the request has the service_name field stablished
        if(Request::has('service_name'))
        {
            //Obtaining the name of the service to be used (class name)
            $className = $this->resolveClassName(Request::get('service_name')));

            $this->app->bind('Including\The\Namespace\For\Service', $className);
        }
    }

    protected function resolveClassName($className)
    {
        $resolver = new Resolver($className);
        $className = $resolver->resolveDependencyName();
        return $className;
    }
}

因此,现在所有的责任都由Resolver类负责,该类基本上使用传递给构造方法的参数来返回将用作Service接口实现的类的全名(带有名称空间): /p>

So now all the responsibilty is for the Resolver class, this class basically use the parameter passed to the contructor to return the fullname (with namespace) of the class that is going to be used as a implementation of the Service interface:

class Resolver
{
    protected $name;
    public function __construct($className)
    {
        $this->name = $className;
    }

    public function resolveDependencyName()
    {
        //This is just an example, you can use whatever as 'service_one'
        if($this->name === 'service_one')
        {
            return Full\Namespace\For\Class\Implementation\ServiceOne::class;
        }

        if($this->name === 'service_two')
        {
            return Full\Namespace\For\Class\Implementation\ServiceTwo::class;
        }
        //If none, so whrow an exception because the dependency can not be resolved 
        throw new ResolverException;
    }
}

好吧,我真的希望它对你们中的某些人有帮助.

Well, I really hope it help to some of you.

最良好的祝愿!

----------编辑-----------

---------- EDIT -----------

我只是意识到,直接在Laravel容器内使用请求数据不是一个好主意,从长远来看,这确实会造成一些麻烦.

I just realize, that it is not a good idea to use directly the request data, inside the container of Laravel, it really is going to make some trouble in the long term.

最好的方法是直接注册支持的所有可能实例(serviceone和servicetwo),然后直接从控制器或中间件中解析其中一个实例,然后由控制器谁决定"要使用的服务(从所有实例中解析).可用)基于请求的输入.

The best way is to directly register all the possible instances suported (serviceone and servicetwo) and then resolve one of them directly from a controller or a middleware, so then is the controller "who decides" what service to use (from all the available) based on the input from the request.

最后,它的工作原理相同,但是它将使您能够以更自然的方式工作.

At the end it works at the same, but it is going to allow you to work in a more natural way.

我必须感谢rizqi.来自Laravel闲聊的问题频道的用户.

I have to say thanks to rizqi. A user from the questions channel of the slack chat of Laravel.

他亲自为此创建了金色的文章.请阅读它,因为可以完全正确地解决此问题.

He personally created a golden article about this. Please read it because solve this issue completely and in a very right way.

laravel注册表模式

这篇关于(Laravel)基于用户输入的接口动态依赖注入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆