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
  • PHP

Classes

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