Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

Pass a rendering helper to section lambdas #101

Merged
merged 3 commits into from Aug 2, 2012

Conversation

Projects
None yet
6 participants
Owner

bobthecow commented Jul 23, 2012

In addition to the section contents, section lambdas (higher order sections) would receive a lambda helper as a second parameter. This helper consists of a single render method, allowing a template to be rendered using the current context stack.

The returned result from a section lambda is automatically rendered as a mustache template, which is sufficient most of the time. But if you want to do something with the rendered value of that template, it doesn't quite cut it.

For example, this data:

<?php
$data = array(
  'foo' => 'win',
  'embiggen' => function($text) {
    return strtoupper($text);
  },
);

... and this template:

{{#embiggen}}{{ foo }}{{/embiggen}}

... would uppercase the {{ FOO }} template string, rather than the value of foo. This would then be automatically rendered, resulting in an empty string, since there is no FOO value available.

With this change, a mustache lambda helper is passed as the second parameter to the anonymous function, giving you a way to render the section value:

<?php
$data = array(
  'foo' => 'win',
  'embiggen' => function($text, $mustache) {
    return strtoupper($mustache->render($text));
  },
);

... which would render as WIN, exactly like you'd expect.

In other languages (JavaScript, Ruby), this method would be bound to the closure context and just be available inside the anonymous function, but this isn't an option in PHP :)

This change is backwards compatible, as the second value will simply be ignored by any section lambda not referencing it.

Great, I'll try how your solution works.

Your $mustache->render() addition was exactly what I was looking for - the solution to handle dynamic partials.

<?php
$template = '{{#dynamicpartial}}{{partialname}}{{/dynamicpartial}}';
$partials = array( 'fullname' => '{{lastname}}, {{name}}' );
$partialname = 'fullname';

$mustache = new Mustache_Engine( array(
    'partials' => $partials
));

$data = array(
    'name' => "Willy",
    'lastname' => 'Moe',
    'partialname' => $partialname,
    'dynamicpartial' => function( $text, $mustache )
    {
        return '{{>' . $mustache->render( $text ) . '}}';
    }
);

echo $mustache->render( $template, $data );

The template calls the lambda 'dynamicpartial'. The function renders the {{partialname}} to build the string that calls the partial and renders the text.

Please add this functionality to Mustache.php, it's a big help.

Owner

bobthecow commented Jul 24, 2012

You could even register 'dynamicpartial' as a helper so you don't have to add it to the rendering context... Just drop this in after instantiating $mustache and it'll always be available:

<?php

$mustache->addHelper('dynamicpartial', function($text, $mustache) {
    return '{{>' . $mustache->render($text) . '}}';
});

Ah - even better.

And from the merge statement I see that you decided to implement the feature in your Mustache.php dev branch - marvelous.

Owner

bobthecow commented Jul 28, 2012

@uhunkler I haven't quite decided yet. It's open as a pull request so we can discuss before I merge it :)

fwg commented Aug 1, 2012

Awesome, just the feature I was missing right now.

uhunkler commented Aug 2, 2012

Justin, what do you think needs discussion about this feature?

Do you need more people confirming the usefulness? Or more arguments?

One big argument I see is that in other Mustache implementations like JavaScript and Ruby this functionality is inherent. To be able to implement Mustache as consistent as possible I think this functionality should be possible in your PHP version too.

Owner

bobthecow commented Aug 2, 2012

@uhunkler Merging :)

@bobthecow bobthecow added a commit that referenced this pull request Aug 2, 2012

@bobthecow bobthecow Merge pull request #101 from bobthecow/feature/lambda-helper
Pass a rendering helper to section lambdas
345a0c4

@bobthecow bobthecow merged commit 345a0c4 into dev Aug 2, 2012

Owner

bobthecow commented Aug 2, 2012

This has been merged into the dev branch, and will go out in the v2.1.0 release.

uhunkler commented Aug 2, 2012

Marvelous :-)

Just something ... What'll happen if it's an user string and it contains, like "{{ admin }}" ? secury issue, isn't it ?

Owner

bobthecow commented Aug 2, 2012

Yup. It's called mustache injection, and it's definitely possible if you return user values from a lambda. I don't see a good way of preventing it at the engine level though.

satyago commented Nov 28, 2012

Sorry - haven't realized master is still < 2.1

Second parameter for helpers not passed anymore?

Owner

bobthecow commented Nov 28, 2012

@satyago Sorry about that. v2.1 is waiting on logging (see #116), but logging is waiting on an in-progress PHP-FIG discussion trying to standardize logging.

Unless that discussion stalls or doesn't come to a resolution, v2.1 will happen after a logging standard is adopted. In the interim, you should feel free to use the dev branch of Mustache.

@bobthecow bobthecow added a commit that referenced this pull request Nov 28, 2012

@bobthecow bobthecow Bind section lambdas to the helper for PHP >= 5.4
This means you can call `$this->render()` from inside a section lambda closure.

See #101
6cbaf8a

satyago commented Nov 28, 2012

Absolutely no problem !
It was my own mistake actually. I thought the master I pulled already was v2.1.
As soon as I realized I pulled the feature/lambda-helper-plus-plus tree ...

Needed this feature quite urgently - seemed the simplest solution for my problem ;)

Thanks for the quick support though !

@bobthecow bobthecow referenced this pull request Nov 28, 2012

Closed

Bind section lambdas? #125

Owner

bobthecow commented Nov 28, 2012

I'd use the dev branch rather than the lambda-helper-plus-plus feature branch. That branch is outdated and will most likely not be merged, as dev already contains the lambda helper.

satyago commented Nov 28, 2012

Thanks and done :) 🎱

mdings commented Dec 21, 2012

According to this Mustache can make use of helpers like so to, for instance, convert a title uppercase:

{{title|case.upper}}

I was just curious why this doesn't work for dynamic partials as well that were added through the addHelper method?

{{header|dynamic-partial}}
Owner

bobthecow commented Jan 5, 2013

It should, but only if you're using the dev branch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment