Jump to content

Intermediate template structure without string concatenation


Pete Jones
 Share

Recommended Posts

I've been using the intermediate template structure (_init.php, _main.php and string concatenation to build output for my various template sections defined in _main.php

This is a bit of a ball-ache as it renders my templates hard to use in editors (string concatenation doesn't work well with element matching/bracket matching.

Is there a better way to put this together (not using includes)?

e.g.

_main.php

<?php if($band1_content):?>
  <section class="w-section page-heading grey">
    <div class="w-container inset-container">
        <?php echo $band1_content;?>
    </div>
  </section>
  <?php endif; ?>

band.php

$band1_content = '<div class="w-container inset-container tabs filter-options">
 <a class="w-inline-block pr-tabs" data-group=""><div class="pr-tabs-text">All</div></a>
 <a class="w-inline-block pr-tabs" data-group="'. $pages->get(1015)->name.'"><div class="pr-tabs-text blue">'. $pages->get(1015)->title.'</div></a>
 <a class="w-inline-block pr-tabs" data-group="'. $pages->get(1016)->name.'"><div class="pr-tabs-text green">'. $pages->get(1016)->title.'</div></a>
 <a class="w-inline-block pr-tabs" data-group="'. $pages->get(1017)->name.'"><div class="pr-tabs-text orange">'. $pages->get(1017)->title.'</div></a>
</div>'; 

Pete

Link to comment
Share on other sites

imho wireRenderFile is still the best way if you want syntax highlighting in your editor; you can then set the $var = wireRenderFile('file', $vars);

you could also use static html files with simple {{tokens}}, load one into a variable and str replace the tokens..

  • Like 1
Link to comment
Share on other sites

I've recently switched more an more to a functional approach of building markup, which in my mind let's me focus much more on the data I want to display and keep the markup to a minimum in my code. If more than a handful of lines are needed i'm also using wireRenderFile like Macrura suggested.

e.g. your second snippet could look like this:

// Get bands and prepend all option
$band1pa = $pages->find("id=1015|1016|1017");
$band1array = array_map(function($i){ return array('name' => $i->name, 'title' => $i->title); }, $band1pa->getValues());
array_unshift($band1array, array('name' => '', 'title' => 'All'));

// Build markup around options
$bandlinks = array_reduce($band1array, function($c, $band){
  $link =  "<a class='w-inline-block pr-tabs' data-group='$band[name]'>";
  $link .= "<div class='pr-tabs-text green'>$band[title]</div>";
  $link .= "</a>";

  return $c . $link;
}, ''); 

// add container markup
$band1_content = "<div class='w-container inset-container tabs filter-options'>$bandlinks</div>";
Link to comment
Share on other sites

I used a form of this extensively on the last project:

https://medium.com/@clsource/the-wire-render-pattern-806bf6d6097a#.zhn62bk3h

to use a static html file / string replacement you would first load the html into a var:

$tpl = file_get_contents($config->paths->templates . 'html/my-file.html');
$search = array('{{token1}}','{{token2}}','{{token3}}');
$replace = array(
       $replacement_for_token1,
       $replacement_for_token2,
       $replacement_for_token3,
);
$content = str_replace($search, $replace, $tpl);

there may be a better way to do this, or use a template engine, but this would at least allow you to use native syntax highlighting within your editor when looking at the html... for repeating structures you'd still end up with markup in your php code for each replacement

  • Like 1
Link to comment
Share on other sites

I also vote for using a template engine. For me PW would be only half the fun if I would have to go back to PHP templating :)

Recently I started using no or only minimal grid classes in the markup, and control Layout mostly at csa level. This also leads to simpler markup and even to a more reusable code as html is independent from CSS, so you can use them even if you decide to use another CSS framework next time.

Link to comment
Share on other sites

In case you're looking for a way to separate your layouts from template-specific views and your business logic from front-end (markup) while still keeping things "editor friendly", you might want to take a look at one of the MVC-ish output approaches out there. My own take on the subject is available from GitHub as pw-mvc, and I've heard good things about the pvc boilerplate by fixate.

Sorry for the shameless self-promotion, but I do think that this approach brings in some very real benefits, especially once things get more complex. Generating and concatenating pieces of markup with code just feels awfully clunky and, at least in my hands, often results in template files that are both ugly and hard to read :)

  • Like 2
Link to comment
Share on other sites

This is a bit of a ball-ache as it renders my templates hard to use in editors (string concatenation doesn't work well with element matching/bracket matching.

My preference is to use output buffering. Works great with IDE completion, matching, etc.

<?php ob_start(); // $band1_content ?>
<div class="w-container inset-container tabs filter-options">
	<a class="w-inline-block pr-tabs" data-group=""><div class="pr-tabs-text">All</div></a>
	<a class="w-inline-block pr-tabs" data-group="<?= $pages->get(1015)->name ?>"><div class="pr-tabs-text blue"><?= $pages->get(1015)->title ?></div></a>
	<a class="w-inline-block pr-tabs" data-group="<?= $pages->get(1016)->name ?>"><div class="pr-tabs-text blue"><?= $pages->get(1016)->title ?></div></a>
	<a class="w-inline-block pr-tabs" data-group="<?= $pages->get(1017)->name ?>"><div class="pr-tabs-text blue"><?= $pages->get(1017)->title ?></div></a>
</div>
<?php $band1_content = ob_get_clean(); ?>
Link to comment
Share on other sites

Some interesting options here.

Having looked at Twig, it feels like an added layer of complexity (and another syntax to learn).

Macrura's wirerender pattern looks nice (https://medium.com/@clsource/the-wire-render-pattern-806bf6d6097a#.sy28dq9o1) as does Teppo's https://github.com/teppokoivula/pw-mvc

Robin S approach seems simplest, does this have any drawbacks?

Link to comment
Share on other sites

"...added layer of complexity (and another syntax to learn)"

Sure, one has to learn a template engine in order to utilize its full potential, but your own design pattern can quickly grow too, becoming more and more complex as time passes by. So, implementing your own design pattern takes time, learning someone else's also takes time.

It was not adrian's nor tpr's intention to convert me, but just because of seeing what Tracy is capable of and reading about Nette Forms and Latte, I started to learn something new and dropped the idea of creating something basic that can fit my needs in the short run, but will be an obstacle in the future. Also, this way I opted for something that guides me in implementing secure frontend, which is an added bonus.

Link to comment
Share on other sites

What about this one:

http://twig.sensiolabs.org/

Just my opinion, but I wouldn't recommend Twig. I realized three projects with it and first it is all fun, how simple the syntax is for outputting something. But every time I wanted to build something a little more complex (for example a contact form or search function), I first had to learn how to build it in PHP and after that try to recreate it in Twig. I always had the impression, that the api of twig is somehow limited, but maybe I haven't looked close enough at the documentation.  ;)

  • Like 1
Link to comment
Share on other sites

@AndZyk: that's a good point.

 

I don't enjoy working with template engines and thus I don't do it unless I really have to, but in the past I've had a few cases where I really did have to. The biggest mistake I did back then was that I tried to add too much logic on the front-end side. Sure, that's almost always a bad idea, but with Twig (and any other language designed for building simple templates) the repercussions are tenfold.

 

The lesson here is to never, ever add complex (business) logic to your Twig templates. Twig is not intended for complex stuff and even if it can be done – it has macros, is easy to extend with custom features, and supports both includes and template inheritance out of the box – the end result is almost always really ugly and way more confusing than it would be if it was written in plain PHP.

 

In theory this is easy, but then there are the border cases. For an example, imagine that you've got a bunch of raw data you need to format and output; do you iterate over the whole dataset in PHP and handle the formatting part there before sending it to Twig, or do you just send it to Twig and handle formatting and output in one go? If you decide to use Twig for both steps, chances are that you're in for one heck of a rough ride.

 

If Twig helps you keep your templates clean, by all means go for it, but in my opinion you will need another layer for handling the business logic, data formatting operations, etc. Twig is a good companion to a larger architectural pattern (such as MVC), but on it's own it's a major pain in the a*s.

  • Like 1
Link to comment
Share on other sites

I agree that a template engine is an additional layer of complication but one have to decide whether it's worth or not. For me the benefits compensate the extra overhead - which, as szabesz wrote, is not significant if you have built a workflow that fits.

Using them in a wrong way may lead to bad things of course, but this is the case with all the other tools like sass, gulp, etc.

  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...