How to check if a tag is empty or self-closing
- daun
- Member | 9
Is there a way of allowing both {custom}inner{/custom}
as well
as {custom}
when writing custom tags?
I'm trying to write a tag that can either be used to output strings (like
include
) or with content inside (like embed
).
Basically, it needs to behave differently when it's a statement vs. when it
contains content.
There's the option of {custom/}
, but how can I find out if the
tag is self-closing? The resulting node seems to be identical whether using
{custom/}
or {custom}{/custom}
.
This is what I have so far, but it returns true
for
both types:
$selfClosing = (
!$node->content ||
$node->content instanceof Nodes\NopNode ||
($node->content instanceof Nodes\TextNode && trim($node->content->content) === '') ||
($node->content instanceof Nodes\FragmentNode && count($node->content->children) === 0)
);
For good measure, this is the whole tag. Maybe the
yield $this->content
must be conditional somehow?
<?php
namespace App\Latte\Extensions\Nodes;
use Latte\CompileException;
use Latte\Compiler\Node;
use Latte\Compiler\Nodes;
use Latte\Compiler\Nodes\AreaNode;
use Latte\Compiler\Nodes\Php\Expression\ArrayNode;
use Latte\Compiler\Nodes\StatementNode;
use Latte\Compiler\NodeTraverser;
use Latte\Compiler\PrintContext;
use Latte\Compiler\Tag;
/**
* {custom}{/custom} or {custom}
*/
final class TagNode extends StatementNode
{
public string $name;
public ArrayNode $args;
public AreaNode $content;
public bool $selfClosing = false;
/** @return \Generator<int, AreaNode|null> */
public static function create(Tag $tag): \Generator
{
$node = $tag->node = new self;
$node->name = $tag->name;
$node->args = $tag->parser->parseArguments();
[$node->content] = yield;
$node->selfClosing = (
!$node->content ||
$node->content instanceof Nodes\NopNode ||
($node->content instanceof Nodes\TextNode && trim($node->content->content) === '') ||
($node->content instanceof Nodes\FragmentNode && count($node->content->children) === 0)
);
return $node;
}
public function print(PrintContext $context): string
{
return $this->selfClosing
? $context->format('echo customFunctionThatReturnsString(%node);', $this->args)
: $context->format('foreach (%node) { %node }', $this->args, $this->content);
}
public function &getIterator(): \Generator
{
yield $this->content;
}
}
Appreciate any pointers! Thanks in advance.
- daun
- Member | 9
Getting closer. When yielding the end tag, it turns out I can check if
it's the same object as the opening tag. So this works to distinguish between
{custom/}
and {custom}{/custom}
.
[$node->content, $endTag] = yield;
$node->hasContent = $endTag && $endTag->closing;
$node->selfClosing = !$endTag || $endTag === $tag;
As regards the non-closing standalone {custom}
, it looks like
that isn't possible? The reason it works for {block}
is that
there's a hardcoded
check in the TemplateParser class. Might open a feature request :)
Last edited by daun (2024-10-26 12:36)