zordius / lightncandy

An extremely fast PHP implementation of handlebars ( http://handlebarsjs.com/ ) and mustache ( http://mustache.github.io/ ),
https://zordius.github.io/HandlebarsCookbook/
MIT License
608 stars 76 forks source link

Non-String Helpers #293

Open jasonh-brimar opened 6 years ago

jasonh-brimar commented 6 years ago

The PHP Code:

require('./vendor/autoload.php');

// Define the template string.
$templateString = '{{json (hash foo="one" bar="two")}}';

// Define the LightnCandy render options.
$renderOptions = [
    'helpers' => [
        'hash' => (
            function ($options): stdClass
            {
                return (object)$options['hash'];
            }
        ),
        'json' => (
            function ($param): string
            {
                return json_encode($param);
            }
        )
    ]
];

// Create the template using LightnCandy.
$template = eval(LightnCandy\LightnCandy::compile($templateString, [
    'flags' => LightnCandy\LightnCandy::FLAG_HANDLEBARSJS_FULL | LightnCandy\LightnCandy::FLAG_ERROR_SKIPPARTIAL | LightnCandy\LightnCandy::FLAG_EXTHELPER | LightnCandy\LightnCandy::FLAG_ERROR_EXCEPTION,
    'helperresolver' => (
        function ($context, $name) use ($renderOptions): bool
        {
            return array_key_exists($name, $renderOptions['helpers']);
        }
    )
]));

?>
<!doctype html>
<html lang="en">

    <head>
        <meta charset="utf-8">
        <title>Non-String Helper Test</title>
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <style>
            #php, #js {
                border: 1px solid black;
                margin: 20px;
                padding: 20px;
            }
            #php {
                background: #ffe;
            }
            #js {
                background: #eff;
            }
        </style>
    </head>

    <body>

        <div id="php">
            <h1>Rendered by PHP</h1>
            <div id="rendered-php"><?= $template(new stdClass(), $renderOptions) ?></div>
        </div>

        <div id="js">
            <h1>Rendered by JS</h1>
            <div id="rendered-js"></div>
        </div>

        <script id="template" type="text/x-handlebars-template"><?= $templateString ?></script>

        <script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.11/handlebars.js" integrity="sha256-JWyJjSicZs/EX4AJmuCHSYYARSvIkYeM79Dn1pJOSCE=" crossorigin="anonymous"></script>

        <script>

            // Register helpers...
            Handlebars.registerHelper({
                hash: function (options) {
                    return Object.assign({}, options.hash);
                },
                json: function (param) {
                    return JSON.stringify(param);
                }
            });

            // Extract the template from the the DOM and render.
            document.getElementById("rendered-js").innerHTML = Handlebars.compile(document.getElementById("template").innerHTML)({});

        </script>

    </body>

</html>

The Issue:

LightnCandy generates an output of "" where Handlebars generates the expected output of {"bar":"two","foo":"one"}. The issue seems to be that LightnCandy tries to cast the returns from all helpers to strings, even if they are nested to be supplied as a non-string value to another helper.

jasonh-brimar commented 4 years ago

I can confirm that this issue is still present in LightnCandy 1.2.5.