FrontController and specific handler dependencies

Hello everyone,

I’ve read several threads but I’m having some problems thinking about this.

My FrontController receives a request which a router routes to a seconds controller like UserController for example. I can inject general dependencies like a config object, a request object, etc but what about objects which this specific controller method use?

For example my UserController may want to use a User (a model object) to fetch user(s) and list/update/add etc.

Since I want to be able to test this I can’t just create them. Is this where Factories comes in? I don’t know much about factories yet.

Thanks in advance!

Sounds like a case for Dependency Injection to me, but I’m probably wrong! :smiley:

Dependency Injection is a big subject. Could you be more specific? For example I am using dependency injection with the general dependencies by injecting them in the constructor like I said :slight_smile: However I can’t do that with the more specific dependencies like the User object.

Since your components (controllers) aren’t known until at runtime, you need some sort of factory, if you want to inject dependencies. A dependency injection container is a type of factory.

In Konstrukt, the creation of controllers is encapsulated in a factory (a k_ComponentCreator), which may use a DI-container to create the controller. Thus your controllers can have their dependencies passed in the constructor. If you use a reflection-based DI-container, it all happens automagically.

I saw the link to Phemto in your documentation and I was wondering. Is there a way to say for interface IInterface use MyClass class. From Phemto docs I can see you can only do willUse(‘MyClass’) and MyClass will be used when I do $phemto->instatiate(‘Foo’) if Foo takes a IInterface but then if I have two classes which both implement IInterface (but one of them also implements IInterface2 and should be use in some other way) I don’t know which one is fetched.

You can tell Phemto to use a specific concrete instance when instantiating a given class. If I recall correctly, the syntax is:


$injector->whenCreating('Foo')->willUse('MyClass');

Now it hit me that I’ve got a lot of model classes which my controllers use. UserController uses the User class, PageController uses the Page class. They all extend an Entity class.

Now using Phemto I want it to give UserController the User class, however Phemto won’t know which one to give me.

Also now I have to pass the Phemto object around to every method to be able to use ->instatiate() or how do you solve that problem?

Presumably by typehinting in the constructor of UserController. Eg.:


class UserController {
  protected $user;
  function __construct(User $user) {
    $this->user = $user;
  }
}

Split your application into shared objects and transient objects. Shared objects are stuff with a lot of dependencies. Make sure that they don’t have any state. Put state in the transient classes, but keep them free of dependencies on shared objects. Then only use dependency injection to manage shared objects.

For example, instead of an active record pattern, use a table data gateway+row data gateway pattern or a data mapper pattern.

Not sure if this helps, but this is what I’m doing:


class UserController extends Controller {
  protected $user;
  function __construct(array $route, array $data = array()) {
    $this->user = $data['user'];
    parent::__construct($route, $data);
  }
} 

class GalleryController extends Controller {
  protected $user;
  protected $gallery;
  function __construct(array $route, array $data = array()) {
    $this->user = $data['user'];
    parent::__construct($route, $data);
  }

  public function viewAction($id) {
    $this->gallery = Galery::loadForUser($this->user, $id);
  }
} 

That way, I can have links like so:

/user/gallery/view/123

Where user and gallery are controllers, view is an action, and 123 some argument.

The passed in data is an array of variables to be passed from one controller to the next, and the route, an array of segments in the route. (split the URL by /)

If anyone has a better way of passing the data from one controller to the next, please share.

Thanks for taking your time to answer but could you explain these concepts some more? I’m not sure what a transient classes is or if you send your phemto object arround.

Wouldn’t it be okay to make the phemto object a singleton and globally accessible? Then I could use injection through constructor most of the times but also access the phemto object and get objects is wanted? :slight_smile: It should still be testable.

OK. I probably went a little fast over that. Basically, the idea is to separate the concepts of application state and side-effects.

Let’s take a database abstraction layer as an example. One solution would be a so-called active record. The following might be an example of that:


$user = new User();
$user->name = "John";
$user->save();

Here, the user entity has two responsibilities: It holds the state (Eg. the name “John”), and at the same time it has the behaviour to persist to the database. So you have state and side-effects coupled together.

Another approach is to separate those two. For example:


$user = new User();
$user->name = "John";
$user_gateway->save($user);

It looks almost similar, but with the key difference that all the state is encapsulated in a local (transient) object without any side effects - All the side effects are contained in a separate object (the gateway).

If you keep state and side-effects separated, you can make the objects with side-effects into shared objects. Whether you use DI or some kind of global strategy for distributing shared objects, this makes testing easier and generally tends to make your code looser coupled and easier to comprehend.

That depends on your definition of OK. A global strategy can work, but I find that the way that DI forces you to keep state and side-effects separate makes your applications better.

The “problem” with that is that you have to create another file for every entity. As we have it now makes it very easy to just create a new entity class add some fields and then you can fetch/save/delete entities very easily without creating another class.

I guess this has been discussed and argued a lot allready :slight_smile:

I honestly fail to see the issue. Create one or two classes. What’s the big deal? If it’s trivial enough, you can always create abstract classes or use code generation.