Search code examples
phpdesign-patternsmodel-view-controllermodelservice-layer

PHP MVC: Share model between controller and view


I'm working on my PHP (H)MVC project in which I separated the views from the controllers - as in the answer How should a model be structured in MVC?. Their relationship is 1:1, so they have the same "actions". Therefore, in bootstrap.php, after I instantiate them I call:

// ... Controller and view are already instantiated.
call_user_func_array(array($controller, $actionName), $actionParameters);
call_user_func_array(array($view, $actionName), $actionParameters);

Let's say that a controller and a view become, each of them, a model (domain object) as constructor parameter. Using Auryn dependency injection container, I try to share the same instance of the model between the controller and the view, without instantiating it beforehand. E.g. before controller and view instantiation takes place in bootstrap.php.

In his answer, tereško describes the use of a model/service factory. But as a "Note" he says:

...A much better implementation would have the DI container (like Auryn) to create controllers and views, with only the required services, instead of using a factory.

My question is: Can I implement this functionality without a model factory using the dependency injection container? I'm kind of stuck in this task and I don't really know if this is somehow possible. Thank you.


Solution

  • Yes, you can.

    But it's kinda fiddly. You basically need to set up the service as "shared":

    <?php
    $injector->define('MailerService', [
        ':server' => 'fak.it',
        ':port' => '443',
    ]);
    $injector->share('MailerService');
    
    $controller = $injector->make('FooBarController');
    

    This assumes that you controller was defined kinda like this:

    <?php
    class FooBarController 
    {
        public function __construct(MailerService $service) 
        {
            // ...
        }
    }
    

    In this aspect the Symfony's standalone DI component is a bit easier to use, because you can put this kinda of configuration in a json or yaml file.

    P.S. You probably should abstract your user input as some sort of Request object ant pass that in your controller on each method-call.

    Kinda like this:

    <?php
    $request = new Request( .. something here maybe .. );
    $controller->action($request);
    

    Make for a bit nicer looking code :)