• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nette / latte / 22368407632

24 Feb 2026 08:17PM UTC coverage: 94.825% (-0.2%) from 95.054%
22368407632

push

github

dg
phpstan

135 of 147 new or added lines in 38 files covered. (91.84%)

186 existing lines in 70 files now uncovered.

5534 of 5836 relevant lines covered (94.83%)

0.95 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.67
/src/Latte/Essential/Nodes/IfNode.php
1
<?php declare(strict_types=1);
2

3
/**
4
 * This file is part of the Latte (https://latte.nette.org)
5
 * Copyright (c) 2008 David Grudl (https://davidgrudl.com)
6
 */
7

8
namespace Latte\Essential\Nodes;
9

10
use Latte\CompileException;
11
use Latte\Compiler\Nodes\AreaNode;
12
use Latte\Compiler\Nodes\Php\Expression;
13
use Latte\Compiler\Nodes\Php\ExpressionNode;
14
use Latte\Compiler\Nodes\Php\Scalar\StringNode;
15
use Latte\Compiler\Nodes\StatementNode;
16
use Latte\Compiler\Position;
17
use Latte\Compiler\PrintContext;
18
use Latte\Compiler\Tag;
19
use Latte\Compiler\TagParser;
20
use Latte\Compiler\TemplateParser;
21
use function in_array;
22

23

24
/**
25
 * {if $cond} ... {elseif $cond} ... {else} ... {/if}
26
 * {ifset $var} ... {elseifset $var} ... {/ifset}
27
 */
28
class IfNode extends StatementNode
29
{
30
        public ExpressionNode $condition;
31
        public AreaNode $then;
32
        public ?AreaNode $else = null;
33
        public ?Position $elseLine = null;
34
        public bool $capture = false;
35
        public bool $ifset = false;
36

37

38
        /** @return \Generator<int, ?list<string>, array{AreaNode, ?Tag}, static> */
39
        public static function create(Tag $tag, TemplateParser $parser): \Generator
1✔
40
        {
41
                $node = $tag->node = new static;
1✔
42
                $node->ifset = in_array($tag->name, ['ifset', 'elseifset'], strict: true);
1✔
43
                $node->capture = !$tag->isNAttribute() && $tag->name === 'if' && $tag->parser->isEnd();
1✔
44
                $node->position = $tag->position;
1✔
45
                if (!$node->capture) {
1✔
46
                        $node->condition = $node->ifset
1✔
47
                                ? self::buildCondition($tag->parser)
1✔
48
                                : $tag->parser->parseExpression();
1✔
49
                }
50

51
                [$node->then, $nextTag] = yield $node->capture
1✔
52
                        ? ['else']
1✔
53
                        : ['else', 'elseif', 'elseifset'];
1✔
54

55
                if ($nextTag?->name === 'else') {
1✔
56
                        if ($nextTag->parser->stream->is('if')) {
1✔
57
                                throw new CompileException('Arguments are not allowed in {else}, did you mean {elseif}?', $nextTag->position);
1✔
58
                        }
59
                        $node->elseLine = $nextTag->position;
1✔
60
                        [$node->else, $nextTag] = yield;
1✔
61

62
                } elseif ($nextTag?->name === 'elseif' || $nextTag?->name === 'elseifset') {
1✔
63
                        if ($node->capture) {
1✔
UNCOV
64
                                throw new CompileException('Tag ' . $nextTag->getNotation() . ' is unexpected here.', $nextTag->position);
×
65
                        }
66
                        $node->else = yield from self::create($nextTag, $parser);
1✔
67
                }
68

69
                if ($node->capture) {
1✔
70
                        assert($nextTag !== null);
71
                        $node->condition = $nextTag->parser->parseExpression();
1✔
72
                }
73

74
                return $node;
1✔
75
        }
76

77

78
        private static function buildCondition(TagParser $parser): ExpressionNode
1✔
79
        {
80
                $list = [];
1✔
81
                do {
82
                        $block = $parser->tryConsumeTokenBeforeUnquotedString('block') ?? $parser->stream->tryConsume('#');
1✔
83
                        $name = $parser->parseUnquotedStringOrExpression();
1✔
84
                        $list[] = $block || $name instanceof StringNode
1✔
85
                                ? new Expression\AuxiliaryNode(
1✔
86
                                        fn(PrintContext $context, ExpressionNode $name) => '$this->hasBlock(' . $context->ensureString($name, 'Block name') . ')',
1✔
87
                                        [$name],
1✔
88
                                )
89
                                : new Expression\IssetNode([$name]);
1✔
90
                } while ($parser->stream->tryConsume(','));
1✔
91

92
                return Expression\BinaryOpNode::nest('&&', ...$list);
1✔
93
        }
94

95

96
        public function print(PrintContext $context): string
1✔
97
        {
98
                return $this->capture
1✔
99
                        ? $this->printCapturing($context)
1✔
100
                        : $this->printCommon($context);
1✔
101
        }
102

103

104
        private function printCommon(PrintContext $context): string
1✔
105
        {
106
                if ($this->else) {
1✔
107
                        return $context->format(
1✔
108
                                ($this->else instanceof self
1✔
109
                                        ? "if (%node) %line { %node } else%node\n"
1✔
110
                                        : "if (%node) %line { %node } else %4.line { %3.node }\n"),
1✔
111
                                $this->condition,
1✔
112
                                $this->position,
1✔
113
                                $this->then,
1✔
114
                                $this->else,
1✔
115
                                $this->elseLine,
1✔
116
                        );
117
                }
118
                return $context->format(
1✔
119
                        "if (%node) %line { %node }\n",
1✔
120
                        $this->condition,
1✔
121
                        $this->position,
1✔
122
                        $this->then,
1✔
123
                );
124
        }
125

126

127
        private function printCapturing(PrintContext $context): string
1✔
128
        {
129
                if ($this->else) {
1✔
130
                        return $context->format(
1✔
131
                                <<<'XX'
132
                                        ob_start(fn() => '') %line;
1✔
133
                                        try {
134
                                                %node
135
                                                ob_start(fn() => '') %line;
136
                                                try {
137
                                                        %node
138
                                                } finally {
139
                                                        $ʟ_ifB = ob_get_clean();
140
                                                }
141
                                        } finally {
142
                                                $ʟ_ifA = ob_get_clean();
143
                                        }
144
                                        echo (%node) ? $ʟ_ifA : $ʟ_ifB %0.line;
145

146

147
                                        XX,
148
                                $this->position,
1✔
149
                                $this->then,
1✔
150
                                $this->elseLine,
1✔
151
                                $this->else,
1✔
152
                                $this->condition,
1✔
153
                        );
154
                }
155

156
                return $context->format(
1✔
157
                        <<<'XX'
158
                                ob_start(fn() => '') %line;
1✔
159
                                try {
160
                                        %node
161
                                } finally {
162
                                        $ʟ_ifA = ob_get_clean();
163
                                }
164
                                if (%node) %0.line { echo $ʟ_ifA; }
165

166
                                XX,
167
                        $this->position,
1✔
168
                        $this->then,
1✔
169
                        $this->condition,
1✔
170
                );
171
        }
172

173

174
        public function &getIterator(): \Generator
1✔
175
        {
176
                yield $this->condition;
1✔
177
                yield $this->then;
1✔
178
                if ($this->else) {
1✔
179
                        yield $this->else;
1✔
180
                }
181
        }
1✔
182
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc