I have been reading a lot about dependency injection recently, and in theory it has made a lot of sense. The idea of having easy to test, single responsibility classes just sounds smart. However, I'm struggling with how far to take it.
I'm working on a PHP web application right now that has a CMS component and is heavily database driven. Within the CMS, you can create pages, and the pages themselves are built using various widgets. The widgets can be straight HTML (from a WYSIWYG editor), or can be a little more complex, like a photo gallery. And this is the important part, the photo gallery widget depends on other db models, like the PhotoGallery and PhotoGalleryImages in order to function properly.
According to Miško Hevery, I should not be passing references to dependencies through the different layers of my application. Instead, each class should simply "ask for" whatever dependencies it requires. Using his example, this is how this looks:
$db = new Database()
$repo = new UserRepository($db);
$page = new LoginPage($repo);
While I can see this working fine for the service layers of my application, I really don't understand how this would work with my value objects/entities. It seems to me that this pattern requires me to instantiate all my models in the highest layer of my application. However, how I can I instantiate all my widgets at that level, when I need my page class to tell me what widgets I need to instantiate? And without knowing what widgets I'm creating, how can I know what widget dependencies need to be created and injected in?
In theory DI makes a lot of sense to me. However, actually implementing this pattern in my new web application is proving to be more difficult. Is there still something I'm missing with respect to DI and IoC? Thanks!
Update: Response to Tandu
Thanks a lot for the response Tandu. I think that DI may not actually be my problem here, because I think I have a very clear understand of what it is, whether it be constructor or setter injection, or whether it be done using a container or the poor man's way. What I do think is happening is that DI is challenging me to rethink how I'm currently programming. I think my OOP design is the problem. To illustrate this, here is how I would have normally programmed this problem:
class Page
{
public $id;
public $name;
public function widgets()
{
// Perform SQL query to select all widgets
// for this page from the database, and then
// return them as Widget objects.
}
}
interface Widget
{
public $id;
public $page_id;
public $type;
public function widgetize();
}
class PhotoGallery_Widget implements Widget
{
public $id;
public $page_id;
public $type;
public function widgetize()
{
$gallery = new Photogallery();
foreach($gallery->images())
{
// Create gallery HTML code
}
}
}
// Finally, to create the page, I would:
$page = new Page(1);
foreach($page->widgets() as $widget)
{
$widget->widgetize();
}
Clearly there are some issues here. The Page model depends on the Widget models. The PhotoGallery_Widget model depends on the PhotoGallery model, and even further the PhotoGallery model depends on the PhotoGalleryImages model. The thing is, developing this way has worked well for me. As I get deeper and deeper into the layers of my application, each layer takes on the responsibility of creating the objects it requires. Introducing DI throws a major wrench into my way of thinking. However, I want to learn how to do this properly. Just because this works for me right now, doesn't mean I should continue doing it this way.
You mention using factories. But don't factories actually break DI because they are instantiating objects?
You may also notice that my models have the responsibility of interacting with the database. I suspect that this is also a problem with my design. Should I be using data mapping of some sort to remove this responsibility from my models?
Given this more specific example of how I'm currently implementing my code, do you have any other recommendations or can you further illustrate how I should be doing it differently?