How to implement a composite view?

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

blueyon
Forum Commoner
Posts: 76
Joined: Tue Oct 30, 2007 9:53 am

How to implement a composite view?

Post by blueyon »

I have been working on composites for a while now and have created a composite controller. This is how it works:

Code: Select all

<?php
class Action extends Controller {
    var $id;    
    var $parent;
    var $children    = array();
    var $pre_action  = array();
    var $post_action = array();
    var $output;
    
    function render($view) {
        foreach ($this->children as $child) {
            $child->execute();
            
            $view->set($child->id, $child->output);
        }
        
        $this->output = $view->fetch();
    }
}
?>

<?php
class ControllerDefault extends Action {
    var $id     = 'content';
    var $parent = 'layout';

    function execute() {
        $view = new View('default.tpl');
        
        $view->set('title', 'Default');
        
        $this->render($view);
    }
}
?>

<?php
class ControllerLayout extends Action {
    var $id       = 'layout';
    var $children = array(
        'header',
        'footer',
        'column'
    );
    
    function execute() {
        $this->view = new View('layout.tpl');
        
        $this->render($this->view);
    }
}
?>

I don't think this is the correct way of doing things.

Can anyone please post some examples?

I have see the Zend tutorial example but it does not look like the right way of going about things.

The only other way I can think of is if one of my pages extended from a layout class which would have methods for setting varables like titel, content and mopdules.
Last edited by blueyon on Sat Jan 12, 2008 10:37 am, edited 3 times in total.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

I think you are headed the right direction and Zend the wrong way. ;) If you take a look at what you have emulated from ZF it is really just Template View that allows renderable objects to be associated with tags in the same way that strings usually are. Zend just limits it to specific tags, but there is no reason that you need to. I would recommend moving all the View stuff that you have stuck in your Controller classes into your View class.
(#10850)
blueyon
Forum Commoner
Posts: 76
Joined: Tue Oct 30, 2007 9:53 am

Post by blueyon »

I don't understand what you mean by moving all the view stuff into the view class. Do you mean the view should call the child controllers?

Is the view allowed to call controllers?

I have seen your skeleton framework which has helped me in the past understanding about patterns, but does not seem to cover this problem fully.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

First I think the View should render, not the Controller. But that is partly personal opinion and mainly because I use a Response object. If you don't then you can use your Controller as the Response.

Second, if you want to composite Controllers then that functionality should be in the Controller class, but if you want to composite Views then that should be done in the View class. Controller hierarchies are used for a couple of specific reasons, such as 1) you have very complex or conditional flow control, 2) your Controllers have a component quality and you like the dispatch/forward style, 3) you don't think the Model Pull style is valid so you do not allow your Views to load their own Models.
(#10850)
blueyon
Forum Commoner
Posts: 76
Joined: Tue Oct 30, 2007 9:53 am

Post by blueyon »

I have been reading about real MVC and SmallTalk-80.

http://st-www.cs.uiuc.edu/users/smarch/st-docs/mvc.html

Read the "The View - Controller Link" and the "The View/SubView Hierarchy".

The way I have setup the controller / view is exactly as its described in this article.

One controller to one view and a controller / view hierarchy.

A lot of web frameworks are not using MVC, but just calling it MVC.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

I have read that article several times over the years. That is a description of MVC as it related to Smalltalk fifteen years ago -- the 1:1 Controller-View relationship amongst other things. It is my opinion that the definition of MVC has grown, especially the details of how it is implemented in web applications. Part of that has to do with the slightly different needs of windowing vs browser applications; part due to the difference between graphics libraries vs HTML; and part due to the understanding of MVC evolving slightly. MVC is not that popular in windowing applications any more, whereas it seems to be a better fit for web apps.

Ultimately you will do what you like.
(#10850)
blueyon
Forum Commoner
Posts: 76
Joined: Tue Oct 30, 2007 9:53 am

Post by blueyon »

Can you post a basic example of how you do your views inside your controller or controllers please?
blueyon
Forum Commoner
Posts: 76
Joined: Tue Oct 30, 2007 9:53 am

Post by blueyon »

Arborint do you mean doing something like this?

Code: Select all

<?php
class ControllerDefault extends Action {
	var $id = 'content';

	function execute() {
		$view = new ViewDefault();

		$view->set('title', 'Default');
		
		$view->render();
	}
}
?>

<?php 
class ViewDefault extends View {
	var $parent = 'layout';
	
    function render() {
    	echo 'content';
    }
}
?>
All your examples on the skeleton frame work are just one view and don't have any sub parts or pages.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

More like:

Code: Select all

<?php
class ControllerDefault extends Action {
	var $id = 'content';

	function execute($registry) {
		$view = new ViewDefault();
		$view->set('title', 'Default');
		$view->set('menu', new MenuView() );
		$view->set('content', new HomeView() );
		
		$response = $registry->get('response');
                $response->setBody($view->render() );
	}
}

class MainView extends View {
	var $parent = 'layout';
	
    function render() {
    	$template = new Template('main.php');
        $template->set('title', $this->data['title'] );
        $template->set('menu', $this->data['menu']->render() );
        $template->set('content', $this->data['content']->render() );
        return $template->render();
    }
}

class MenuView extends View {
	var $parent = 'layout';
	
    function render() {
    	$template = new Template('menu.php');
        return $template->render();
    }
}

class HomeView extends View {
	var $parent = 'layout';
	
    function render() {
    	$template = new Template('home.php');
        return $template->render();
    }
}
(#10850)
blueyon
Forum Commoner
Posts: 76
Joined: Tue Oct 30, 2007 9:53 am

Re: How to implement a composite view?

Post by blueyon »

Arborint,

One more question please.

I think I get the idea, but if you add the view and do all the attachments on each page then its going to add a lot of code and take up much more time to develop each page.

So I'm wondering do you do a forward to a action that builds the layout before rendering?
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: How to implement a composite view?

Post by Christopher »

blueyon wrote:I think I get the idea, but if you add the view and do all the attachments on each page then its going to add a lot of code and take up much more time to develop each page.
A couple of comments. First, there is localized code reduction and overall code reduction. My goal is to achieve the latter which sometimes means simple things are a little harder, but complex things are a lot easier. Second, you will need to do the child attachments somewhere and at the parent node for those children is the most modular place to put them. There is going to be "a lot of code" anyway. The question is -- where to put it so it is the most independent from everything around it.
blueyon wrote:So I'm wondering do you do a forward to a action that builds the layout before rendering?
You can use Controllers or Views -- it really depends on how you think about them. If you use Controllers then you pass a Response through and each Controller attaches children to it. You will notice that these system often have extra methods to find Views. If you use Views then each View adds its children and the children in turn add any children they have. One thing you need to clarify for yourself is -- what is a Template and what is a View. Different programmers and frameworks give different answers as to where the dividing line is between those two.

Perhaps you could give a code sample of where you think there is too much code that takes too much time to develop and we could think about how to streamline it.
(#10850)
matthijs
DevNet Master
Posts: 3360
Joined: Thu Oct 06, 2005 3:57 pm

Re: How to implement a composite view?

Post by matthijs »

I'm following this thread with interest as I recently had a similar question in this thread.

One thing though, in your example Arborint, shouldn't

Code: Select all

<?php
class ControllerDefault extends Action {
   var $id = 'content';
      
   function execute($registry) {
      $view = new ViewDefault();
      $view->set('title', 'Default');
      $view->set('menu', new MenuView() );
      $view->set('content', new HomeView() );

      $response = $registry->get('response');
      $response->setBody($view->render() );
   }
}  
be

Code: Select all

<?php
class ControllerDefault extends Action {
   var $id = 'content';

   function execute($registry) {[b]
      $view = new MainView();[/b]
      $view->set('title', 'Default');
      $view->set('menu', new MenuView() );
      $view->set('content', new HomeView() );

      $response = $registry->get('response');
      $response->setBody($view->render() );
   }
} 
 

Code: Select all

class MainView extends View {
   var $parent = 'layout';

   function render() {
      $template = new Template('main.php');
      $template->set('title', $this->data['title'] );
      $template->set('menu', $this->data['menu']->render() );
      $template->set('content', $this->data['content']->render() );
      return $template->render();
   }
}   
And in this example, were would the $this->data come from?
blueyon
Forum Commoner
Posts: 76
Joined: Tue Oct 30, 2007 9:53 am

Re: How to implement a composite view?

Post by blueyon »

Code: Select all

<?php
class ControllerDefault extends Action {
var $id = 'content';

function execute($registry) {
$view = new ViewDefault();
$view->set('title', 'Default');
$view->set('menu', new MenuView() );
$view->set('content', new HomeView() );

$response = $registry->get('response');
$response->setBody($view->render() );
}
}
?>
The problem is that if you create a view in a controller which you then attach all the child views or have the main view automaticlly include all the child views then some of these child views might require some database access. Now if you keep want to keep calling the framework MVC then you should not have database access in the view. The only thing I can think of is having the compsite work from the controller level. I have also read some where that the controller part of MVC is a said to be a composite pattern.

I have managed to build a composite controller by having my front controller traverse through each child controller and execute it before executing its parent controller and then storing each output into the response object. I don't feel the code looked very clean when creating this, but it did work.

I then came up with another solution after studying Phrame.

I created a action chain like this:

1. First action would forward to to a request handler.
2. Request handler would then decide which page to forward too.
3. The page would then store in a data container the information needed to build the main conent of the page and forward to a layout renderer.
4. The renderer would then build the layout from a xml file which describes the layout structure. It would call each child and store its output. It would then set the response content and then forward to the response output action.
5. The response output action would display the output.

Example:

start -> handle request -> page -> render layout -> repsonse output

This is the ultimate in code reduction because It now means each action is is reusable.

If you require a global login you can do:

start -> user is logged in -> handle request -> page -> render layout -> response output
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: How to implement a composite view?

Post by Christopher »

matthijs wrote:I'm following this thread with interest as I recently had a similar question
One thing though, in your example Arborint, shouldn't
Yes it should be MainView.
matthijs wrote:And in this example, were would the $this->data come from?

Code: Select all

class View {
   var $data = array();

   function set($name, $value) {
      $this->data[$name] = $value;
   }

}

class MainView extends View {
   var $parent = 'layout';

   function render() {
      $template = new Template('main.php');
      $template->set('title', $this->data['title'] );
      $template->set('menu', $this->data['menu']->render() );
      $template->set('content', $this->data['content']->render() );
      return $template->render();
   }
}    
(#10850)
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Re: How to implement a composite view?

Post by Christopher »

blueyon wrote:The problem is that if you create a view in a controller which you then attach all the child views or have the main view automaticlly include all the child views then some of these child views might require some database access. Now if you keep want to keep calling the framework MVC then you should not have database access in the view. The only thing I can think of is having the compsite work from the controller level. I have also read some where that the controller part of MVC is a said to be a composite pattern.
There is nothing in the MVC pattern that says that the View cannot access the database. MVC define two separations: Primary - between the Model and the Presentation (V+C) and Secondary - between the View and Controller. Either the View or Controller may have a dependency on the Model
blueyon wrote:I have managed to build a composite controller by having my front controller traverse through each child controller and execute it before executing its parent controller and then storing each output into the response object. I don't feel the code looked very clean when creating this, but it did work.
I have tried the same thing -- and came to the same conclusion. In addition, I have found that code that uses forwarding is harder to maintain and modify.
blueyon wrote:I then came up with another solution after studying Phrame.

I created a action chain like this:

1. First action would forward to to a request handler.
2. Request handler would then decide which page to forward too.
3. The page would then store in a data container the information needed to build the main conent of the page and forward to a layout renderer.
4. The renderer would then build the layout from a xml file which describes the layout structure. It would call each child and store its output. It would then set the response content and then forward to the response output action.
5. The response output action would display the output.

Example:

start -> handle request -> page -> render layout -> repsonse output

This is the ultimate in code reduction because It now means each action is is reusable.

If you require a global login you can do:

start -> user is logged in -> handle request -> page -> render layout -> response output
Modify the code above to show how it works ...
(#10850)
Post Reply