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 ($node->modifiers
80: && (!$begin || (is_string($begin) && strpos($begin, '%modify') === false))
81: && (!$end || (is_string($end) && strpos($end, '%modify') === false))
82: && (!$attr || (is_string($attr) && strpos($attr, '%modify') === false))
83: ) {
84: throw new CompileException('Modifiers are not allowed in ' . $node->getNotation());
85: }
86:
87: if ($node->args
88: && (!$begin || (is_string($begin) && strpos($begin, '%node') === false))
89: && (!$end || (is_string($end) && strpos($end, '%node') === false))
90: && (!$attr || (is_string($attr) && strpos($attr, '%node') === false))
91: ) {
92: throw new CompileException('Arguments are not allowed in ' . $node->getNotation());
93: }
94:
95: if ($attr && $node->prefix === $node::PREFIX_NONE) {
96: $node->empty = true;
97: $node->context[1] = Latte\Compiler::CONTEXT_HTML_ATTRIBUTE;
98: $res = $this->compile($node, $attr);
99: if ($res === false) {
100: return false;
101: } elseif (!$node->attrCode) {
102: $node->attrCode = "<?php $res ?>";
103: }
104: $node->context[1] = Latte\Compiler::CONTEXT_HTML_TEXT;
105:
106: } elseif ($begin) {
107: $res = $this->compile($node, $begin);
108: if ($res === false || ($node->empty && $node->prefix)) {
109: return false;
110: } elseif (!$node->openingCode && is_string($res) && $res !== '') {
111: $node->openingCode = "<?php $res ?>";
112: }
113:
114: } elseif (!$end) {
115: return false;
116: }
117: }
118:
119:
120: 121: 122: 123:
124: public function nodeClosed(MacroNode $node)
125: {
126: if (isset($this->macros[$node->name][1])) {
127: $res = $this->compile($node, $this->macros[$node->name][1]);
128: if (!$node->closingCode && is_string($res) && $res !== '') {
129: $node->closingCode = "<?php $res ?>";
130: }
131: }
132: }
133:
134:
135: 136: 137: 138:
139: private function compile(MacroNode $node, $def)
140: {
141: $node->tokenizer->reset();
142: $writer = Latte\PhpWriter::using($node);
143: return is_string($def)
144: ? $writer->write($def)
145: : call_user_func($def, $node, $writer);
146: }
147:
148:
149: 150: 151:
152: public function getCompiler()
153: {
154: return $this->compiler;
155: }
156:
157:
158:
159: protected function (MacroNode $node)
160: {
161: if ($node->tokenizer->isNext()) {
162: $args = Latte\Runtime\Filters::truncate($node->tokenizer->joinAll(), 20);
163: trigger_error("Unexpected arguments '$args' in " . $node->getNotation());
164: }
165: }
166: }
167: