1

I am looking for a better explanation of the view layer in MCV, and in particular how the flow in the program goes from controller to view, with focus on the state of the model when using a 1:1 relationship between controller and view.

In all examples I have seen data is being forwarded to the view from the controller, and the view does nothing specific that would require a specific view to be written for a specific controller. Have I misunderstood the 1:1 relationship mantra? The latest example I found was posted here some days back: https://stackoverflow.com/a/18983927/1681418

class View
{
   public function render($templateFile, array $vars = array())
   {
      ob_start();
      extract($vars);
      require($templateFile);

      return ob_get_clean();
   }
}

I have tried to create specific view classes for each controller, and I currently have a view that extracts all data from the model as it requires it. It is clean in the sense that I have a very defined do-stuff-to-the-model section (=controller) and a read-only-from-model section (=view). I have however a few shortcomings that I have yet to find a tidy solution for, namely:

  • Where should the template file be selected?
  • How does the view get to know about errors in the model?
  • How does the view get to know about successful or unsuccessful command/action in controller?
  • How do I change view when there is an error? Or how do I properly do my routing for the cases when a user state changes.

I have no trouble rendering correct output on my page, but my current approach feels wrong. **Anyone got an example of a view that uses domain driven design with the model as a layer, not a class? **

This answer is very similar to what I usually find, and I do not understand how this approach uses or requires a 1:1 relationship.

I am mostly looking for examples, not code review, but I have in any case extracted some pieces of my code below for examples. Here I am calling the controller via a dispatcher for access control and routing, then the view via the same dispatcher to again check for access. The view in turns calls different presentation objects that assigns data to the template engine if http request, json if ajax request.

class Controller
{
    public function login()
    {
        $this->serviceFactory
            ->build('recognition')
            ->authenticate($this->request->username, $this->request->password);
    }
}

class View
{
    public function login()
    {

        /** Prepare server response (i.e. state of the model) */
        $this->presentationObjectFactory
            ->build('serverresponse', true)
            ->setPresentationName('success')
            ->assignData($this->serviceFactory->build('modelLog')->getModelResponse('success'));

        /** Get current visitor information */
        $this->presentationObjectFactory
            ->build('visitor', true)
            ->assignData($this->serviceFactory->build('recognition')->getCurrentVisitor()); 

        return $this->serviceFactory->build('recognition')->getCurrentVisitor()->isLoggedIn() ? 
                    $this->indexAction() : /* Reroute to index of view */
                    $this->display('login.html'); /* Show the login template when unsuccesful login*/
    }
}

class PresentationObject
{
    public function assignData(Collection $visitors)
    {
        $dateformat = new DateFormat();
        $dateTime = new \Datetime();

        foreach($visitors as $visitor)
        {
            $dateTime->setTimestamp($visitor->timestamp);

            $this->assign_block_vars('visitor', array(
                'ID'                => $visitor->id,
                'USERNAME'          => $visitor->user->Username,
                'IP'                => $visitor->remote_addr,
                'HTTP_USER_AGENT'   => $visitor->http_user_agent,
                'LAST_SEEN_ONLINE'  => ucfirst($dateformat->formatDateDiff($dateTime)),
                'DEVICE'            => $visitor->getDevice(),
                'PLATFORM'          => $visitor->getPlatform(), 
                'BROWSER'           => $visitor->getBrowser(),  
            ));
        }
    }
}

My knowledge and understanding of MVC and domain driven design is strongly influenced by the user tereško, but I have probably misunderstood something on the View part of this explanations...

Community
  • 1
  • 1
bblue
  • 545
  • 5
  • 24
  • The [templates](http://codeangel.org/articles/simple-php-template-engine.html) should be chosen by current view, based on data that you extracted from model. Error-state (which would be triggered by failed command from controller) can be one form of said data. If you encounter error, when opening nonexistence article, that can be handled in two ways: view sending a *HTTP Location* header or view choosing, instead of document displaying template, some template for communicating an error message. – tereško Oct 13 '13 at 00:07
  • @tereško What purpose does injecting the view to the controller then serve? Is it simply an architectural decisions for pulling vs. pushing data to the view? I see in your post here: http://stackoverflow.com/questions/5863870/how-should-a-model-be-structured-in-mvc/5864000#5864000 that you are injecting the View into the controller. – bblue Oct 13 '13 at 01:38
  • 1
    The current view gets injected in controller because the user's commands are not always targeted at domain model. Take for example: collapsible widgets. If you implement them with PHP as fallback option (in case if JS is not available), then expanding or collapsing the widget would be purely *UI logic*. Controllers can not only change the state of model, but also (in rare cases) the state of view. Which is why controller has a view as a dependency. – tereško Oct 13 '13 at 02:54
  • 1
    As for "pulling or pushing". IMHO, it boils down to flexibility. If your controller has an additional responsibility to provide view with data, then you have added another reason for change. If you change something in a view, now you also need to alter the controller which handles populating it with data. Unfortunately that is not the case with *php frameworks*; they actually tend to not have views, only templates and merge the responsibilities of view in the controller. – tereško Oct 13 '13 at 03:04
  • 1
    You should read this first: http://r.je/mvc-php-front-controller.html – Yang Oct 14 '13 at 08:19
  • @DaveJust That was an interesting read. I found [this article](http://r.je/views-are-not-templates.html) on the same site that was also very helpful in explaining the confusion around Views and responsibilities of MVC. In all, that website was a super reference point I will use later. – bblue Oct 14 '13 at 20:52
  • @birdieblue Take a look also at, http://poincare.matf.bg.ac.rs/~andjelkaz/pzv/cas4/mvc.pdf – Yang Oct 15 '13 at 07:12

1 Answers1

1

What purpose does a 1:1 relationship between controller and view serve?

There is no need for a strict 1:1 rule if the view can be applied in multiple workflow contexts / controllers / models. Keeping a view and controller separate, even if they are only used together and can be merged, is a best practice for a clear separation of responsibilities. It also makes it easier to swap and share views later.

Where should the template file be selected?

In your case you have a View class, so it should be defined there. In some systems the template is the view and is often selected in the controller or configuration files.

How does the view get to know about errors in the model? How does the view get to know about successful or unsuccessful command/action in controller?

In some architectures the models return their issues to the controller during updates or any other actions. In the controller I usually add any problems to a user message stack. Then in the view I output those messages to the user.

How do I change view when there is an error? Or how do I properly do my routing for the cases when a user state changes.

This I've seen handled in quite a few different ways. The most robust solution is for your controller to pass the next workflow steps to the view. The view should basically stay as agnostic as possible to any business logic.

Any example code would be too long and elaborate for SO. I would start with good MVC framework tutorials:

Matt S
  • 14,976
  • 6
  • 57
  • 76
  • Care to send me some real life examples for the last two points that I could look at offline of SO? I've come to understand that my approach to date is more or less sound, but my code for that part is really messy and quite possibly the source of my grief. – bblue Oct 14 '13 at 20:59
  • 1
    All of my own real life examples are owned by my clients, so I can't share them. But I've added a few links to how some frameworks handle validation, which should help explain my point. Unfortunately I've never seen a really good rules / workflow example on the internet (with clean MVC). They're usually very specialized and complex. – Matt S Oct 14 '13 at 21:18