Rationale behind Dependency Injection Container libraries

Ha - another bag of worms! I haven’t considered that but will read up on that. Seems like lots of controller classes then, I don’t know if I like it… Maybe better to do like Tom suggested in the other thread to have controllers depend only on the request and model objects? I think Symfony gives access to the whole application object in the controllers - could this be treated like a model? Or probably something more than a model? A big global holding access to the whole applications?

But it’s not generally “loading the entire library”, it’s constructing an object or an object graph. If doing that uses a substantial amount of resources, well, the constructors of those objects are doing too much and the problem isn’t really the fact that the object should be lazy loaded, it’s that the constructors shouldn’t be doing as much in the first place.

And let’s be clear, the logic for “Should I inject the object or not” might involve something more substantial than a single if statement (several function calls, possibly reflection, method_exists, etc).

That’s a really good point indeed! I hadn’t considered that.

Perhaps I misunderstood, what I mean, is that if you had your lazy-load mechanism that says “should the DB class be initialised or not?”, wherever that check is, is concerning itself with database-related internals that shouldn’t really matter outside of the database class. This is why it’s better not to lazy load, but have PDO connect JIT the first time it’s needed instead.

Might not be optimised and might not be needed by a specific class. I go always refer to this, but I’ll link to it again: http://misko.hevery.com/code-reviewers-guide/flaw-class-does-too-much/ If the object is hinted in the constructor and then not used, your class probably needs to be split into two.

Which is basically what Jeff just said here: :slight_smile:

I’m not sure about one action per controller, but one controller per set of closely related actions. For example, listing a set of records and deleting one of those records. It’s likely that after deletion you’ll want to show the list again and both actions will require accessing the list of records somehow (either directly via the database or through a repository of some kind)

Perhaps another misunderstanding - by the check to initialise I meant what a DIC is doing - reflecting hints to check what object to initialise and pass - except I meant it for controller methods and not only for the constructor. No need to look at database-related internals.

okay, but I was talking about the exact opposite - the object not being hinted in the constructor but only hinted in one of the methods - just like I showed in the code above. Is there anything wrong with such usage (apart from the fact that perhaps the controller shouldn’t be dealing with database objects, only a model object)?

Well, this distinction makes the whole difference - I think most people keep only closely related actions in one controller and that’s what I’ve always been doing. Jeff’s idea of separate controllers even for related actions seems like too much splitting to me.

Ah, I see. The only problem with the code you posted, is that whatever is calling the archive method needs to either construct, use a DIC to construct, or already have a constructed db2 instance… essentially just moving the problem up a level.

So now I get your original problem: Should we get the DIC to call the controller action, and inject the arguments? I think that’s a very interesting question… which I’m trying to understand how that might work and it’s an interesting concept.

Perhaps like this:

$controller = $dic->create('ProductController');
$dic->call($controller, $action);

That’s a very interesting approach and I can’t see any immediate downsides, I think that could be a really nice way of calling actions.

edit: Actually this is already possible with Dice, although it’s slightly less dynamic

$controllerName = 'ProductController';
$dice->addRule($controllerName, ['call' => ['archive', []] ]);
$controller = $dic->create($controllerName);

Yes, that’s what I meant! I think most common usage in popular frameworks is to construct dependencies in the controllers out of a container, which is basically a service locator. I’m thinking about moving it up one level and automating constructing those dependencies. I’ll try it out when I have some time to experiment with creating a new framework :smile:

The more I think about this, the more I think it’s a great idea :slight_smile: I’m going to implement it and see how I get on.

2 Likes

Great, don’t forget to report back your observations !

Well sorry to bump this thread. I am thinking about using a dependency injection container myself as well, so I can inject required dependencies into my controller and repository classes easily. The idea is that, my controller classes usually depend on one or multiple repository objects, while certain repository objects may also depend on other repository objects(if theres a foreign key). Below is an example that demonstrate that(I only show the constructors since these are the only one that matter):


class UserRepository{

    public function __construct(PDO $database){
            $this->database = $pdo;
        }
}

class PostRepository{
    public function __construct(PDO $database, UserRepository $userRepository){
        $this->database = $database;
        $this->userRepository = $userRepository;
    }
}

class CommentRepository{

    public function __construct(PDO $database, UserRepository $userRepository, PostRepository $postRepository){
            $this->database = $database;
            $this->userRepository = $userRepository;
            $this->postRepository = $postRepository;
        }
}

class PostController{

    public function __construct(UserRepository $userRepository, PostRepository $postRepository, CommentRepository $commentRepository){
            $this->userRepository = $userRepository;
            $this->postRepository = $postRepository;
            $this->commentRepository = $commentRepository;
        }
}

As you see, the dependency graph is kinda strange, largely because a comment has foreign keys user(poster) and post(where the comments belong), and post has foreign key user(poster). For this reason, the PostRepository depends on UserRepository, and CommentRepository depend on User and Post repositories.

If I use a dependency injection container, such as Dice, I will need to configure the dependencies using rules. Since I want the PDO, UserRepository, and PostRepository injected into the Controller and CommentRepository to be the same instance, while by default all DICs will just create new instances. The question is, where do I put my DIC configuration logic? If my Dispatcher class is responsible for creating controllers, should I put such logic inside the dispatcher? But imagine I have like 20 controllers and 50 repositories, the configuration logic will be very very long, using a single method for this will make it a God class with long method with more than 1000 lines of code.

Another question is, since my controller class depends on CommentRepository, which depends on PostRepository, which in turn depends on UserRepository, may I just inject the CommentRepository and get the other dependencies from the CommentRepository. But does this violate good OO design principles? It feels like courier antipattern to me. What do you think?

By doing this you’d be making your controller code dependent on the implementation of CommentRepository. What happens if you refactor the repository and it no longer uses some of those dependencies?

The other problem would be that your controller’s dependencies would not all be explicitly declared in the constructor/method signatures. You’d be using your CommentRepository like a service locator.

This is a good question. Generally speaking it’s better to put the DIC logic in its own file (or files) and include it when required. You mentioned Dice, which supports simple loading of JSON files. Since it uses arrays, it’s very easy to define Dice’s configuration in its own JSON file and import it.

I see, thanks for the advice. And yeah, I definitely realize that I will practically make the CommentRepository a service locator this way. I dont need SL, I need DI.

yeah, you make a good point, and I was thinking about the same thing too. So I can write the rules in JSON and load it by PHP, then send it to Dice as $rule parameter? Do you have an example for this?

The real problem here is your repositories. They should not be dependent on each other. By making them depend on each other all you are really doing is to make one massive class disguised as individual classes. And the whole thing will blow up once you add a few more database tables.

I suspect you are basically trying to share mapping information. Take a look at Doctrine 2’s design. Store the mapping information in a manager class which can then be accessed by individual repositories.

And do use an application configuration file for defing your services. Here is a yaml example for the Symfony dic:

  # =====================================================
  # Exporter
  cerad_project_tournament_export_command:
    class: Cerad\ProjectTournament\Export\ExportCommand
    tags:  [{ name: console.command }]
    arguments:
      - '@cerad_project_tournament_exporter_excel'

  cerad_project_tournament_export_action:
    class: Cerad\ProjectTournament\Export\ExportAction
    calls: [[setContainer, ['@service_container']]]
    arguments:
      - '@cerad_project_tournament_exporter_excel'
      - '@cerad_project_tournament_export_form'

  cerad_project_tournament_exporter_excel:
    class: Cerad\ProjectTournament\Export\ExporterExcel
    arguments:
      - '@cerad_project_tournament_export_repository'

  cerad_project_tournament_export_repository:
    class: Cerad\ProjectTournament\Export\ExportRepository
    arguments:
      - '@cerad_project_tournament_connection_dbal'

   cerad_project_tournament_export_form:
    class: Cerad\ProjectTournament\Export\ExportForm
    arguments:
      - '@cerad_project_tournament_connection_dbal'

So you are saying that repositories should not depend on each other, I see your point. But in this case, how can I load any related domain models? Lets say I have a Post domain model, which has an Author that should be another domain model. It can be either lazy loaded or eager loaded depending on the configuration of my PostRepository class. The question now is, how can a PostRepository class create a Post domain model with loaded Author/User property field? The User domain model has to come from somewhere, and if the PostRepository class does not have a dependency on UserRepository, it means that the PostRepository will have to create the User object on its own. But doesnt this violate good OO design principle? Since now you can create both a Post and User domain model with this repository.

Sorry but I am still a bit confused, I dont see any other possible solutions other than supply a dependency of UserRepository to the constructor of PostRepository. Can you elaborate a bit more? Thanks.

If you could post the link to your source code them I might be able to help out.

As it stands, I don’t understand the problem.

$blog = $blogRepository->find($blogId);
$author = $blog->getAuthor();

The above code should be simple to implement without having to inject a bunch of cross-dependencies.

From a big picture point of view, having class A depend on class B and class B depend on class A will often lead to problems.

Well in the above code, you are expecting that $blog->getAuthor() will work properly, but how? If BlogRepository does not contain a dependency of UserRepository(Author should be an instance of domain model User), then how is it supposed to create a User domain model just by calling $blogRepository->find($blogID)? Do you mean, the BlogRepository should be able to create a User domain model on its own? Like, writing a JOIN query and manually create the User object for $blog->author property? This is a part of the code in my PostRepository that generates a complete Post object, the loadModel($object) is called inside each findByXYZ method for repository to load the model:

// $object is a stdclass object generated from PDO::fetchObject(), which contains only data and is used only during model creation.
protected function loadModel($object){
    $post = new Post;
    $post->setID($object->id);
    $post->setUser($this->userRepository->find($object->user))
    $post->setTitle($object->title);
    $post->setContent($object->content);
    $post->setDatePosted(new DateTime($object->dateposted));
    $post->setStatus($object->status);
    return $post;
}

Actually I looked up an example with foreign key mapping in Martin Fowler’s book ‘Patterns of Enterprise Application Architecture’. This is how it is done in his example:

protected DomainObject doLoad(long id, ResultSet rs) throws SQLException{
    string title = rs.getString(2);
    long artistID = rs.getLong(3);
    Artist artist = MapperRegistry.artist().find(artistID);
    Album result = new Album(id, title, artist);
}

As you can see, my repository actually mirrors the mapper in Martin Fowler’s book. The differences are:

  1. ResultSet in Fowler’s book is specific to Java, while in my book I get a stdclass object to hold temporary data. But anyway, they both are just temporary data structure to transfer data from DB to model.
  2. Fowler’s Album class is simple enough so he passes the three fields to Album constructor, while I use setters since there are a lot more fields(dont want to have a constructor with 5+ parameters).
  3. Fowler uses Registry to fetch ArtistMapper for AlbumMapper to use, while I use dependency injection to push an instance of UserRepository to PostRepository, thus removing the need for Registry.

As you see, Fowler’s approach is essentially the same with mine, and my repository works even better since I am using dependency injection rather than relying on a static registry. I understand that by the time Fowler wrote the book(2002-2003), the concept of DI aint widely adopted so singletons and registries were common at that time. If Fowler rewrites the book today, he would definitely use dependency injection. Thus passing ArtistMapper to AlbumMapper as a dependency, like how I am passing UserRepository to PostRepository as dependency.

So can you illustrate by an example of how you would approach this problem, if PostRepository is not dependent on UserRepository?

This is a question that I’m also interested in getting an answer to. If entities are completely decoupled from any storage and database access mechanisms then if we want to use dependency injection then I can’t see how this is going to work:

This code should be rewritten to something like this:

$blog = $blogRepository->find($blogId);
$author = $blog->getAuthor($userRepository);

Otherwise the entity object is not able to load Author on its own. And even if we inject UserRepository like this and the blog entity can use it to fetch the author then we are beginning to violate SRP because now the entity is dealing with retrieving data. This starts to resemble Active Record.

The problem can be avoided if BlogRepository eager-loads the author (e.g. with a JOIN) but if we prefer lazy loading then I can’t see a way out other than add the responsibility for fetching more data into the blog entity.

The basic problem with your approach is that you have database mapping information scattered across multiple repositories.

Instead, consider having a single array in which you store the mapping information for Blog and Author as well as the fact that there is a relation between Blog and Author. Each repository has access to this mapping information which allows the Blog repository to create and link an Author object as needed. Likewise the Author repository will have no problem creating and returning blog posts as needed.

Try to imagine a more complicated domain with a dozen or so inter-related entities. Do you really want to inject a half a dozen or more repositories into each related repository?

Once again, I would urge you to look at some of the more successful existing ORM solutions such as Doctrine or Propel. Its not about following abstract patterns, it’s about generating useful and working code.

Yeah you do make a point, if a domain model has like 5+ dependencies on other different domain models, I will need to supply its repository’s constructor with 5+ other repositories. This can soon go out of control, and configuration scattered across multiple files sure is another problem.

But your proposed alternative has an issue as well. Since this array for mapping information is shared across all repositories, I feel that it has become some kind of service locator for the persistence layer. I’d suppose this array is created somewhere and passed as constructor parameter to all repositories. A non-static service locator does the same thing if you inject it to a class’ constructor, just the syntax is different. Maybe I am confused and missing something here?