如何在Laravel 4中执行构造函数注入的依赖项?

时间:2013-06-10 20:11:45

标签: php laravel

我的团队喜欢构造函数注入依赖项的想法,因为它在查看类时非常清楚deps。随着外墙的使用,我知道他们可以被嘲笑和swap ped,但是人们必须检查一个类的每一行以找出它依赖的东西!我发现我可以在幕后找到真正的类,例如Form::getFacadeRoot()

我最终得到的控制器代码是:

use Illuminate\Html\FormBuilder as Form;
use Illuminate\Validation\Factory as Validator;
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage as Session;
use Illuminate\Http\Request as Input;
use Illuminate\Routing\Redirector as Redirect;
use Illuminate\View\Environment as View;

class HomeController extends BaseController {

    protected $form;
    protected $validator;
    protected $session;
    protected $input;
    protected $redirect;
    protected $view;

    protected $layout = 'layouts.master';

    protected $validationRules = array(
        'name'  => array('required', 'min:3'),
        'email' => array('required', 'regex:/^.+@.+\..{2,4}$/')
    );

    public function __construct(Form $form, Validator $validator, Session $session,
        Input $input, Redirector $redirect, View $view
    ) {
        $this->form      = $form;
        $this->validator = $validator;
        $this->session   = $session;
        $this->input     = $input;
        $this->redirect  = $redirect;
        $this->view      = $view;
    }

        ...
}

当我的测试$this->client->request('Get', '/');时,它出错:

Illuminate\Container\BindingResolutionException: Unresolvable dependency resolving [Parameter #2 [ <required> $csrfToken ]].

我是否接近正确的轨道?我有点像这样做,因为我没有看到很多关于这个问题的讨论。随意评论我尝试的原因;我可以在外墙上出售。

谢谢!

2 个答案:

答案 0 :(得分:7)

您需要使用Laravel的IoC容器将类依赖关系映射到类。这可以使用App facade完成。所以在上面的示例中使用构造函数

public function __construct(Form $form, Validator $validator, Session $session, Input $input, Redirector $redirect, View $view)

您将创建一个看起来像以下内容的绑定:

App::bind('Form', function(){
    return new Illuminate\Html\FormBuilder()
});

Taylor Otwell建议使用Interfaces作为类依赖关系的契约。因此,理想情况下,您完成的代码看起来就像下面的内容(我已经将它简化了一点)。

对于您的控制器:

use Namespace\For\FormInterface;

class HomeController extends BaseController {

    public function __construct(FormInterface $form)
    {
        $this->form = $form;
    }

    public function myHomePage()
    {
        $this->form->myFormFunction()
    }
}

对于界面:

namespace Namespace\For;

interface FormInterface(){

    public function myFormFunction()
}

要注射的课程:

use Namespace\For\FormInterface;

class MyFormClass implements FormInterface{

    public function myFormFunction()
    {
        // Do some stuff here
    }
}

然后最后你创建了将它们组合在一起的绑定:

App::bind('Namespace\For\FormInterface', function()
{
    return new MyFormClass();
});

这里发生的事情是每次Laravel看到一个FormInterface类型的实例在控制器中暗示如果创建一个新的myFormFunction()并将其作为参数传递。通过使用接口,它为您的类依赖项提供了遵循的契约,以确保它们可以轻松交换而不会导致错误。所以说你的团队后来开发了一个新的改进的表单类,你只需更新你的绑定:

App::bind('Namespace\For\FormInterface', function()
{
    return new  MyNewFormClass();
});

我强烈建议您查看服务提供商,因为它们提供了管理包和IoC绑定的绝佳方法。有关服务提供商的文章可以在这里找到:

http://fideloper.com/laravel-4-where-to-put-bindings

您可以在此处阅读有关Laravel的IoC容器的更多信息:

http://laravel.com/docs/ioc

此外,如果您可以获得从Apprentice到Artisan的书的副本。高级应用程序架构使用Laravel 4,Taylor Otwell我强烈推荐阅读。它很容易理解并且真正详细地介绍了如何管理依赖注入。

希望有所帮助。

答案 1 :(得分:2)

如果你选择这条路线,我认为你会牺牲很多可读性。

最终,依赖注入只是一种允许可测试性的模式。外立面在没有注射的情况下很容易测试,所以我认为这样做没有多大价值......