Accessing raw text content of AreaNode
- daun
- Member | 9
Hi! I'm writing a custom tag for Latte 3. I need to extract the raw value between start and end tag and store that in a variable. Is this possible? To get the raw value, I must tell Latte to ignore the contents of the tag somehow.
Given the below Latte template, I'd like to get the exact string “Ignored by {latte} <b>and<b/> {returned} as string” inside the custom Node class to create a unique hash from it and write it to disk.
Normally rendered by Latte
{raw}
Ignored by {latte} <b>and<b/> {returned} as string
{/raw}
The class below is what I have so far, but it returns already parsed PHP output.
Using $context->format('%raw', $areaNode)
throws an error
that I can't render a FragmentNode instance to string.
Using $areaNode->print($context)
seems to parse the node and
return the PHP output.
Appreciate any help.
<?php
use Latte\Compiler\Nodes\AreaNode;
use Latte\Compiler\Nodes\NopNode;
use Latte\Compiler\Nodes\StatementNode;
use Latte\Compiler\PrintContext;
use Latte\Compiler\Tag;
/**
* {raw} {/raw}
*/
class RawNode extends StatementNode
{
public AreaNode $content;
/** @return \Generator<int, ?array, array{AreaNode, ?Tag}, static> */
public static function create(Tag $tag): \Generator
{
$node = $tag->node = new static;
if ($tag->void) return new NopNode;
[$node->content] = yield;
return $node;
}
public function print(PrintContext $context): string
{
$raw = $this->content->print($context);
$hash = sha1($raw);
// ?????
return $context->format("echo '%raw'; %line;", $hash, $this->position);
}
public function &getIterator(): \Generator
{
yield $this->content;
}
}
Last edited by daun (2024-01-29 16:24)
- daun
- Member | 9
I think I've found a solution. It seems a bit hacky, so if anyone can think of a more elegant solution, happy to hear it!
The idea is:
- Disable lexer syntax
- Set parser content type to text
- Read inner value of node
- Restore syntax and content type
- Extract text contents using NodeHelpers::toText()
<?php
use Latte\CompileException;
use Latte\Compiler\NodeHelpers;
use Latte\Compiler\Nodes\AreaNode;
use Latte\Compiler\Nodes\StatementNode;
use Latte\Compiler\PrintContext;
use Latte\Compiler\Tag;
use Latte\Compiler\TemplateParser;
use Latte\ContentType;
/**
* {raw} {/raw}
*/
class RawNode extends StatementNode
{
public AreaNode $content;
/** @return \Generator<int, ?array, array{AreaNode, ?Tag}, static> */
public static function create(Tag $tag, TemplateParser $parser): \Generator
{
$node = $tag->node = new static;
// Temporarily disable {} syntax and switch to text content type
$lexer = $parser->getLexer();
$delimiters = [$lexer->openDelimiter, $lexer->closeDelimiter];
$lexer->setSyntax('off', $tag->isNAttribute() ? null : $tag->name);
$type = $parser->getContentType();
$parser->setContentType(ContentType::Text);
// Read inner content as raw text
[$node->content] = yield;
// Restore previous syntax and content type
$parser->setContentType($type);
[$lexer->openDelimiter, $lexer->closeDelimiter] = $delimiters;
return $node;
}
public function print(PrintContext $context): string
{
$raw = NodeHelpers::toText($this->content);
$hash = sha1($raw);
return $context->format("echo '%raw'; %line;", $hash, $this->position);
}
public function &getIterator(): \Generator
{
yield $this->content;
}
}
- Marek Bartoš
- Nette Blogger | 1275
{syntax off}
Ignored by {latte} <b>and<b/> {returned} as string
{/syntax}
- daun
- Member | 9
@MarekBartoš Thanks! Turning syntax
off is only the
first required step here. The tag also needs to save the raw inner content into
a variable, hash it, save it to disk and render the content in a different
template language :) For that to work, I also need to switch the content type
to text so Latte doesn't return html node as children of the syntax node,
however the contentType
tag only works for the whole file, as far
as I could tell.