Packages

  • 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

Classes

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