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 !
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.
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...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With