0

I'm basically trying to write a json_encode filter, by which I'm hoping to get a raw json object, but what I'm getting instead, is an escaped string of the json object.

Expected result:

{"foo":"bar"}

Actual result:

"{\"foo\":\"bar\"}"

Right now the only way I can get it the way I want, is by using the noescape filter, but this makes it unnecessarily more ugly

{$object|json_encode|noescape}

My json_encode filter

public static function json_encode(FilterInfo $info, mixed $value): string {
    $info->contentType = ContentType::JavaScript;
    return json_encode($value);
}
Inc33
  • 1,747
  • 1
  • 20
  • 26

2 Answers2

0

You can try something like {do printf('%s',json_encode($object)) } printf isn't restricted unlike echo and print within the context of the php and do tags. Even if it was restricted, you can define your own function and have it echo from there.

But it looks like noescape is a very special filter which doesn't actually appear in the core filter list, it is the compiler/nodes and essential/nodes sections which check in multiple places for the presence of the noescape filter within the filter list then make decisions based on it.

➜  latte grep -r 'noescape' .
./latte/src/Latte/Essential/Nodes/BlockNode.php:        if ($node->modifier->hasFilter('noescape') && count($node->modifier->filters) === 1) {
./latte/src/Latte/Essential/Nodes/BlockNode.php:            throw new CompileException('Filter |noescape is not expected here.', $tag->position);
./latte/src/Latte/Essential/Nodes/IncludeFileNode.php:      $noEscape = $this->modifier->hasFilter('noescape');
./latte/src/Latte/Essential/Nodes/IncludeBlockNode.php:     $noEscape = $this->modifier->hasFilter('noescape');
./latte/src/Latte/Compiler/Nodes/Php/FilterNode.php:        NoEscape = 'noescape';
./latte/src/Latte/Compiler/Nodes/Php/ModifierNode.php:          } elseif ($name === 'noescape') {
./latte/src/Latte/Compiler/Nodes/Php/ModifierNode.php:          if ($name === 'noescape') {
./latte/src/Latte/Compiler/Nodes/Php/ModifierNode.php:              $noescape = true;
./latte/src/Latte/Compiler/Nodes/Php/ModifierNode.php:      if ($this->escape && empty($noescape)) {
➜  latte 

I'm afraid trying to find a simple way to do this without having to use noescape would push latte to its limits.

It might be possible to dynamically slap on the noescape filter if your extension finds the json_encode filter being used. Otherwise it looks like the way to do this is like so:

{$object|escapeJs|noescape}

You could also try a different syntax like:

{do json_encode_output($object) }

and define a global function like so:

function json_encode_output($object)
{
    echo json_encode($object);
}

It might also be possible to define your own tag like:

{json $output}

But considering how latte is designed, I'd probably just settle with the more verbose:

{$object|escapeJs|noescape}

Or I might actually reach for:

{json_encode($object)|noescape}

Edit:

I think I actually just figured it out. Simply echo from your function.

    public static function json_encode(FilterInfo $info, mixed $value): string {
        echo json_encode($value);
        return '';
    }
Kevin Y
  • 646
  • 5
  • 18
0

Found the answer in their forum.

This isn't very obvious from the documentation, but seems like since latte understands the context automatically, you don't really need any filter for json_encode, just need to write it as: var jsonObject = {$object} and it will automatically encode it to json

Inc33
  • 1,747
  • 1
  • 20
  • 26