MVC and dependency injection, forced to use singleton Controller?

I am working on building a PHP framework that behaves according to MVC principles and uses dependency injection. I think I have a front controller block; there is a working router that instantiates the controller and invokes the appropriate action based on the requested URI.

Next up is dependency injection. I want to implement a container that resolves dependencies using reflection. That being said, I think I am having problems with my controllers.

There are several things I call "system dependencies" that must be made available to derived controller classes. I haven't created all of these dependencies yet, but it seems reasonable that controllers have access to services like InputProvider (to encapsulate get / post parameters or command line arguments) and possibly Output dependencies. Ideally, I would use a framework Container to inject these dependencies into the controller constructor, but this is where I ran into problems.

If I use constructor injection for system dependencies in a controller, then I force derived controllers to manage the base controller's dependencies if they implement the constructor itself. This is apparently not the most convenient one. Another option is to use setter injection for system dependencies, but then derived controllers won't have access to those system dependencies if they need them in their constructor.

The only solution I see that offers the best of both worlds is to make my controllers stand alone. They must have a private constructor, so I can safely use setter injection without worrying about derived class constructors. Instead, there is an overridden initialize () method (assuming I am triggering a method injection somehow), which basically acts as a constructor (like an initializer for a derived controller). Thus, constructor injection is replaced by the initialize () method injection method, where all system dependencies will be available without requiring the derived controller to manage them.

But then a quick Google search seems unanimous that single controllers are bad practice. I am very unsure how to proceed. I probably overestimate this, but not wanting my application to be reliable and maintainable, I also see it as a little exercise in applying best practices, so I would like to do "right".
I believe the best practice in this case would be to delegate responsibility for managing the required system dependencies to a derived controller. The dependency should probably only be created if that controller actually has a need. Why inject an InputProvider into the base controller when it's possible the derived controller is never going to use it? But at the same time, I keep getting back to user friendliness and how nice it is to have a member always available $this->input

, for example in an environment like CodeIgniter.

I appreciate any and all contributions to my dilemmas. I also apologize for the wall of text, but I couldn't think of any code examples that would make the explanation easier, since this is all so abstract to me right now!

Regards,
Seriously Torn Individual

+3


source to share


1 answer


Several solutions are possible:

  • disallow controllers from using __construct()

    : make it private publicly definitive and force controllers to override something like init()

    and call it from the constructor. Then the constructor will inject all the dependencies (reflection? Other stuff?) So they are all ready in init()

    .

  • you can use an existing DI library like PHP-DI (disclaimer: I'm working on it), which will allow you to define dependencies, but they are available in the constructor (magically, yes).

Something like that:



<?php
use DI\Annotations\Inject;

class FooController {
    /**
     * @Inject
     * @var Bar
     */
    private $bar;

    public function __construct() {
        // The dependency is already injected
        $this->bar->sayHello();
    }

    public function setBar(Bar $bar) {
        return $this->bar = $bar;
    }
}

      

For example, this is how I work with Zend Framework 1. I cannot use constructors, so I add to properties. Here is the ZF1 integration project .

+1


source







All Articles