2

My team likes the idea of constructor-injected dependencies because it makes deps very clear when looking at a class. With the use of the facades, I'm aware they can be mocked and swapped, but one would have to examine every line of a class to figure out what it depends on! I discovered that I could find the true class behind the facade with, for instance, Form::getFacadeRoot().

The controller code that I've ended up with is:

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;
    }

        ...
}

When my test does $this->client->request('Get', '/');, it errors out:

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

Am I on even close to the right track here? I'm sort of making this up as I go along because I don't see much discussion on this issue. Feel free to comment on my reason for even trying; I could be sold on facades, yet.

Thanks !

2 Answers 2

7

You need to map the class dependencies to a class using Laravel's IoC container. This can be done using the App facade. So in your example above with the constructor

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

You would create a binding that would look something along the lines of:

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

Taylor Otwell recommends using Interfaces as contracts for the class dependencies. So Ideally your finished code would look something like that below (I've slimed it down a bit for the example).

For your controller:

use Namespace\For\FormInterface;

class HomeController extends BaseController {

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

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

For the interface:

namespace Namespace\For;

interface FormInterface(){

    public function myFormFunction()
}

The class to be injected:

use Namespace\For\FormInterface;

class MyFormClass implements FormInterface{

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

And then finally you create the binding that brings it all together:

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

What's happening here is every time Laravel sees an instance of FormInterface type hinted in a controller if creates a new myFormFunction() and passes it in as the param. By using interfaces it gives your class dependencies a contract to follow to ensure that they can be easily swapped without causing errors. So say your team later develops a new and improved form class you would simply update your binding like so:

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

I would highly recommend looking into Service Providers as they provide an excellent way to manage packages and IoC bindings. A good article on Service Providers can be found here:

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

And you can read more about Laravel's IoC container here:

http://laravel.com/docs/ioc

Furthermore if you can get your hands on a copy of the book From Apprentice to Artisan. Advanced Application Architecture With Laravel 4, by Taylor Otwell I would highly recommend a read. Its easy to follow and really goes into detail about managing dependency injection.

Hope that helps.

Sign up to request clarification or add additional context in comments.

Comments

2

I think you're going to sacrifice quite a bit on readability, if you choose this route.

Ultimately, dependency injection is just a pattern to allow for testability. The facades are easily testable without injection, so I don't see much value in doing this...

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.