1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Latte\Macros;
9:
10: use Latte;
11: use Latte\CompileException;
12: use Latte\MacroNode;
13:
14:
15: 16: 17:
18: class MacroSet implements Latte\IMacro
19: {
20: use Latte\Strict;
21:
22:
23: private $compiler;
24:
25:
26: private $macros;
27:
28:
29: public function __construct(Latte\Compiler $compiler)
30: {
31: $this->compiler = $compiler;
32: }
33:
34:
35: public function addMacro($name, $begin, $end = null, $attr = null, $flags = null)
36: {
37: if (!$begin && !$end && !$attr) {
38: throw new \InvalidArgumentException("At least one argument must be specified for macro '$name'.");
39: }
40: foreach ([$begin, $end, $attr] as $arg) {
41: if ($arg && !is_string($arg)) {
42: Latte\Helpers::checkCallback($arg);
43: }
44: }
45:
46: $this->macros[$name] = [$begin, $end, $attr];
47: $this->compiler->addMacro($name, $this, $flags);
48: return $this;
49: }
50:
51:
52: 53: 54: 55:
56: public function initialize()
57: {
58: }
59:
60:
61: 62: 63: 64:
65: public function finalize()
66: {
67: }
68:
69:
70: 71: 72: 73:
74: public function nodeOpened(MacroNode $node)
75: {
76: list($begin, $end, $attr) = $this->macros[$node->name];
77: $node->empty = !$end;
78:
79: if (
80: $node->modifiers
81: && (!$begin || (is_string($begin) && strpos($begin, '%modify') === false))
82: && (!$end || (is_string($end) && strpos($end, '%modify') === false))
83: && (!$attr || (is_string($attr) && strpos($attr, '%modify') === false))
84: ) {
85: throw new CompileException('Modifiers are not allowed in ' . $node->getNotation());
86: }
87:
88: if (
89: $node->args
90: && (!$begin || (is_string($begin) && strpos($begin, '%node') === false))
91: && (!$end || (is_string($end) && strpos($end, '%node') === false))
92: && (!$attr || (is_string($attr) && strpos($attr, '%node') === false))
93: ) {
94: throw new CompileException('Arguments are not allowed in ' . $node->getNotation());
95: }
96:
97: if ($attr && $node->prefix === $node::PREFIX_NONE) {
98: $node->empty = true;
99: $node->context[1] = Latte\Compiler::CONTEXT_HTML_ATTRIBUTE;
100: $res = $this->compile($node, $attr);
101: if ($res === false) {
102: return false;
103: } elseif (!$node->attrCode) {
104: $node->attrCode = "<?php $res ?>";
105: }
106: $node->context[1] = Latte\Compiler::CONTEXT_HTML_TEXT;
107:
108: } elseif ($begin) {
109: $res = $this->compile($node, $begin);
110: if ($res === false || ($node->empty && $node->prefix)) {
111: return false;
112: } elseif (!$node->openingCode && is_string($res) && $res !== '') {
113: $node->openingCode = "<?php $res ?>";
114: }
115:
116: } elseif (!$end) {
117: return false;
118: }
119: }
120:
121:
122: 123: 124: 125:
126: public function nodeClosed(MacroNode $node)
127: {
128: if (isset($this->macros[$node->name][1])) {
129: $res = $this->compile($node, $this->macros[$node->name][1]);
130: if (!$node->closingCode && is_string($res) && $res !== '') {
131: $node->closingCode = "<?php $res ?>";
132: }
133: }
134: }
135:
136:
137: 138: 139: 140:
141: private function compile(MacroNode $node, $def)
142: {
143: $node->tokenizer->reset();
144: $writer = Latte\PhpWriter::using($node);
145: return is_string($def)
146: ? $writer->write($def)
147: : call_user_func($def, $node, $writer);
148: }
149:
150:
151: 152: 153:
154: public function getCompiler()
155: {
156: return $this->compiler;
157: }
158:
159:
160:
161: protected function (MacroNode $node)
162: {
163: if ($node->tokenizer->isNext()) {
164: $args = Latte\Runtime\Filters::truncate($node->tokenizer->joinAll(), 20);
165: trigger_error("Unexpected arguments '$args' in " . $node->getNotation());
166: }
167: }
168: }
169: