Namespaces

  • Nette
    • Application
      • Diagnostics
      • Responses
      • Routers
      • UI
    • Caching
      • Storages
    • ComponentModel
    • Config
      • Adapters
      • Extensions
    • Database
      • Diagnostics
      • Drivers
      • Reflection
      • Table
    • DI
      • Diagnostics
    • Diagnostics
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Latte
      • Macros
    • Loaders
    • Localization
    • Mail
    • Reflection
    • Security
      • Diagnostics
    • Templating
    • Utils
      • PhpGenerator
  • NetteModule
  • None
  • PHP

Classes

  • CacheMacro
  • CoreMacros
  • FormMacros
  • MacroSet
  • UIMacros
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (http://nette.org)
  5:  *
  6:  * Copyright (c) 2004 David Grudl (http://davidgrudl.com)
  7:  *
  8:  * For the full copyright and license information, please view
  9:  * the file license.txt that was distributed with this source code.
 10:  */
 11: 
 12: namespace Nette\Latte\Macros;
 13: 
 14: use Nette,
 15:     Nette\Latte,
 16:     Nette\Latte\CompileException,
 17:     Nette\Latte\MacroNode,
 18:     Nette\Latte\PhpWriter;
 19: 
 20: 
 21: 
 22: /**
 23:  * Basic macros for Latte.
 24:  *
 25:  * - {if ?} ... {elseif ?} ... {else} ... {/if}
 26:  * - {ifset ?} ... {elseifset ?} ... {/ifset}
 27:  * - {for ?} ... {/for}
 28:  * - {foreach ?} ... {/foreach}
 29:  * - {$variable} with escaping
 30:  * - {!$variable} without escaping
 31:  * - {=expression} echo with escaping
 32:  * - {!=expression} echo without escaping
 33:  * - {?expression} evaluate PHP statement
 34:  * - {_expression} echo translation with escaping
 35:  * - {!_expression} echo translation without escaping
 36:  * - {attr ?} HTML element attributes
 37:  * - {capture ?} ... {/capture} capture block to parameter
 38:  * - {var var => value} set template parameter
 39:  * - {default var => value} set default template parameter
 40:  * - {dump $var}
 41:  * - {debugbreak}
 42:  * - {l} {r} to display { }
 43:  *
 44:  * @author     David Grudl
 45:  */
 46: class CoreMacros extends MacroSet
 47: {
 48: 
 49: 
 50:     public static function install(Latte\Compiler $compiler)
 51:     {
 52:         $me = new static($compiler);
 53: 
 54:         $me->addMacro('if', array($me, 'macroIf'), array($me, 'macroEndIf'));
 55:         $me->addMacro('elseif', 'elseif (%node.args):');
 56:         $me->addMacro('else', array($me, 'macroElse'));
 57:         $me->addMacro('ifset', 'if (isset(%node.args)):', 'endif');
 58:         $me->addMacro('elseifset', 'elseif (isset(%node.args)):');
 59: 
 60:         $me->addMacro('foreach', '', array($me, 'macroEndForeach'));
 61:         $me->addMacro('for', 'for (%node.args):', 'endfor');
 62:         $me->addMacro('while', 'while (%node.args):', 'endwhile');
 63:         $me->addMacro('continueIf', 'if (%node.args) continue');
 64:         $me->addMacro('breakIf', 'if (%node.args) break');
 65:         $me->addMacro('first', 'if ($iterator->isFirst(%node.args)):', 'endif');
 66:         $me->addMacro('last', 'if ($iterator->isLast(%node.args)):', 'endif');
 67:         $me->addMacro('sep', 'if (!$iterator->isLast(%node.args)):', 'endif');
 68: 
 69:         $me->addMacro('var', array($me, 'macroVar'));
 70:         $me->addMacro('assign', array($me, 'macroVar')); // deprecated
 71:         $me->addMacro('default', array($me, 'macroVar'));
 72:         $me->addMacro('dump', array($me, 'macroDump'));
 73:         $me->addMacro('debugbreak', array($me, 'macroDebugbreak'));
 74:         $me->addMacro('l', '?>{<?php');
 75:         $me->addMacro('r', '?>}<?php');
 76: 
 77:         $me->addMacro('_', array($me, 'macroTranslate'), array($me, 'macroTranslate'));
 78:         $me->addMacro('=', array($me, 'macroExpr'));
 79:         $me->addMacro('?', array($me, 'macroExpr'));
 80: 
 81:         $me->addMacro('capture', array($me, 'macroCapture'), array($me, 'macroCaptureEnd'));
 82:         $me->addMacro('include', array($me, 'macroInclude'));
 83:         $me->addMacro('use', array($me, 'macroUse'));
 84: 
 85:         $me->addMacro('class', NULL, NULL, array($me, 'macroClass'));
 86:         $me->addMacro('attr', array($me, 'macroOldAttr'), '', array($me, 'macroAttr'));
 87:         $me->addMacro('href', NULL); // TODO: placeholder
 88:     }
 89: 
 90: 
 91: 
 92:     /**
 93:      * Finishes template parsing.
 94:      * @return array(prolog, epilog)
 95:      */
 96:     public function finalize()
 97:     {
 98:         return array('list($_l, $_g) = Nette\Latte\Macros\CoreMacros::initRuntime($template, '
 99:             . var_export($this->getCompiler()->getTemplateId(), TRUE) . ')');
100:     }
101: 
102: 
103: 
104:     /********************* macros ****************d*g**/
105: 
106: 
107: 
108:     /**
109:      * {if ...}
110:      */
111:     public function macroIf(MacroNode $node, PhpWriter $writer)
112:     {
113:         if ($node->data->capture = ($node->args === '')) {
114:             return 'ob_start()';
115:         }
116:         if ($node->prefix === $node::PREFIX_TAG) {
117:             return $writer->write($node->htmlNode->closing ? 'if (array_pop($_l->ifs)):' : 'if ($_l->ifs[] = (%node.args)):');
118:         }
119:         return $writer->write('if (%node.args):');
120:     }
121: 
122: 
123: 
124:     /**
125:      * {/if ...}
126:      */
127:     public function macroEndIf(MacroNode $node, PhpWriter $writer)
128:     {
129:         if ($node->data->capture) {
130:             if ($node->args === '') {
131:                 throw new CompileException('Missing condition in {if} macro.');
132:             }
133:             return $writer->write('if (%node.args) '
134:                 . (isset($node->data->else) ? '{ ob_end_clean(); ob_end_flush(); }' : 'ob_end_flush();')
135:                 . ' else '
136:                 . (isset($node->data->else) ? '{ $_else = ob_get_contents(); ob_end_clean(); ob_end_clean(); echo $_else; }' : 'ob_end_clean();')
137:             );
138:         }
139:         return 'endif';
140:     }
141: 
142: 
143: 
144:     /**
145:      * {else}
146:      */
147:     public function macroElse(MacroNode $node, PhpWriter $writer)
148:     {
149:         $ifNode = $node->parentNode;
150:         if ($ifNode && $ifNode->name === 'if' && $ifNode->data->capture) {
151:             if (isset($ifNode->data->else)) {
152:                 throw new CompileException("Macro {if} supports only one {else}.");
153:             }
154:             $ifNode->data->else = TRUE;
155:             return 'ob_start()';
156:         }
157:         return 'else:';
158:     }
159: 
160: 
161: 
162:     /**
163:      * {_$var |modifiers}
164:      */
165:     public function macroTranslate(MacroNode $node, PhpWriter $writer)
166:     {
167:         if ($node->closing) {
168:             return $writer->write('echo %modify($template->translate(ob_get_clean()))');
169: 
170:         } elseif ($node->isEmpty = ($node->args !== '')) {
171:             return $writer->write('echo %modify($template->translate(%node.args))');
172: 
173:         } else {
174:             return 'ob_start()';
175:         }
176:     }
177: 
178: 
179: 
180:     /**
181:      * {include "file" [,] [params]}
182:      */
183:     public function macroInclude(MacroNode $node, PhpWriter $writer)
184:     {
185:         $code = $writer->write('Nette\Latte\Macros\CoreMacros::includeTemplate(%node.word, %node.array? + $template->getParameters(), $_l->templates[%var])',
186:             $this->getCompiler()->getTemplateId());
187: 
188:         if ($node->modifiers) {
189:             return $writer->write('echo %modify(%raw->__toString(TRUE))', $code);
190:         } else {
191:             return $code . '->render()';
192:         }
193:     }
194: 
195: 
196: 
197:     /**
198:      * {use class MacroSet}
199:      */
200:     public function macroUse(MacroNode $node, PhpWriter $writer)
201:     {
202:         Nette\Callback::create($node->tokenizer->fetchWord(), 'install')
203:             ->invoke($this->getCompiler())
204:             ->initialize();
205:     }
206: 
207: 
208: 
209:     /**
210:      * {capture $variable}
211:      */
212:     public function macroCapture(MacroNode $node, PhpWriter $writer)
213:     {
214:         $variable = $node->tokenizer->fetchWord();
215:         if (substr($variable, 0, 1) !== '$') {
216:             throw new CompileException("Invalid capture block variable '$variable'");
217:         }
218:         $node->data->variable = $variable;
219:         return 'ob_start()';
220:     }
221: 
222: 
223: 
224:     /**
225:      * {/capture}
226:      */
227:     public function macroCaptureEnd(MacroNode $node, PhpWriter $writer)
228:     {
229:         return $node->data->variable . $writer->write(" = %modify(ob_get_clean())");
230:     }
231: 
232: 
233: 
234:     /**
235:      * {foreach ...}
236:      */
237:     public function macroEndForeach(MacroNode $node, PhpWriter $writer)
238:     {
239:         if (preg_match('#\W(\$iterator|include|require|get_defined_vars)\W#', $this->getCompiler()->expandTokens($node->content))) {
240:             $node->openingCode = '<?php $iterations = 0; foreach ($iterator = $_l->its[] = new Nette\Iterators\CachingIterator('
241:             . preg_replace('#(.*)\s+as\s+#i', '$1) as ', $writer->formatArgs(), 1) . '): ?>';
242:             $node->closingCode = '<?php $iterations++; endforeach; array_pop($_l->its); $iterator = end($_l->its) ?>';
243:         } else {
244:             $node->openingCode = '<?php $iterations = 0; foreach (' . $writer->formatArgs() . '): ?>';
245:             $node->closingCode = '<?php $iterations++; endforeach ?>';
246:         }
247:     }
248: 
249: 
250: 
251:     /**
252:      * n:class="..."
253:      */
254:     public function macroClass(MacroNode $node, PhpWriter $writer)
255:     {
256:         return $writer->write('if ($_l->tmp = array_filter(%node.array)) echo \' class="\' . %escape(implode(" ", array_unique($_l->tmp))) . \'"\'');
257:     }
258: 
259: 
260: 
261:     /**
262:      * n:attr="..."
263:      */
264:     public function macroAttr(MacroNode $node, PhpWriter $writer)
265:     {
266:         return $writer->write('echo Nette\Utils\Html::el(NULL, %node.array)->attributes()');
267:     }
268: 
269: 
270: 
271:     /**
272:      * {attr ...}
273:      * @deprecated
274:      */
275:     public function macroOldAttr(MacroNode $node)
276:     {
277:         return Nette\Utils\Strings::replace($node->args . ' ', '#\)\s+#', ')->');
278:     }
279: 
280: 
281: 
282:     /**
283:      * {dump ...}
284:      */
285:     public function macroDump(MacroNode $node, PhpWriter $writer)
286:     {
287:         $args = $writer->formatArgs();
288:         return 'Nette\Diagnostics\Debugger::barDump(' . ($node->args ? "array(" . $writer->write('%var', $args) . " => $args)" : 'get_defined_vars()')
289:             . ', "Template " . str_replace(dirname(dirname($template->getFile())), "\xE2\x80\xA6", $template->getFile()))';
290:     }
291: 
292: 
293: 
294:     /**
295:      * {debugbreak ...}
296:      */
297:     public function macroDebugbreak(MacroNode $node, PhpWriter $writer)
298:     {
299:         return $writer->write(($node->args == NULL ? '' : 'if (!(%node.args)); else')
300:             . 'if (function_exists("debugbreak")) debugbreak(); elseif (function_exists("xdebug_break")) xdebug_break()');
301:     }
302: 
303: 
304: 
305:     /**
306:      * {var ...}
307:      * {default ...}
308:      */
309:     public function macroVar(MacroNode $node, PhpWriter $writer)
310:     {
311:         $out = '';
312:         $var = TRUE;
313:         $tokenizer = $writer->preprocess();
314:         while ($token = $tokenizer->fetchToken()) {
315:             if ($var && ($token['type'] === Latte\MacroTokenizer::T_SYMBOL || $token['type'] === Latte\MacroTokenizer::T_VARIABLE)) {
316:                 if ($node->name === 'default') {
317:                     $out .= "'" . ltrim($token['value'], "$") . "'";
318:                 } else {
319:                     $out .= '$' . ltrim($token['value'], "$");
320:                 }
321:                 $var = NULL;
322: 
323:             } elseif (($token['value'] === '=' || $token['value'] === '=>') && $token['depth'] === 0) {
324:                 $out .= $node->name === 'default' ? '=>' : '=';
325:                 $var = FALSE;
326: 
327:             } elseif ($token['value'] === ',' && $token['depth'] === 0) {
328:                 $out .= $node->name === 'default' ? ',' : ';';
329:                 $var = TRUE;
330: 
331:             } elseif ($var === NULL && $node->name === 'default' && $token['type'] !== Latte\MacroTokenizer::T_WHITESPACE) {
332:                 throw new CompileException("Unexpected '$token[value]' in {default $node->args}");
333: 
334:             } else {
335:                 $out .= $writer->canQuote($tokenizer) ? "'$token[value]'" : $token['value'];
336:             }
337:         }
338:         return $node->name === 'default' ? "extract(array($out), EXTR_SKIP)" : $out;
339:     }
340: 
341: 
342: 
343:     /**
344:      * {= ...}
345:      * {? ...}
346:      */
347:     public function macroExpr(MacroNode $node, PhpWriter $writer)
348:     {
349:         return $writer->write(($node->name === '?' ? '' : 'echo ') . '%modify(%node.args)');
350:     }
351: 
352: 
353: 
354:     /********************* run-time helpers ****************d*g**/
355: 
356: 
357: 
358:     /**
359:      * Includes subtemplate.
360:      * @param  mixed      included file name or template
361:      * @param  array      parameters
362:      * @param  Nette\Templating\ITemplate  current template
363:      * @return Nette\Templating\Template
364:      */
365:     public static function includeTemplate($destination, array $params, Nette\Templating\ITemplate $template)
366:     {
367:         if ($destination instanceof Nette\Templating\ITemplate) {
368:             $tpl = $destination;
369: 
370:         } elseif ($destination == NULL) { // intentionally ==
371:             throw new Nette\InvalidArgumentException("Template file name was not specified.");
372: 
373:         } elseif ($template instanceof Nette\Templating\IFileTemplate) {
374:             if (substr($destination, 0, 1) !== '/' && substr($destination, 1, 1) !== ':') {
375:                 $destination = dirname($template->getFile()) . '/' . $destination;
376:             }
377:             $tpl = clone $template;
378:             $tpl->setFile($destination);
379: 
380:         } else {
381:             throw new Nette\NotSupportedException('Macro {include "filename"} is supported only with Nette\Templating\IFileTemplate.');
382:         }
383: 
384:         $tpl->setParameters($params); // interface?
385:         return $tpl;
386:     }
387: 
388: 
389: 
390:     /**
391:      * Initializes local & global storage in template.
392:      * @return \stdClass
393:      */
394:     public static function initRuntime(Nette\Templating\ITemplate $template, $templateId)
395:     {
396:         // local storage
397:         if (isset($template->_l)) {
398:             $local = $template->_l;
399:             unset($template->_l);
400:         } else {
401:             $local = new \stdClass;
402:         }
403:         $local->templates[$templateId] = $template;
404: 
405:         // global storage
406:         if (!isset($template->_g)) {
407:             $template->_g = new \stdClass;
408:         }
409: 
410:         return array($local, $template->_g);
411:     }
412: 
413: }
414: 
Nette Framework 2.0.7 API API documentation generated by ApiGen 2.8.0