• 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Separation between Controller and View

#1
[eluser]7bit[/eluser]
Hi,

I've been playing around with CI for 2 days now and have a question about the "best practise" for implementing the view:

I have seen examples like this:

Controller:

Code:
$this->load->model('foo');
$this->load->model('bar');
// do some stuff maybe even modify
// some data in the model if it was a POST request

// [...]

// prepare and load the view
$data['bar'] = $this->bar->get_some_data();
$this->load->view('someview', $data);

And inside the view:

Code:
<html>
<head>
</head>
<body>
  <?= $bar ?>
</body>
</html>

Now, according to what I have read about MVC, the view should always be responsible for pulling its data out of the model on its *own*. This would mean that in the above example the 'view' part of the MVC is actually starting in the second part of the controller where the data array is being set up or maybe even earlier when data is pulled out of the model.

This lead me to the conclusion that it actually had to be like this:

Controller:

Code:
// manipulate the model or
// do NOTHING

// load the appropriate view
$this->load->view('someview')

And in the view:

someview.php
Code:
<?
$this->load->model('foo');
$this->load->model('bar');
// pull all necessary data
// but do NOT modify the model
// [...]
$data['bar'] = $this->bar->get_some_data();
$this->load->view('someview_template', $data);
?>

someview_template.php
Code:
<html>
<head>
</head>
<body>
  <?= $bar ?>
</body>
</html>

If I do it that way the I coud have views that can include or load other views like for example:
Code:
<html>
<head>
</head>
<body>
  <div id="menu">
    &lt;? $this->load->view('menu') ?&gt;
  </div>
  <div id="content">
    &lt;?= $content ?&gt;
  </div>
&lt;/body&gt;
&lt;/html&gt;

and menu would be a pair of view files like above, the first will pull the menu structure out of the db and maybe determine what is the current page to be highlighted or folded out and the second one would contain some php for a simple loop over an array and the html needed to display it.

No controller would ever need to know anything about all the possible sub-views, they would be completely self-contained and all that my controllers ever had to do was reacting to user input, manipulating the model if necessary and selecting the appropriate view, give it only minimal necessary data like only the ID of the record to be displayed and the view would be completely autonomous.

Would this violate any fundamental design principles? Is there a better solution for things like this? What would be the official CI way to do such things like nested view components? To me this approach fits perfectly into the MVC pattern.

#2
[eluser]Colin Williams[/eluser]
Quote:No controller would ever need to know anything about all the possible sub-views, they would be completely self-contained and all that my controllers ever had to do was reacting to user input, manipulating the model if necessary and selecting the appropriate view, give it only minimal necessary data like only the ID of the record to be displayed and the view would be completely autonomous.

Makes a great case. I don't think you need to convince yourself any further.

Quote:Would this violate any fundamental design principles?

I treat views as moronic templates that just know how to format the data they are given. They don't call models, and are typically just some form of markup language mixed with variables, conditions and loops. This style and your proposed style are just different, not necessarily wrong and right.

Quote:What would be the official CI way to do such things like nested view components?

There really are only a few "official CI way[s]" of doing things (overloading libraries, routing, etc). Don't concern yourself with an artificial "CI way" because they only exist in situations where you're altering core functionality. You can pretty much organize and design your application as you see fit. I think a lot of newcomers stumble here and constantly worry that they're breaking some sort of CI law. Ignore CI and just stick to more abstract design principles (like DRY, for instance).

Quote:To me this approach fits perfectly into the MVC pattern.

MVC is very interpretive. Lot's of things fit into an MVC pattern (if not everything). You'll often see programmers exalt that they've discovered X program is actually MVC "when you think about it this way." You can look at a tree outside and break it down into an MVC pattern. Pick a path and stick with it.

#3
[eluser]Mirage[/eluser]
I work the same way Colin does and I think that most CodeIgniters do.

But your approach shows an interesting alternative approach and it makes a more clear distinction between view and template.

The part that makes it a bit confusing is that in your model, views are supposed to 'read' the model, whereas if you were to write to it, you'd do that in the controller. So while you're consolidating subviews in your model your splitting some intelligence between view and controller. The read-only access cannot be enforced so it'd require good discipline to code that way.

Other than that, I too would say - If this is the way you think about the process, stick with it. That's the beauty of CI - it doesn't tend to force you to adopt the MVC interpretation of the framework developers.

Oh - and welcome to CI!

Cheers -
m

#4
[eluser]Colin Williams[/eluser]
I suppose the general guideline to follow is "Views should not alter the state of the model." Or as Mirage put it, read only. The difference, then—whether the read happens in the controller and is then passed to the view, or if the view calls one of the available read methods—is quite minimal.

If I were going to argue for the former method, I'd say that the conditions of the read method could be better maintained and controlled in the controller. The alternative (as you pointed out) is passing these conditions on for the view to use. So again, you can really have it either way. Although, with the latter, you're shifting a bit of responsibility on to the view. Not sure if that's a good or a bad thing. Depends on the environment.

#5
[eluser]7bit[/eluser]
The idea with the "intelligent" view came when reading a discusson somewhere (don't remember which forum) about the MVC pattern in general and its use in most of the web frameworks. Someone said: In *true* MVC the controller doesn't push data into the view, insted the view has an observer relationship with the model and pulls it's data out of it whenever the model changes, and it does this without interacting with the controller. The controller should only deal with user *input*. The conclusion someone could draw from this discussion would be that most frameworks that do it like CI aren't true MVC but something else. (not necessary something wrong but just something else)

Since it is in most cases not possible or practicable to notify the view directly about changes in the model the closest one can get to this pattern is to simply regard every page request as notification for the view that the model *may* have changed and it is time to pull the current state and display it.

It was just my attempt to see whether those OOP gurus in this discussion were right and MVC is really a different thing or whether one could just move some code around and have a "better" MVC without changing the way the framework works. I'm not sure which way it is really better, i was just thinking about multiple controllers loading the same (part of the) view and having all relevant logic for this part of the view in one place together with the view. This *may* make parts of the application more modular.

I have some free time and I'm just experimenting. Yesterday evening I spontaneously decided to write my own ultra-small bare bones mini MVC framework. Heavyly inspired by CI and Kohana i hacked together just the bare minimum to achieve the routing of URIs to controllers, some autoloading of classes, the cascading, etc., just a few hundred lines of code. Nothing special, and then while I pondered about the mechanisms that drive the views I had an idea: The whole problem with view partials and repeating view-related code in the controller or in different views comes from the fact that all those views work *procedural*. Why not implement override polymorphism in view templates? Just make all views classes that can inherit from each other and let them extend existing views, override parts of the parent view with their own version and so on. PHP is a full blown *template* language and it's object oriented, so why not use it to its full potential when it comes to *templates*?

Consider the following view template for my (not yet existing) template engine:
Code:
&lt;?class V_index extends Polytemplate{function part_0(){?&gt;
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

    &lt;html &gt;
    &lt;head&gt;
    &lt;title&gt;Conforming XHTML 1.0 Strict Template&lt;/title&gt;
    &lt;/head&gt;
    &lt;body&gt;

&lt;?}function part_1(){?&gt;
    <div>part_1: Hello world!</div>

&lt;?}function part_2(){?&gt;
    <div>part_2: &lt;?=$this->data->foo?&gt;</div>

&lt;?}function part_3(){?&gt;
    <div>part_3: &lt;?=$this->data->bar?&gt;</div>

&lt;?}function part_4(){?&gt;
    <div>part_5: End.</div>

&lt;?}function part_999(){?&gt;
    &lt;/body&gt;
    &lt;/html&gt;

&lt;?}}?&gt;

it inherits a constructor from Polytemplate:
Code:
&lt;?php
class Polytemplate{
    function __construct($data = null){
        $this->data = $data;
        $parts = get_class_methods($this);
        sort($parts);
        foreach ($parts as $key => $method){
            if (substr($method, 0, 5) == 'part_'){
                $this->$method();
            }
        }
    }
}
?&gt;
All methods in the view that begin with 'part_' will be called in alphabetic order (therefore their names contain numbers) when the class is instantiated, the resulting html will go to the browser or the output buffer in the correct order.

Now consider this:
Code:
&lt;?class V_index2 extends V_index{

// this class will
// * inherit header, footer and part 4
// * decorate part1
// * remove parts 2 and 3
// * add a new part 2a

function part_1(){?&gt;
    <div style="color: green;">
        &lt;?parent::part_1()?&gt;
    </div>

&lt;?}function part_2(){?&gt;
&lt;?}function part_3(){?&gt;
&lt;?}function part_2a(){?&gt;
    <div style="color: red;">
        <b>&lt;?=$this->data->bar?&gt; &lt;?=$this->data->foo?&gt;</b>
    </div>

&lt;?}}?&gt;
This really works! This is fun! Imagine what you could do with it! I have to play with this for a while, but I think it is a great improvement over the procedural style used in CodeIgniter and many other frameworks.

#6
[eluser]nmweb[/eluser]
Template inheritance is a very good concept although this implementation would not be mine by choice. I'd move it out of the php realm and use some custom syntax like Django has:
Code:
{% extends "base_generic.html" %}

{% block title %}{{ section.title }}{% endblock %}

{% block content %}
<h1>{{ section.title }}</h1>

{% for story in story_list %}
<h2>
  <a href="{{ story.get_absolute_url }}">
    {{ story.headline|upper }}
  </a>
</h2>
<p>{{ story.tease|truncatewords:"100" }}</p>
{% endfor %}
{% endblock %}

Concerning MVC and pushing to the view and pulling by the view I think you're right. Remember the whole paradigm wasn't created for the web but rather for normal applications and the statelessness of http brings some problems to MVC, aptly solved by using the view for pulling from the model. Nevertheless, personal preference plays a big part here.

#7
[eluser]Rick Jolly[/eluser]
[quote author="7bit" date="1221341393"]
No controller would ever need to know anything about all the possible sub-views, they would be completely self-contained and all that my controllers ever had to do was reacting to user input, manipulating the model if necessary and selecting the appropriate view, give it only minimal necessary data like only the ID of the record to be displayed and the view would be completely autonomous.
[/quote]
I like your thinking. Maybe checkout Modular Extensions (HMVC) if you haven't already. It's a similar take on what you've described. I see the difference like this:

Your take:
Code:
Controller -> View Code -> View Template -> View Code -> View Template
                                         -> View Code -> View Template
Modular Extensions:
Code:
Controller -> View Template -> View Code (Module) -> View Template
                            -> View Code (Module) -> View Template
                            -> View Code (Module) -> View Template

Modular Extensions might be a little more consistent. Of course, if you were to load the main view HMVC module from the controller, it would be exactly the same as your method. However, often the main view does require a lot of info from the controller (validation fields/messages for example), so it might be more difficult to get that seperation between the controller and the main view. Partials are usually a different story.

#8
[eluser]7bit[/eluser]
[quote author="nmweb" date="1221441614"]Template inheritance is a very good concept although this implementation would not be mine by choice. I'd move it out of the php realm and use some custom syntax like Django has:
Code:
{% extends "base_generic.html" %}

{% block title %}{{ section.title }}{% endblock %}

{% block content %}
<h1>{{ section.title }}</h1>

{% for story in story_list %}
<h2>
  <a href="{{ story.get_absolute_url }}">
    {{ story.headline|upper }}
  </a>
</h2>
<p>{{ story.tease|truncatewords:"100" }}</p>
{% endfor %}
{% endblock %}
[/quote]

Implementing a template language interpreter in another template language seems like an unnecessary waste of resources to me. To me this feels like (re)implementing php-reloaded in php with absolutely no benefit. The only advantage would be having {% %} instead of &lt;? ?&gt; and some minor syntactic sugar at an incredible high cost in terms of performance and complexity. Your example would 1:1 translate to the following if done in pure php:
(untested)
Code:
&lt;?class template extends base_generic.php{

function part_0_title(){?&gt;
  &lt;?=$this->data->section->title ?&gt;
&lt;?}

function part_1_content(){?&gt;
  <h1>&lt;?=$this->data->section->title ?&gt;</h1>

  &lt;? foreach ($this->data->story_list as $i => $story){?&gt;
    <h2>
      &lt;?='&lt;a href="'.$this->data->story->get_absolute_url().'">' ?&gt;
        &lt;?=strtoupper($this->data->story->headline) ?&gt;
      </a>
    </h2>
    <p>&lt;?=truncate_words($this->data->story->tease, 100) ?&gt;</p>
  &lt;? endforeach ?&gt;
&lt;?}
}?&gt;

#9
[eluser]7bit[/eluser]
Another advantage of doing template iheritance with pure php is that you can insert php-only classes at the root or anywhere else into the inheritance tree that give your views the functionality to autonomously communicate with the model.

#10
[eluser]7bit[/eluser]
[quote author="Rick Jolly" date="1221445463"]
I like your thinking. Maybe checkout Modular Extensions (HMVC) if you haven't already. It's a similar take on what you've described. I see the difference like this:
[/quote]

I stumbled upon it in the wiki just a few minutes after i wrote my original posting, but maybe it's already too late, I have just started to write a completely new framework from scratch ;-)


Digg   Delicious   Reddit   Facebook   Twitter   StumbleUpon  


  Theme © 2014 iAndrew  
Powered By MyBB, © 2002-2019 MyBB Group.