Namespaces

  • Latte
    • Loaders
    • Macros
    • Runtime
  • Nette
    • Application
      • Responses
      • Routers
      • UI
    • Bridges
      • ApplicationDI
      • ApplicationLatte
      • ApplicationTracy
      • CacheDI
      • CacheLatte
      • DatabaseDI
      • DatabaseTracy
      • DITracy
      • FormsDI
      • FormsLatte
      • Framework
      • HttpDI
      • HttpTracy
      • MailDI
      • ReflectionDI
      • SecurityDI
      • SecurityTracy
    • Caching
      • Storages
    • ComponentModel
    • Database
      • Conventions
      • Drivers
      • Reflection
      • Table
    • DI
      • Config
        • Adapters
      • Extensions
    • Diagnostics
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Latte
    • Loaders
    • Localization
    • Mail
    • Neon
    • PhpGenerator
    • Reflection
    • Security
    • Templating
    • Utils
  • NetteModule
  • none
  • Tracy
    • Bridges
      • Nette

Classes

  • BlockMacros
  • BlockMacrosRuntime
  • CoreMacros
  • MacroSet
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (http://nette.org)
  5:  * Copyright (c) 2004 David Grudl (http://davidgrudl.com)
  6:  */
  7: 
  8: namespace Latte\Macros;
  9: 
 10: use Latte,
 11:     Latte\CompileException,
 12:     Latte\MacroNode,
 13:     Latte\PhpWriter;
 14: 
 15: 
 16: /**
 17:  * Basic macros for Latte.
 18:  *
 19:  * - {if ?} ... {elseif ?} ... {else} ... {/if}
 20:  * - {ifset ?} ... {elseifset ?} ... {/ifset}
 21:  * - {for ?} ... {/for}
 22:  * - {foreach ?} ... {/foreach}
 23:  * - {$variable} with escaping
 24:  * - {=expression} echo with escaping
 25:  * - {?expression} evaluate PHP statement
 26:  * - {_expression} echo translation with escaping
 27:  * - {attr ?} HTML element attributes
 28:  * - {capture ?} ... {/capture} capture block to parameter
 29:  * - {var var => value} set template parameter
 30:  * - {default var => value} set default template parameter
 31:  * - {dump $var}
 32:  * - {debugbreak}
 33:  * - {contentType ...} HTTP Content-Type header
 34:  * - {status ...} HTTP status
 35:  * - {l} {r} to display { }
 36:  *
 37:  * @author     David Grudl
 38:  */
 39: class CoreMacros extends MacroSet
 40: {
 41: 
 42: 
 43:     public static function install(Latte\Compiler $compiler)
 44:     {
 45:         $me = new static($compiler);
 46: 
 47:         $me->addMacro('if', array($me, 'macroIf'), array($me, 'macroEndIf'));
 48:         $me->addMacro('elseif', '} elseif (%node.args) {');
 49:         $me->addMacro('else', array($me, 'macroElse'));
 50:         $me->addMacro('ifset', 'if (isset(%node.args)) {', '}');
 51:         $me->addMacro('elseifset', '} elseif (isset(%node.args)) {');
 52:         $me->addMacro('ifcontent', array($me, 'macroIfContent'), array($me, 'macroEndIfContent'));
 53: 
 54:         $me->addMacro('switch', '$_l->switch[] = (%node.args); if (FALSE) {', '} array_pop($_l->switch)');
 55:         $me->addMacro('case', '} elseif (end($_l->switch) === (%node.args)) {');
 56: 
 57:         $me->addMacro('foreach', '', array($me, 'macroEndForeach'));
 58:         $me->addMacro('for', 'for (%node.args) {', '}');
 59:         $me->addMacro('while', 'while (%node.args) {', '}');
 60:         $me->addMacro('continueIf', array($me, 'macroBreakContinueIf'));
 61:         $me->addMacro('breakIf', array($me, 'macroBreakContinueIf'));
 62:         $me->addMacro('first', 'if ($iterator->isFirst(%node.args)) {', '}');
 63:         $me->addMacro('last', 'if ($iterator->isLast(%node.args)) {', '}');
 64:         $me->addMacro('sep', 'if (!$iterator->isLast(%node.args)) {', '}');
 65: 
 66:         $me->addMacro('var', array($me, 'macroVar'));
 67:         $me->addMacro('default', array($me, 'macroVar'));
 68:         $me->addMacro('dump', array($me, 'macroDump'));
 69:         $me->addMacro('debugbreak', array($me, 'macroDebugbreak'));
 70:         $me->addMacro('l', '?>{<?php');
 71:         $me->addMacro('r', '?>}<?php');
 72: 
 73:         $me->addMacro('_', array($me, 'macroTranslate'), array($me, 'macroTranslate'));
 74:         $me->addMacro('=', array($me, 'macroExpr'));
 75:         $me->addMacro('?', array($me, 'macroExpr'));
 76: 
 77:         $me->addMacro('capture', array($me, 'macroCapture'), array($me, 'macroCaptureEnd'));
 78:         $me->addMacro('include', array($me, 'macroInclude'));
 79:         $me->addMacro('use', array($me, 'macroUse'));
 80:         $me->addMacro('contentType', array($me, 'macroContentType'));
 81:         $me->addMacro('status', array($me, 'macroStatus'));
 82:         $me->addMacro('php', array($me, 'macroExpr'));
 83: 
 84:         $me->addMacro('class', NULL, NULL, array($me, 'macroClass'));
 85:         $me->addMacro('attr', NULL, NULL, array($me, 'macroAttr'));
 86:     }
 87: 
 88: 
 89:     /**
 90:      * Finishes template parsing.
 91:      * @return array(prolog, epilog)
 92:      */
 93:     public function finalize()
 94:     {
 95:         return array('list($_b, $_g, $_l) = $template->initialize('
 96:             . var_export($this->getCompiler()->getTemplateId(), TRUE) . ', '
 97:             . var_export($this->getCompiler()->getContentType(), TRUE)
 98:         . ')');
 99:     }
100: 
101: 
102:     /********************* macros ****************d*g**/
103: 
104: 
105:     /**
106:      * {if ...}
107:      */
108:     public function macroIf(MacroNode $node, PhpWriter $writer)
109:     {
110:         if ($node->data->capture = ($node->args === '')) {
111:             return 'ob_start()';
112:         }
113:         if ($node->prefix === $node::PREFIX_TAG) {
114:             return $writer->write($node->htmlNode->closing ? 'if (array_pop($_l->ifs)) {' : 'if ($_l->ifs[] = (%node.args)) {');
115:         }
116:         return $writer->write('if (%node.args) {');
117:     }
118: 
119: 
120:     /**
121:      * {/if ...}
122:      */
123:     public function macroEndIf(MacroNode $node, PhpWriter $writer)
124:     {
125:         if ($node->data->capture) {
126:             if ($node->args === '') {
127:                 throw new CompileException('Missing condition in {if} macro.');
128:             }
129:             return $writer->write('if (%node.args) '
130:                 . (isset($node->data->else) ? '{ ob_end_clean(); ob_end_flush(); }' : 'ob_end_flush();')
131:                 . ' else '
132:                 . (isset($node->data->else) ? '{ $_l->else = ob_get_contents(); ob_end_clean(); ob_end_clean(); echo $_l->else; }' : 'ob_end_clean();')
133:             );
134:         }
135:         return '}';
136:     }
137: 
138: 
139:     /**
140:      * {else}
141:      */
142:     public function macroElse(MacroNode $node, PhpWriter $writer)
143:     {
144:         $ifNode = $node->parentNode;
145:         if ($ifNode && $ifNode->name === 'if' && $ifNode->data->capture) {
146:             if (isset($ifNode->data->else)) {
147:                 throw new CompileException('Macro {if} supports only one {else}.');
148:             }
149:             $ifNode->data->else = TRUE;
150:             return 'ob_start()';
151:         }
152:         return '} else {';
153:     }
154: 
155: 
156:     /**
157:      * n:ifcontent
158:      */
159:     public function macroIfContent(MacroNode $node, PhpWriter $writer)
160:     {
161:         if (!$node->prefix) {
162:             throw new CompileException("Unknown macro {{$node->name}}, use n:{$node->name} attribute.");
163:         } elseif ($node->prefix !== MacroNode::PREFIX_NONE) {
164:             throw new CompileException("Unknown attribute n:{$node->prefix}-{$node->name}, use n:{$node->name} attribute.");
165:         }
166: 
167:         return $writer->write('ob_start()');
168:     }
169: 
170: 
171:     /**
172:      * n:ifcontent
173:      */
174:     public function macroEndIfContent(MacroNode $node, PhpWriter $writer)
175:     {
176:         preg_match('#(^.*?>)(.*)(<.*\z)#s', $node->content, $parts);
177:         $node->content = $parts[1]
178:             . '<?php ob_start() ?>'
179:             . $parts[2]
180:             . '<?php $_l->ifcontent = ob_get_contents(); ob_end_flush() ?>'
181:             . $parts[3];
182:         return 'rtrim($_l->ifcontent) === "" ? ob_end_clean() : ob_end_flush()';
183:     }
184: 
185: 
186:     /**
187:      * {_$var |modifiers}
188:      */
189:     public function macroTranslate(MacroNode $node, PhpWriter $writer)
190:     {
191:         if ($node->closing) {
192:             return $writer->write('echo %modify($template->translate(ob_get_clean()))');
193: 
194:         } elseif ($node->isEmpty = ($node->args !== '')) {
195:             return $writer->write('echo %modify($template->translate(%node.args))');
196: 
197:         } else {
198:             return 'ob_start()';
199:         }
200:     }
201: 
202: 
203:     /**
204:      * {include "file" [,] [params]}
205:      */
206:     public function macroInclude(MacroNode $node, PhpWriter $writer)
207:     {
208:         $code = $writer->write('$_b->templates[%var]->renderChildTemplate(%node.word, %node.array? + $template->getParameters())',
209:             $this->getCompiler()->getTemplateId());
210: 
211:         if ($node->modifiers) {
212:             return $writer->write('ob_start(); %raw; echo %modify(ob_get_clean())', $code);
213:         } else {
214:             return $code;
215:         }
216:     }
217: 
218: 
219:     /**
220:      * {use class MacroSet}
221:      */
222:     public function macroUse(MacroNode $node, PhpWriter $writer)
223:     {
224:         call_user_func(Latte\Helpers::checkCallback(array($node->tokenizer->fetchWord(), 'install')), $this->getCompiler())
225:             ->initialize();
226:     }
227: 
228: 
229:     /**
230:      * {capture $variable}
231:      */
232:     public function macroCapture(MacroNode $node, PhpWriter $writer)
233:     {
234:         $variable = $node->tokenizer->fetchWord();
235:         if (substr($variable, 0, 1) !== '$') {
236:             throw new CompileException("Invalid capture block variable '$variable'");
237:         }
238:         $node->data->variable = $variable;
239:         return 'ob_start()';
240:     }
241: 
242: 
243:     /**
244:      * {/capture}
245:      */
246:     public function macroCaptureEnd(MacroNode $node, PhpWriter $writer)
247:     {
248:         return $node->data->variable . $writer->write(' = %modify(ob_get_clean())');
249:     }
250: 
251: 
252:     /**
253:      * {foreach ...}
254:      */
255:     public function macroEndForeach(MacroNode $node, PhpWriter $writer)
256:     {
257:         if ($node->modifiers !== '|noiterator' && preg_match('#\W(\$iterator|include|require|get_defined_vars)\W#', $this->getCompiler()->expandTokens($node->content))) {
258:             $node->openingCode = '<?php $iterations = 0; foreach ($iterator = $_l->its[] = new Latte\Runtime\CachingIterator('
259:             . preg_replace('#(.*)\s+as\s+#i', '$1) as ', $writer->formatArgs(), 1) . ') { ?>';
260:             $node->closingCode = '<?php $iterations++; } array_pop($_l->its); $iterator = end($_l->its) ?>';
261:         } else {
262:             $node->openingCode = '<?php $iterations = 0; foreach (' . $writer->formatArgs() . ') { ?>';
263:             $node->closingCode = '<?php $iterations++; } ?>';
264:         }
265:     }
266: 
267: 
268:     /**
269:      * {breakIf ...}
270:      * {continueIf ...}
271:      */
272:     public function macroBreakContinueIf(MacroNode $node, PhpWriter $writer)
273:     {
274:         $cmd = str_replace('If', '', $node->name);
275:         if ($node->parentNode && $node->parentNode->prefix === $node::PREFIX_NONE) {
276:             return $writer->write("if (%node.args) { echo \"</{$node->parentNode->htmlNode->name}>\\n\"; $cmd; }");
277:         }
278:         return $writer->write("if (%node.args) $cmd");
279:     }
280: 
281: 
282:     /**
283:      * n:class="..."
284:      */
285:     public function macroClass(MacroNode $node, PhpWriter $writer)
286:     {
287:         if (isset($node->htmlNode->attrs['class'])) {
288:             throw new CompileException('It is not possible to combine class with n:class.');
289:         }
290:         return $writer->write('if ($_l->tmp = array_filter(%node.array)) echo \' class="\' . %escape(implode(" ", array_unique($_l->tmp))) . \'"\'');
291:     }
292: 
293: 
294:     /**
295:      * n:attr="..."
296:      */
297:     public function macroAttr(MacroNode $node, PhpWriter $writer)
298:     {
299:         return $writer->write('echo Latte\Runtime\Filters::htmlAttributes(%node.array)');
300:     }
301: 
302: 
303:     /**
304:      * {dump ...}
305:      */
306:     public function macroDump(MacroNode $node, PhpWriter $writer)
307:     {
308:         $args = $writer->formatArgs();
309:         return $writer->write(
310:             'Tracy\Debugger::barDump(' . ($args ? "($args)" : 'get_defined_vars()'). ', %var)',
311:             $args ?: 'variables'
312:         );
313:     }
314: 
315: 
316:     /**
317:      * {debugbreak ...}
318:      */
319:     public function macroDebugbreak(MacroNode $node, PhpWriter $writer)
320:     {
321:         return $writer->write(($node->args == NULL ? '' : 'if (!(%node.args)); else')
322:             . 'if (function_exists("debugbreak")) debugbreak(); elseif (function_exists("xdebug_break")) xdebug_break()');
323:     }
324: 
325: 
326:     /**
327:      * {var ...}
328:      * {default ...}
329:      */
330:     public function macroVar(MacroNode $node, PhpWriter $writer)
331:     {
332:         if ($node->args === '' && $node->parentNode && $node->parentNode->name === 'switch') {
333:             return '} else {';
334:         }
335: 
336:         $var = TRUE;
337:         $tokens = $writer->preprocess();
338:         $res = new Latte\MacroTokens;
339:         while ($tokens->nextToken()) {
340:             if ($var && $tokens->isCurrent(Latte\MacroTokens::T_SYMBOL, Latte\MacroTokens::T_VARIABLE)) {
341:                 if ($node->name === 'default') {
342:                     $res->append("'" . ltrim($tokens->currentValue(), '$') . "'");
343:                 } else {
344:                     $res->append('$' . ltrim($tokens->currentValue(), '$'));
345:                 }
346:                 $var = NULL;
347: 
348:             } elseif ($tokens->isCurrent('=', '=>') && $tokens->depth === 0) {
349:                 $res->append($node->name === 'default' ? '=>' : '=');
350:                 $var = FALSE;
351: 
352:             } elseif ($tokens->isCurrent(',') && $tokens->depth === 0) {
353:                 if ($var === NULL) {
354:                     $res->append($node->name === 'default' ? '=>NULL' : '=NULL');
355:                 }
356:                 $res->append($node->name === 'default' ? ',' : ';');
357:                 $var = TRUE;
358: 
359:             } elseif ($var === NULL && $node->name === 'default' && !$tokens->isCurrent(Latte\MacroTokens::T_WHITESPACE)) {
360:                 throw new CompileException("Unexpected '{$tokens->currentValue()}' in {default $node->args}");
361: 
362:             } else {
363:                 $res->append($tokens->currentToken());
364:             }
365:         }
366:         if ($var === NULL) {
367:             $res->append($node->name === 'default' ? '=>NULL' : '=NULL');
368:         }
369:         $out = $writer->quoteFilter($res)->joinAll();
370:         return $node->name === 'default' ? "extract(array($out), EXTR_SKIP)" : $out;
371:     }
372: 
373: 
374:     /**
375:      * {= ...}
376:      * {? ...}
377:      */
378:     public function macroExpr(MacroNode $node, PhpWriter $writer)
379:     {
380:         return $writer->write(($node->name === '=' ? 'echo ' : '') . '%modify(%node.args)');
381:     }
382: 
383: 
384:     /**
385:      * {contentType ...}
386:      */
387:     public function macroContentType(MacroNode $node, PhpWriter $writer)
388:     {
389:         if (strpos($node->args, 'xhtml') !== FALSE) {
390:             $this->getCompiler()->setContentType(Latte\Compiler::CONTENT_XHTML);
391: 
392:         } elseif (strpos($node->args, 'html') !== FALSE) {
393:             $this->getCompiler()->setContentType(Latte\Compiler::CONTENT_HTML);
394: 
395:         } elseif (strpos($node->args, 'xml') !== FALSE) {
396:             $this->getCompiler()->setContentType(Latte\Compiler::CONTENT_XML);
397: 
398:         } elseif (strpos($node->args, 'javascript') !== FALSE) {
399:             $this->getCompiler()->setContentType(Latte\Compiler::CONTENT_JS);
400: 
401:         } elseif (strpos($node->args, 'css') !== FALSE) {
402:             $this->getCompiler()->setContentType(Latte\Compiler::CONTENT_CSS);
403: 
404:         } elseif (strpos($node->args, 'calendar') !== FALSE) {
405:             $this->getCompiler()->setContentType(Latte\Compiler::CONTENT_ICAL);
406: 
407:         } else {
408:             $this->getCompiler()->setContentType(Latte\Compiler::CONTENT_TEXT);
409:         }
410: 
411:         // temporary solution
412:         if (strpos($node->args, '/')) {
413:             return $writer->write('header(%var)', "Content-Type: $node->args");
414:         }
415:     }
416: 
417: 
418:     /**
419:      * {status ...}
420:      */
421:     public function macroStatus(MacroNode $node, PhpWriter $writer)
422:     {
423:         return $writer->write((substr($node->args, -1) === '?' ? 'if (!headers_sent()) ' : '') .
424:             'header((isset($_SERVER["SERVER_PROTOCOL"]) ? $_SERVER["SERVER_PROTOCOL"] : "HTTP/1.1") . " " . %0.var, TRUE, %0.var)', (int) $node->args
425:         );
426:     }
427: 
428: }
429: 
Nette 2.3.1 API API documentation generated by ApiGen 2.8.0