Virus721
Virus721

Reputation: 8315

How to use PHP templating features properly?

Before i get to the point, let me introduce the context :) I've been working on the view layer of a MVC framwork i'm trying to develop. I've created several reusable views such as an accordion, a drop down menu, a text editor, a color picker, etc. Using this, i can do, for example :

<?php
$template = newView('Template');
$template->panel()->add(newView('Accordion')
    ->add('Accordion entry 1')
    ->add('Accordion entry 2')
    ->add('Accordion entry 3'));
$template->content()->add(newView('Block')
    ->add('Bla bla bla')
    ->add('Bla bla bla')
    ->add('Bla bla bla'));
echo $template;
?>

And that sort of things. The problem is that, to be able to do that, i have to mix PHP and html code. For example : here is how i generate the HTML of a drop down menu :

public function __toString() {
    $output =
        '<nav'.$this->_getHeader().'>'.
            $this->_label.
            '<ul>';
    for($i = 0, $l = count($this->_entries), $last = $l - 1; $i < $l; ++$i) {
        if($i === 0) {
           $this->_entries[$i]->addClass('First');
        }
        elseif($i === $last) {
           $this->_entries[$i]->addClass('Last');
        }
        $output .= '<li>'.$this->_entries[$i].'</li>';
    }
    $output .=
            '</ul>'.
        '</nav>';
    return $output;
}

A developper could easily design this by beautifying the code using Firebug or reading the PHP code, but a designer wouldn't like it. To solve this i would like to use the PHP templating system. This, for example, would be much more readable by a designer.

<table>
    <?php foreach($users as $user); ?>
    <tr>
        <td><?= $user->firstName ?></td>
        <td><?= $user->lastName  ?></td>
    </tr>
    <?php endforeach; ?>
</table>

My problem is, how can i do, using the PHP templates, to create reusable views ? For example, imagine that i have a view representing a picture thumb with a picture and details about it. If i need to display a page containing 100 of them, how can i do ? Should i require the view 100 times ? Will it be executed / parsed / loaded from the damn slow disk 100 times ? I don't see how i could build some kind of "lego-style" view layer using the templaetes. Do you have any idea or even examples ?

Thanks for reading.

Upvotes: 1

Views: 139

Answers (1)

Marat Tanalin
Marat Tanalin

Reputation: 14123

To prevent repeated reading of a file, you can load a file once and save its contents to a variable.

Repeating rows is of a view's responsibility and is undesired to be inside template itself.

As for templating itself, I would recommend to avoid using pure-PHP templates in favor of passive templates with variables/placeholders like this:

<!-- table.tpl - Template for table. -->
<table>
{{rows}}
</table>

<!-- table-row.tpl - Template for table row. -->
<tr>
    <td>{{first_name}}</td>
    <td>{{last_name}}</td>
</tr>

You can then replace template variables with their needed values. For example, in simplest case (real world templating is of course more sophisticated):

$tableTpl = file_get_contents('tpl_dir/table.tpl');
$rowTpl   = file_get_contents('tpl_dir/table-row.tpl');

$rows = array(
    array(
        'first_name' => 'Lorem',
        'last_name'  => 'Ipsum'
    ),
    array(
        'first_name' => 'Foo',
        'last_name'  => 'Bar'
    )
);

$rowsFrags = array();

// This loop can be moved to a method of a template engine class.
foreach ($rows as $row) {
    $names = array_keys($row);

    foreach ($names as &$name) {
        $name = '{{' . $name . '}}';
    }

    $rowsFrags[] = str_replace($names, array_values($row), $rowTpl);
}

$rowsCode  = implode("\n", $rowsFrags);
$tableCode = str_replace('{{rows}}', $rowsCode, $tableTpl);

echo $tableCode;

Upvotes: 2

Related Questions