Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
BlockMacros: {define} accepts named parameters [Closes #184][Closes #198
]
  • Loading branch information
dg committed Nov 23, 2020
1 parent 84af218 commit ce2b118
Show file tree
Hide file tree
Showing 29 changed files with 318 additions and 44 deletions.
35 changes: 19 additions & 16 deletions src/Latte/Macros/BlockMacros.php
Expand Up @@ -84,9 +84,9 @@ public function finalize()
$compiler = $this->getCompiler();
foreach ($this->placeholders as $key => [$index, $blockName]) {
$block = $this->blocks[$index][$blockName] ?? $this->blocks[Template::LAYER_LOCAL][$blockName] ?? null;
$compiler->placeholders[$key] = $block
$compiler->placeholders[$key] = $block && !$block->hasParameters
? 'get_defined_vars()'
: '$this->params';
: '[]';
}

$meta = [];
Expand Down Expand Up @@ -328,25 +328,30 @@ public function macroDefine(MacroNode $node, PhpWriter $writer): string
}

$tokens = $node->tokenizer;
$args = [];
$params = [];
while ($tokens->isNext()) {
if ($tokens->nextToken($tokens::T_SYMBOL, '?', 'null', '\\')) { // type
$tokens->nextAll($tokens::T_SYMBOL, '\\', '|', '[', ']', 'null');
}
$args[] = $tokens->consumeValue($tokens::T_VARIABLE);
$param = $tokens->consumeValue($tokens::T_VARIABLE);
$params[] = $writer->write(
'%raw = $__args[%var] ?? $__args[%var] ?? null;',
$param,
count($params),
substr($param, 1)
);
if ($tokens->isNext()) {
$tokens->consumeValue(',');
}
}

$extendsCheck = $this->blocks[Template::LAYER_TOP] || count($this->blocks) > 1 || $node->parentNode;
$block = $this->addBlock($node, $layer);
$block->hasParameters = (bool) $params;

$data->after = function () use ($node, $block, $args) {
$args = $args
? ('[' . implode(', ', $args) . '] = $__args + [' . str_repeat('null, ', count($args)) . '];')
: null;
$this->extractMethod($node, $block, $args);
$data->after = function () use ($node, $block, $params) {
$params = $params ? implode('', $params) : null;
$this->extractMethod($node, $block, $params);
};

return $extendsCheck
Expand Down Expand Up @@ -433,12 +438,12 @@ public function macroSnippet(MacroNode $node, PhpWriter $writer): string
"<?php echo ' {$this->snippetAttribute}=\"' . htmlspecialchars(\$this->global->snippetDriver->getHtmlId(%var)) . '\"' ?>",
$data->name
);
return $writer->write('$this->renderBlock(%var, $this->params, null, %var)', $data->name, Template::LAYER_SNIPPET);
return $writer->write('$this->renderBlock(%var, [], null, %var)', $data->name, Template::LAYER_SNIPPET);
}

return $writer->write(
"?>\n<div {$this->snippetAttribute}=\"<?php echo htmlspecialchars(\$this->global->snippetDriver->getHtmlId(%var)) ?>\">"
. '<?php $this->renderBlock(%var, $this->params, null, %var) ?>'
. '<?php $this->renderBlock(%var, [], null, %var) ?>'
. "\n</div><?php ",
$data->name,
$data->name,
Expand Down Expand Up @@ -499,7 +504,7 @@ public function macroSnippetArea(MacroNode $node, PhpWriter $writer): string
);
$this->extractMethod($node, $block);
};
return $writer->write('$this->renderBlock(%var, $this->params, null, %var)', $data->name, Template::LAYER_SNIPPET);
return $writer->write('$this->renderBlock(%var, [], null, %var)', $data->name, Template::LAYER_SNIPPET);
}


Expand Down Expand Up @@ -533,12 +538,10 @@ private function addBlock(MacroNode $node, string $layer = null): Block
}


private function extractMethod(MacroNode $node, Block $block, string $args = null): void
private function extractMethod(MacroNode $node, Block $block, string $params = null): void
{
if (preg_match('#\$|n:#', $node->content)) {
$node->content = '<?php '
. ($args === null ? 'extract($__args);' : 'extract($this->params); ' . $args)
. ' ?>' . $node->content;
$node->content = '<?php extract($this->params);' . ($params ?? 'extract($__args);') . '?>' . $node->content;
}
$block->code = preg_replace('#^\n+|(?<=\n)[ \t]+$#D', '', $node->content);
$node->content = substr_replace($node->content, $node->openingCode . "\n", strspn($node->content, "\n"), strlen($block->code));
Expand Down
3 changes: 3 additions & 0 deletions src/Latte/Runtime/Block.php
Expand Up @@ -21,4 +21,7 @@ final class Block

/** @var callable[] used by Template */
public $functions = [];

/** @var bool used by BlockMacros */
public $hasParameters = false;
}
78 changes: 78 additions & 0 deletions tests/Latte/BlockMacros.define.args.phpt
Expand Up @@ -44,6 +44,7 @@ Assert::matchFile(
);


//typehints
$template = <<<'XX'
{define test $var1, ?stdClass $var2, \C\B|null $var3}
{/define}
Expand All @@ -55,3 +56,80 @@ Assert::matchFile(
__DIR__ . '/expected/BlockMacros.define.typehints.phtml',
$latte->compile($template)
);


// named arguments
$template = <<<'XX'
named arguments
{define test $var1, $var2, $var3}
Variables {$var1}, {$var2}, {$var3}
{/define}
a) {include test, 1, var1 => 2}
b) {include test, var2 => 1}
c) {include test, hello => 1}
d) {include test, var2 => 1, 2} // invalid
XX;

Assert::matchFile(
__DIR__ . '/expected/BlockMacros.define.args2.phtml',
$latte->compile($template)
);
Assert::matchFile(
__DIR__ . '/expected/BlockMacros.define.args2.html',
$latte->renderToString($template, ['var3' => 'outer'])
);


// named arguments (order dependent)
$template = <<<'XX'
named arguments order
a) {include test, 1, var1 => 2}
b) {include test, var2 => 1}
c) {include test, hello => 1}
{define test $var1, $var2, $var3}
Variables {$var1}, {$var2}, {$var3}
{/define}
XX;

Assert::matchFile(
__DIR__ . '/expected/BlockMacros.define.args3.phtml',
$latte->compile($template)
);


// named arguments (file dependent)
$latte->setLoader(new Latte\Loaders\StringLoader([
'main' => '
named arguments import
{import import.latte}
a) {include test, 1, var1 => 2}
b) {include test, var2 => 1}
c) {include test, hello => 1}',

'import.latte' => '
{define test $var1, $var2, $var3}
Variables {$var1}, {$var2}, {$var3}
{/define}',
]));

Assert::matchFile(
__DIR__ . '/expected/BlockMacros.define.args4.phtml',
$latte->compile('main')
);
Assert::matchFile(
__DIR__ . '/expected/BlockMacros.define.args4.html',
$latte->renderToString('main', ['var3' => 'outer'])
);
13 changes: 8 additions & 5 deletions tests/Latte/expected/BlockMacros.define.args1.phtml
Expand Up @@ -16,7 +16,7 @@ final class Template%a% extends Latte\Runtime\Template
}
echo '
a) ';
$this->renderBlock($__nm = 'test', [1] + get_defined_vars(), 'html');
$this->renderBlock($__nm = 'test', [1] + [], 'html');
echo '
Expand All @@ -27,19 +27,21 @@ b) ';
';
$var1 = 'outer';
echo 'c) ';
$this->renderBlock($__nm = 'test', get_defined_vars(), 'html');
$this->renderBlock($__nm = 'test', [], 'html');
echo '
d) ';
$this->renderBlock($__nm = 'test', [null] + get_defined_vars(), 'html');
$this->renderBlock($__nm = 'test', [null] + [], 'html');
return get_defined_vars();
}


public function blockTest(array $__args): void
{
extract($this->params);
[$var1, $var2, $var3] = $__args + [null, null, null, ];
$var1 = $__args[0] ?? $__args['var1'] ?? null;
$var2 = $__args[1] ?? $__args['var2'] ?? null;
$var3 = $__args[2] ?? $__args['var3'] ?? null;
echo ' Variables ';
echo LR\Filters::escapeHtmlText($var1) /* line 2 */;
echo ', ';
Expand All @@ -52,8 +54,9 @@ d) ';

public function blockOuter(array $__args): void
{
extract($this->params);
extract($__args);
$this->renderBlock($__nm = 'test', ['hello'] + get_defined_vars(), 'html');
$this->renderBlock($__nm = 'test', ['hello'] + [], 'html');

}

Expand Down
14 changes: 14 additions & 0 deletions tests/Latte/expected/BlockMacros.define.args2.html
@@ -0,0 +1,14 @@
named arguments


a) Variables 1, ,


b) Variables , 1,


c) Variables , ,


d) Variables 2, 1,
// invalid
55 changes: 55 additions & 0 deletions tests/Latte/expected/BlockMacros.define.args2.phtml
@@ -0,0 +1,55 @@
<?php
%A%

final class Template%a% extends Latte\Runtime\Template
{
protected const BLOCKS = [
['test' => 'blockTest'],
];


public function main(): array
{
extract($this->params);
echo 'named arguments
';
if ($this->getParentName()) {
return get_defined_vars();
}
echo '
a) ';
$this->renderBlock($__nm = 'test', [1, 'var1' => 2] + [], 'html');
echo '
b) ';
$this->renderBlock($__nm = 'test', ['var2' => 1] + [], 'html');
echo '
c) ';
$this->renderBlock($__nm = 'test', ['hello' => 1] + [], 'html');
echo '
d) ';
$this->renderBlock($__nm = 'test', ['var2' => 1, 2] + [], 'html');
echo ' // invalid';
return get_defined_vars();
}


public function blockTest(array $__args): void
{
extract($this->params);
$var1 = $__args[0] ?? $__args['var1'] ?? null;
$var2 = $__args[1] ?? $__args['var2'] ?? null;
$var3 = $__args[2] ?? $__args['var3'] ?? null;
echo ' Variables ';
echo LR\Filters::escapeHtmlText($var1) /* line 4 */;
echo ', ';
echo LR\Filters::escapeHtmlText($var2) /* line 4 */;
echo ', ';
echo LR\Filters::escapeHtmlText($var3) /* line 4 */;
echo "\n";
}

}
51 changes: 51 additions & 0 deletions tests/Latte/expected/BlockMacros.define.args3.phtml
@@ -0,0 +1,51 @@
<?php
%A%

final class Template%a% extends Latte\Runtime\Template
{
protected const BLOCKS = [
['test' => 'blockTest'],
];


public function main(): array
{
extract($this->params);
echo 'named arguments order
a) ';
$this->renderBlock($__nm = 'test', [1, 'var1' => 2] + [], 'html');
echo '
b) ';
$this->renderBlock($__nm = 'test', ['var2' => 1] + [], 'html');
echo '
c) ';
$this->renderBlock($__nm = 'test', ['hello' => 1] + [], 'html');
echo '
';
if ($this->getParentName()) {
return get_defined_vars();
}
return get_defined_vars();
}


public function blockTest(array $__args): void
{
extract($this->params);
$var1 = $__args[0] ?? $__args['var1'] ?? null;
$var2 = $__args[1] ?? $__args['var2'] ?? null;
$var3 = $__args[2] ?? $__args['var3'] ?? null;
echo ' Variables ';
echo LR\Filters::escapeHtmlText($var1) /* line 10 */;
echo ', ';
echo LR\Filters::escapeHtmlText($var2) /* line 10 */;
echo ', ';
echo LR\Filters::escapeHtmlText($var3) /* line 10 */;
echo "\n";
}

}
11 changes: 11 additions & 0 deletions tests/Latte/expected/BlockMacros.define.args4.html
@@ -0,0 +1,11 @@

named arguments import


a) Variables 1, ,


b) Variables , 1,


c) Variables , ,
29 changes: 29 additions & 0 deletions tests/Latte/expected/BlockMacros.define.args4.phtml
@@ -0,0 +1,29 @@
<?php
%A%

final class Template%a% extends Latte\Runtime\Template
{

public function main(): array
{
extract($this->params);
echo '
named arguments import
';
$this->createTemplate("import.latte", $this->params, "import")->render();
echo '
a) ';
$this->renderBlock($__nm = 'test', [1, 'var1' => 2] + [], 'html');
echo '
b) ';
$this->renderBlock($__nm = 'test', ['var2' => 1] + [], 'html');
echo '
c) ';
$this->renderBlock($__nm = 'test', ['hello' => 1] + [], 'html');
return get_defined_vars();
}

}

0 comments on commit ce2b118

Please sign in to comment.