SitePoint Sponsor

User Tag List

Results 1 to 15 of 15
  1. #1
    SitePoint Addict lundberg's Avatar
    Join Date
    Mar 2003
    Location
    Sweden
    Posts
    370
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    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!

    Martin Lundberg
    Sweden

  2. #2
    Twitter: @AnthonySterling silver trophy AnthonySterling's Avatar
    Join Date
    Apr 2008
    Location
    North-East, UK.
    Posts
    6,111
    Mentioned
    3 Post(s)
    Tagged
    0 Thread(s)
    Sounds like a case for Dependency Injection to me, but I'm probably wrong!
    @AnthonySterling: I'm a PHP developer, a consultant for oopnorth.com and the organiser of @phpne, a PHP User Group covering the North-East of England.

  3. #3
    SitePoint Addict lundberg's Avatar
    Join Date
    Mar 2003
    Location
    Sweden
    Posts
    370
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by AnthonySterling View Post
    Sounds like a case for Dependency Injection to me, but I'm probably wrong!
    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 However I can't do that with the more specific dependencies like the User object.

    Martin Lundberg
    Sweden

  4. #4
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    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.

  5. #5
    SitePoint Addict lundberg's Avatar
    Join Date
    Mar 2003
    Location
    Sweden
    Posts
    370
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken View Post
    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.

    Martin Lundberg
    Sweden

  6. #6
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by lundberg View Post
    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:

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

  7. #7
    SitePoint Addict lundberg's Avatar
    Join Date
    Mar 2003
    Location
    Sweden
    Posts
    370
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken View Post
    You can tell Phemto to use a specific concrete instance when instantiating a given class. If I recall correctly, the syntax is:

    PHP Code:
    $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.

    Martin Lundberg
    Sweden

  8. #8
    SitePoint Addict lundberg's Avatar
    Join Date
    Mar 2003
    Location
    Sweden
    Posts
    370
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    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?

    Martin Lundberg
    Sweden

  9. #9
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by lundberg View Post
    Now using Phemto I want it to give UserController the User class, however Phemto won't know which one to give me.
    Presumably by typehinting in the constructor of UserController. Eg.:

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

    Quote Originally Posted by lundberg View Post
    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?
    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.

  10. #10
    SitePoint Guru
    Join Date
    Jun 2006
    Posts
    638
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Not sure if this helps, but this is what I'm doing:
    PHP Code:
    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:
    Code:
    /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.

  11. #11
    SitePoint Addict lundberg's Avatar
    Join Date
    Mar 2003
    Location
    Sweden
    Posts
    370
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken View Post
    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.
    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.

    Martin Lundberg
    Sweden

  12. #12
    SitePoint Addict lundberg's Avatar
    Join Date
    Mar 2003
    Location
    Sweden
    Posts
    370
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    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? It should still be testable.

    Martin Lundberg
    Sweden

  13. #13
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by lundberg View Post
    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.
    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:

    PHP Code:
    $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:

    PHP Code:
    $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.

    Quote Originally Posted by lundberg View Post
    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? It should still be testable.
    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.

  14. #14
    SitePoint Addict lundberg's Avatar
    Join Date
    Mar 2003
    Location
    Sweden
    Posts
    370
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    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

    Martin Lundberg
    Sweden

  15. #15
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by lundberg View Post
    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 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.


Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •