views:

1450

answers:

16

Hi,

What's the most elegant templating (preferably in pure PHP!) solution you've seen?

Specifically i'm interested in handling:

  1. Detecting in a repeating block whether it's the first or last element
  2. Easy handling of odd/even cases, like a zebra striped table, or similar
  3. Other modulos logic, where you'd do something every n'th time.

I'm looking for something that makes this less of a pain:

<?php
$persons = array('John', 'Jack', 'Jill', 'Jason');
?>

<?php $i = 0; ?>
<?php if (isset($persons)): ?>
<ul>
<?php foreach ($persons as $name): ?>
    <li class="<?= ($i++ % 2 === 0) ? 'odd' : 'even' ?>"><?= $name ?></li>
<?php endforeach ?>
</ul>
<?php endif ?>

Does it really take the mess above to create something like this below?

<ul>
    <li class="odd">John</li>
    <li class="even">Jack</li>
    <li class="odd">Jill</li>
    <li class="even">Jason</li>
</ul>

Is it only me that find the above near hideous?

All those starting and closing of php-tags makes me cringe.

A: 

I use Modulo like you did in your example all the time.

Daok
+5  A: 

Tiny But Strong

www.tinybutstrong.com

It doesn't make the smarty mistake of embedding another macro language in the page, but does allow you to handle every practical web display issue I've ever thrown at it. In particular the above odd/even constructs are a doddle. For something like your code selecting from a database table

In the PHP file

$TBS->MergeBlock('blk1',$sqlconnect, "SELECT name from people ");

And in the HTML file

<ul>
    <li class="odd">[blk.name;block=ul]</li>
    <li class="even">[blk.name;block=ul]</li>
</ul>

And that's it. Notice that the HTML is completely Dreamweaver compatible. Furthermore if I wanted to make that alternate over three line styles all I'd need to do is add the extra line, maybe with different classes, so

<ul>
    <li class="linestyle1">[blk.name;block=ul]</li>
    <li class="linestyle2">[blk.name;block=ul]</li>
    <li class="linestyle3">[blk.name;block=ul]</li>
</ul>
Cruachan
+1 Tiny But Strong is absolutely incredible. Once you learn to use magnets templating gets orders of magnitude easier.
Sean Vieira
+1 Definitely. Unbelievable lightweight!
Industrial
A: 

If what cringes you is the opening and closing tags, write a function that creates the html string and then have it return it. At least it will save you some tags.

tehborkentooth
+4  A: 

It ain't pure PHP (the templating syntax then), but it works realy nice; Smarty.

For loops you can do:


<ul>
{foreach from=$var name=loop item=test}
  {if $smarty.foreach.loop.first}<li>This is the first item</li>{/if}
  <li class="{cycle values="odd,even"}">{$var.name}</li>
  {if $smarty.foreach.loop.last}<li>This was the last item</li>{/if}
{/foreach}
</ul>
D4V360
I know it's popular, but I think Smarty is one of the worst public libraries ever.
Peter Bailey
And why is it one of the worst public libraries?
D4V360
I don't have enough space in these comments to write a real answer, but basically because it's a complete other language, and there are many things wrong with that. Maintainability, performance, transferrability, etc. It's just not a development approach I agree with.
Peter Bailey
And that example looks absolutely terrible! I'll take: "<?php ul($users); ?>" any day.
Bobby Jack
-1 agreed. Smarty is evil. It just forces you to use *two* scrippting languages *in the same page*. There are better ways
Cruachan
Smarty isn't very secure either, I believe.
Eli
Personally Smarty is one of the only frameworks for PHP (other than Zend) I think is remotely worth using. It's worth noting the W3C website itself uses Smarty (Check the source of http://www.w3.org/).
Iain Collins
+2  A: 

I've used Smarty Template Engine in the past. It's Pretty solid. And as you can probably tell from the website; it has quite the large user-base and is updated regularly.

It's in pure PHP as well.

roosteronacid
+3  A: 

have you considered phptal?. one main benefit of it (or something similar) is that you get templates which can pass validation. most php template engines seem to ignore this.

Owen
Can't vouch for phptal, but having used another implementation of TAL in the past, it's a solid templating language.
Sean McSomething
+7  A: 

You don't need to open the tags more than once. You can also make a function out of it if you do the same thing multiple times:

<?php
function makeul($items, $classes) {
  $c = count($classes);
  $out = "";

  if (isset($items) && count($items) > 0) {
    $out = "<ul>\n";
    foreach ($items as $item) {
      $out .= "\t<li class=\"" . $classes[$i++%$c] . "\">$item</li>\n";
    }
    $out .= "</ul>\n";
  }
  return $out;
}
?>

other page content

<?php
$persons = array('John', 'Jack', 'Jill', 'Jason');
$classes = array('odd', 'even');
print makeul($persons, $classes);
?>

Also, if you don't mind using Javascript, Jquery makes things done mod 2 pretty easy (e.g., for zebra striping a table):

$("tr:odd").addClass("odd");
$("tr:even").addClass("even");
Randy
Totally agree with you here - no need to overcomplicate the solution when PHP already offers itself as a templating language. You can drop the 'classes' argument (at least in the default case) since the classes will normally be 'odd' + 'even'.
Bobby Jack
well, the function is written more generic so you can also pass more than two alternatives for classes. as you can see, modulo is taken according to count($classes).
tharkun
99%: "\"" . htmlspecialchars($classes[$i++%$c] . "\">" . htmlspecialchars($item) / "</li>\n";
jmucchiello
+1  A: 

Savant is a lightweight, pure PHP templating engine. Version 2 has a cycle plugin similar to the Smarty one mentioned earlier. I haven't been able to find a reference to the same plugin in version 3, but I'm sure you could write it fairly easily.

Shabbyrobe
A: 

As template engines goes, I really like makrell. It's kind of like functional programming for templates; Gives you a lot of freedom and expressiveness, without getting overly complicated.

To render your example, the makrell markup could look like this:

{ul @ary @var} {{
  <?php if (isset($@ary)): ?>
  <?php $i = 0; ?>
  <ul>
  <?php foreach($@ary as $@var) : ?>
}}

{/ul} {{
  <?php endforeach; ?>
  </ul>
  <?php endif; ?>
}}

{li @var} {{
  <li class="<?= ($i++ % 2 === 0) ? 'odd' : 'even' ?>">
    <?php echo htmlspecialchars($@var); ?>
  </li>
}}

{ul customers cust}
  {li cust}
{/ul}
troelskn
This is total garbage, if code like this come to me in an interview, you'd never get hired
TravisO
Indeed, what the hell is this?
The Pixel Developer
Are you sh*tting me? This crap is twice as ugly as the original, and a thousand times less likely to be understood by the HTML person who comes along later to update it.
Eli
Ahh, good old 'enterprise solutions'. There is no security like job security. :)
Meep3D
...and this does nothing that PHP can't do and yet you have to learn a syntax.Wow: 14 downvotes but accepted ;)
Franz
+3  A: 

I use PHPTAL for templating because it is written in 100% actual HTML with placeholder data, so it even works in a WYSIWYG editor for a web designer. That and it's just way easy to understand.

Here's what it would look like for me. Please forgive the markup, I'm new here and the four spaces block wasn't working right for me (the list was a list, not the markup).

PHP Code:

  $tal = new PHPTAL;
  $tal->setTemplate('people.htm')
      ->set('people', array('John', 'Jack', 'Jill', 'Jason'));
  echo $tal->execute();

Template:

  <ul>
    <li tal:repeat="person people" tal:content="person">John Doe</li>
  </ul>

Output:

  • John
  • Jack
  • Jill
  • Jason
  • Now obviously I wouldn't make a template for this little, but I could use a macro for it or build a whole page and include that variable. But you get the idea. Using PHPTAL has just about tripled my speed at templating and programming, just by the simplicity (no new syntax to learn like smarty).

    The Wicked Flea
    How would you do zebra striping with phptal? I was doing the following, but it looks too verbose:<td tal:condition="repeat/item/odd" tal:content="item" class="odd">item value</td><td tal:condition="repeat/item/even" tal:content="item" class="even">item value</td>
    starmonkey
    Not reading the manual careful enough? ;) http://phptal.org/manual/de/split/tal-attributes.html<li tal:repeat="name persons" tal:attributes="class php: repeat.name.odd ? 'odd' : 'even'" tal:content="name" /> does the trick.
    Vadim Ferderer
    A: 

    I have been a fan of HAML for quite a while, it looks like PHP folk have HAML now: see http://phphaml.sourceforge.net/

    Sam Saffron
    +1  A: 

    A small help on the looping:

    <? $b=false; foreach($MyList as $name) { ?>
       <li class="row<?= $b=!$b ?>"><?= htmlspecialchars($name); ?></li>
    <? } ?>
    

    By saying $b=!$b, it automatically alternates between true and false. Since false prints as "", and true prints as "1", then by defining css classes row and row1, you can get your altering rows without any trouble.

    consider using :first-child css to style the first one differently.

    gahooa
    A: 
    <?= ($i++ % 2 === 0) ? 'odd' : 'even' ?>
    

    You're doing it the other way around. Your first item is now called even instead of odd. Use ++$i.

    I'm having the same problem. But I think your original solution is the neatest. So I'll go with that.

    Erik
    +2  A: 

    How's about XSLT? The only template system that has a standards body behind it. Works the same across programming languages. Learn it once, use it everywhere!

    bytebrite
    A: 

    I created a simple templating system in PHP to solve this problem a while ago:

    http://code.google.com/p/templatephp/

    It takes a multidimensional array, and requires the addition of some extra tags to the HMTL to create the combined template.

    It's not as complicated (albeit powerful) as Smarty and some other solutons, but wins out in simplicity a lot of the time. A demo of the menu creation:

    <p>Main Menu</p>
    <ul>
    {block:menu_items}
            <li><a href="{var:link}">{var:name}</a></li>
    {/block:menu_items}
    </ul>
    

    Merged with...

        array (
            'menu_items' => array (
                    array (
                            'link' => 'home.htm',
                            'name' => 'Home'
                    ),
                    array (
                            'link' => 'about.htm',
                            'name' => 'About Us'
                    ),
                    array (
                            'link' => 'portfolio.htm',
                            'name' => 'Portfolio'
                    ),
                    array (
                            'link' => 'contact.htm',
                            'name' => 'Contact Us'
                    )
            )
    );
    

    Will create the menu...

    <p>Main Menu</p>
    <ul>
            <li><a href="home.htm">Home</a></li>
            <li><a href="about.htm">About Us</a></li>
            <li><a href="portfolio.htm">Portfolio</a></li>
            <li><a href="contact.htm">Contact Us</a></li>
    </ul>
    
    Meep3D
    As a side note the striping of tables should be done with css (using jquery) rather than built into the template. Saves a lot of headaches.
    Meep3D
    +2  A: 

    Symfony Components: Templating

    alt text

    Symfony intends on moving to a new templating system based on the lightweight PHP templating system twig.

    The lead developer Fabien Potencier, explains the decision here: http://fabien.potencier.org/article/35/templating-engines-in-php-follow-up

    Symfony can usually be replied upon to make very informed decisions on such matters, so this framework should be something to look into.

    The component is here: http://components.symfony-project.org/templating/

    Jon Winstanley