MVC - xsl/xml as model/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

Post Reply
User avatar
Hurreman
Forum Commoner
Posts: 61
Joined: Sat Apr 29, 2006 8:42 am

MVC - xsl/xml as model/view ?

Post by Hurreman »

Lately, I've been planning a larger project and trying to figure out how everything should work before I actually start coding.
My last try on MVC and separating presentation from logic wasn't very successful (due to lack of planning beforehand),.

What I've got so far is a modified version of arborint's frontcontroller and servicelocator skeleton, which works perfectly. My problem has been in the model/view, where I end up having a lot of mixed php/xhtml output. I've got PHP code generating xhtml, and well, it's far from a pretty solution. I've been looking at a couple of solutions (using Template Lite or a similiar template engine), but lately I've been curious about using xml/xsl. Would it be a bad idea using xml/xsl as view/model?

Also, the project will rely on a lot of DOM/Ajax drag-drop, and I'm not sure how using xml/xsl would affect working with the DOM with javascript...



I'll paste some of my current and horrible, HORRIBLE code for everyone to laugh at... :oops:


Action/Viewboards.php

Code: Select all

<?php
include_once('inc/forumlayout.php');

class viewboards extends forumlayout
{
    function printContent()
    {
        echo '<div id="content">';
        $this->forum->printBoards();
        echo '</div>';
    }

    function execute()
    {
        $this->printHead();
        $this->printHeader();
        $this->printNavigation();
        $this->printContent();
        $this->printRightDiv();
        $this->printFooter();
    }
}
?>
Function from within Lib/Forum.php

Code: Select all

// Pre: Table 'boards' must exist and have entries
    // Post:
    // Note: Prints a table of the boards found in the 'boards' table.
    function printBoards()
    {
        $query = "SELECT * FROM boardcategories";
       
        $stmt = $this->db->createQuery($query);
        $rs = $stmt->execute();
        echo '<table cellspacing="0" cellpadding="0" class="boards">' . "\n";


        // Print all categories and their child-boards
        while($rs->next())
        {
            echo '<tr>' . "\n";
            echo '<td class="topBoardTitle">' . $rs->getField('boardCatTitle') . '</td>';
            echo '<td class="topBoardTopics">Topics</td>';
            echo '<td class="topBoardPosts">Posts</td>';
            echo '<td class="topBoardLastPost">Last Post</td>';
            echo '</tr>';


            // Select all child boards
            $stmt2 = $this->db->createQuery('SELECT * FROM boards WHERE boardCatID=? ORDER BY boardOrder,boardID');
            $stmt2->setParameter(1,$rs->getField('boardCatID'));
            $rs2 = $stmt2->execute();
            while($rs2->next())
            {
                echo '<tr>';
                echo '<td class="boardTitle">';
                echo '<p><a href="forum.php?action=listposts&id=' . $rs2->getField('boardID') . '">' . $rs2->getField('boardTitle') . '</a></p><p>' . $rs2->getField('boardDesc') . '</p></td>';
                echo '<td class="boardTopics">' . $this->getBoardTopics($rs2->getField('boardID')) . '</td>';
                echo '<td class="boardPosts">' . $this->getBoardPosts($rs2->getField('boardID')) . '</td>';
                echo '<td class="boardLastPost">';
                $this->printBoardLastPost($rs2->getField('boardID'));
                echo '</td>';
                echo '</tr>';
            }
        }
        echo '</table>';
    }
User avatar
Kieran Huggins
DevNet Master
Posts: 3635
Joined: Wed Dec 06, 2006 4:14 pm
Location: Toronto, Canada
Contact:

Post by Kieran Huggins »

I've been down the xml/xslt view path, and it was more trouble than it was worth. It's tough to let go since it looks like such a perfect answer, but in the end the severe overhead of all those "XML sit-ups" just wasn't worth it. XML+XSLT is a fickle beast.

I'd recommend a lightweight template layer, with separate templates for each output format you want to support. You can select the output type by examining $_SERVER['HTTP_ACCEPT'] for hints.

If your template looks too messy, see if you're doing too much at that layer and see what you can move to the controller.

Take a look into the concept of "partials" and "layouts" in Rails. That might give you some good ideas for a simpler view layer.

Good luck!
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

Hurreman wrote:My problem has been in the model/view, where I end up having a lot of mixed php/xhtml output. I've got PHP code generating xhtml, and well, it's far from a pretty solution. I've been looking at a couple of solutions (using Template Lite or a similiar template engine), but lately I've been curious about using xml/xsl. Would it be a bad idea using xml/xsl as view/model?
XML/XSL is certainly a possiblity, but it is certainly not the simplest solution as Kieran notes. Given what you are doing, PHP templates might be enough. Here is some code and ideas to get you going. The model, view and template code below is completely untested -- I just edited the code in your post.

As you can see, it starts to separate things and define dependencies -- which will have benefits down the road and complexity increases.

First a simple PHP template class. It encapsulates a template, Lazy Load by design, and heads toward building a Response from renderable objects.

Code: Select all

<?php
class Template {
    protected $data = array();
    protected $filename = '';
	
    public function __construct($filename='', $data=array()) {
        $this->filename = $filename;
        $this->data = $data;
    }
	
    public function get($name) {
    	return (isset($this->data[$name]) ? $this->data[$name] : null);
    }

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

    public function has($name) {
    	return isset($this->data[$name]);
    }

    public function render() {
        extract($this->data);
        ob_start();
        include($this->filename);
        $str = ob_get_clean();
        return($str);
    }

}
Here is very rough hacked, example at a PHP template:

Code: Select all

<table cellspacing="0" cellpadding="0" class="boards">
<?php
        // Print all categories and their child-boards
        while($boards in $data)
        {
?>
            <tr>
            <td class="topBoardTitle"<?php echo  $data['CatTitle']; ?></td>
            <td class="topBoardTopics">Topics</td>
            <td class="topBoardPosts">Posts</td>
            <td class="topBoardLastPost">Last Post</td>
            </tr>
<?php
            // Select all child boards
            while($data in$row)
            {
?>
                <tr>
                <td class="boardTitle">
                <p><a href="forum.php?action=listposts&id=; ?>$data['boardID); ?>"<?php echo $data['boardTitle); ?></a></p><p<?php echo $row['boardDesc); ?></p></td>
                <td class="boardTopics"<?php echo $this->getBoardTopics($row['boardID']; ?></td>
                <td class="boardPosts"<?php echo $row['boardID']; ?></td>
                <td class="boardLastPost">
                <?php echo $row['LastPost']; ?>
                </td>
                </tr>
<?php
            }
        }
?>
        </table>
This is to show the concept of a Boards Model (though you may not want to do it this way):

Code: Select all

class BoardsModel {

    function __construct($db);
        $this->db = $db;
    }

    function findBoards()
    {
        $data = array();

        $query = "SELECT * FROM boardcategories";
       
        $stmt = $this->db->createQuery($query);
        $rs = $stmt->execute();
        while($rs->next())
        {
            // Select all child boards
            $stmt2 = $this->db->createQuery('SELECT * FROM boards WHERE boardCatID=? ORDER BY boardOrder,boardID');
            $stmt2->setParameter(1,$rs->getField('boardCatID'));
            $rs2 = $stmt2->execute();
            while($rs2->next())
            {
                $id = $data$rs2->getField('boardID');
                $data[$id]['id'] = $id; 
                $data[$id]['boardTitle'] = $rs2->getField('boardTitle') ;
                $data[$id]['boardDesc'] = $rs2->getField('boardDesc');
                $data[$id]['BoardTopics'] = $this->getBoardTopics($rs2->getField('boardID'));
                $data[$id]['BoardPosts'] = $this->getBoardPosts($rs2->getField('boardID'));
                $data[$id]['BoardLastPost'] = $this->getBoardLastPost($rs2->getField('boardID'));
            }
        }
        return $data;
    }
}
And here is a modified version of your view class Action/Viewboards.php

Code: Select all

<?php
class viewboards extends forumlayout
{
    function getContent()
    {
        $template = new template('path/to/boards_template.php');
        $model = new BoardsModel($db);     // this really should be instantiated outside view
        $template->set('boards', $model->findBoards());

        return '<div id="content">' . $template->render() . '</div>';
    }

    function render()
    {
        return $this->getHead() .
                $this->getHeader() .
                $this->getNavigation() .
                $this->getContent() .
                $this->getRightDiv() .
                $this->getFooter();
    }
}
Hurreman wrote:What I've got so far is a modified version of arborint's frontcontroller and servicelocator skeleton, which works perfectly.
I am glad the skeleton code has been of use. Someone recently asked me recently to update it to PHP5, so the latest (which includes a bunch of code, some examples and basic documentation) is available here. If you want more information specifically about how the skeleton Template/View/Response rendering is intended to work, just ask.
(#10850)
User avatar
Hurreman
Forum Commoner
Posts: 61
Joined: Sat Apr 29, 2006 8:42 am

Post by Hurreman »

Cheers for the input guys!

And I agree with both of you. The more I looked into using xml/xsl, the less interesting it looked.

I'll be sure to give your example a try and report back when (not if) I run into problems :roll:

I'm coding ASP/VB.NET all day at work, so lately I've felt a bit confused when swapping between VB-like syntax and PHP/Javascript :)
Post Reply