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