Packages

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

Classes

  • CacheMacro
  • CoreMacros
  • FormMacros
  • MacroSet
  • UIMacros
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (http://nette.org)
  5:  *
  6:  * Copyright (c) 2004, 2011 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(Parser $parser)
 45:     {
 46:         $me = new self($parser);
 47: 
 48:         $me->addMacro('if', array($me, 'macroIf'), array($me, 'macroEndIf'));
 49:         $me->addMacro('elseif', 'elseif (%node.args):');
 50:         $me->addMacro('else', 'else:');
 51:         $me->addMacro('ifset', 'if (isset(%node.args)):', 'endif');
 52:         $me->addMacro('elseifset', 'elseif (isset(%node.args)):');
 53: 
 54:         $me->addMacro('foreach', array($me, 'macroForeach'), '$iterations++; endforeach; array_pop($_l->its); $iterator = end($_l->its)');
 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('syntax', array($me, 'macroSyntax'), array($me, 'macroSyntax'));
 76:         $me->addMacro('capture', array($me, 'macroCapture'), array($me, 'macroCaptureEnd'));
 77:         $me->addMacro('include', array($me, 'macroInclude'));
 78:         $me->addMacro('use', array($me, 'macroUse'));
 79: 
 80:         $me->addMacro('@href', NULL, NULL); // TODO: placeholder
 81:         $me->addMacro('@class', array($me, 'macroClass'));
 82:         $me->addMacro('@attr', array($me, 'macroAttr'));
 83:         $me->addMacro('attr', array($me, 'macroOldAttr'));
 84:     }
 85: 
 86: 
 87: 
 88:     /**
 89:      * Finishes template parsing.
 90:      * @return array(prolog, epilog)
 91:      */
 92:     public function finalize()
 93:     {
 94:         return array('list($_l, $_g) = CoreMacros::initRuntime($template, '
 95:             . var_export($this->parser->templateId, TRUE) . ')');
 96:     }
 97: 
 98: 
 99: 
100:     /********************* macros ****************d*g**/
101: 
102: 
103: 
104:     /**
105:      * {if ...}
106:      */
107:     public function macroIf(MacroNode $node, $writer)
108:     {
109:         if ($node->data->capture = ($node->args === '')) {
110:             return 'ob_start()';
111:         }
112:         return $writer->write('if (%node.args):');
113:     }
114: 
115: 
116: 
117:     /**
118:      * {/if ...}
119:      */
120:     public function macroEndIf(MacroNode $node, $writer)
121:     {
122:         if ($node->data->capture) {
123:             if ($node->args === '') {
124:                 throw new LatteException('Missing condition in {if} macro.');
125:             }
126:             return $writer->write('if (%node.args) ob_end_flush(); else ob_end_clean()');
127:         }
128:         return 'endif';
129:     }
130: 
131: 
132: 
133:     /**
134:      * {_$var |modifiers}
135:      */
136:     public function macroTranslate(MacroNode $node, $writer)
137:     {
138:         if ($node->closing) {
139:             return $writer->write('echo %modify($template->translate(ob_get_clean()))');
140: 
141:         } elseif ($node->isEmpty = ($node->args !== '')) {
142:             return $writer->write('echo %modify($template->translate(%node.args))');
143: 
144:         } else {
145:             return 'ob_start()';
146:         }
147:     }
148: 
149: 
150: 
151:     /**
152:      * {syntax name}
153:      */
154:     public function macroSyntax(MacroNode $node)
155:     {
156:         if ($node->closing) {
157:             $node->args = 'latte';
158:         }
159:         switch ($node->args) {
160:         case '':
161:         case 'latte':
162:             $this->parser->setDelimiters('\\{(?![\\s\'"{}])', '\\}'); // {...}
163:             break;
164: 
165:         case 'double':
166:             $this->parser->setDelimiters('\\{\\{(?![\\s\'"{}])', '\\}\\}'); // {{...}}
167:             break;
168: 
169:         case 'asp':
170:             $this->parser->setDelimiters('<%\s*', '\s*%>'); /* <%...%> */
171:             break;
172: 
173:         case 'python':
174:             $this->parser->setDelimiters('\\{[{%]\s*', '\s*[%}]\\}'); // {% ... %} | {{ ... }}
175:             break;
176: 
177:         case 'off':
178:             $this->parser->setDelimiters('[^\x00-\xFF]', '');
179:             break;
180: 
181:         default:
182:             throw new LatteException("Unknown syntax '$node->args'");
183:         }
184:     }
185: 
186: 
187: 
188:     /**
189:      * {include "file" [,] [params]}
190:      */
191:     public function macroInclude(MacroNode $node, $writer)
192:     {
193:         $code = $writer->write('CoreMacros::includeTemplate(%node.word, %node.array? + $template->getParams(), $_l->templates[%var])',
194:             $this->parser->templateId);
195: 
196:         if ($node->modifiers) {
197:             return $writer->write('echo %modify(%raw->__toString(TRUE))', $code);
198:         } else {
199:             return $code . '->render()';
200:         }
201:     }
202: 
203: 
204: 
205:     /**
206:      * {use class MacroSet}
207:      */
208:     public function macroUse(MacroNode $node, $writer)
209:     {
210:         call_user_func(array($node->tokenizer->fetchWord(), 'install'), $this->parser)
211:             ->initialize();
212:     }
213: 
214: 
215: 
216:     /**
217:      * {capture $variable}
218:      */
219:     public function macroCapture(MacroNode $node, $writer)
220:     {
221:         $variable = $node->tokenizer->fetchWord();
222:         if (substr($variable, 0, 1) !== '$') {
223:             throw new LatteException("Invalid capture block variable '$variable'");
224:         }
225:         $node->data->variable = $variable;
226:         return 'ob_start()';
227:     }
228: 
229: 
230: 
231:     /**
232:      * {/capture}
233:      */
234:     public function macroCaptureEnd(MacroNode $node, $writer)
235:     {
236:         return $writer->write("{$node->data->variable} = %modify(ob_get_clean())");
237:     }
238: 
239: 
240: 
241:     /**
242:      * {foreach ...}
243:      */
244:     public function macroForeach(MacroNode $node, $writer)
245:     {
246:         return '$iterations = 0; foreach ($iterator = $_l->its[] = new SmartCachingIterator('
247:             . preg_replace('#(.*)\s+as\s+#i', '$1) as ', $writer->formatArgs(), 1) . '):';
248:     }
249: 
250: 
251: 
252:     /**
253:      * n:class="..."
254:      */
255:     public function macroClass(MacroNode $node, $writer)
256:     {
257:         return $writer->write('if ($_l->tmp = trim(implode(" ", array_unique(%node.array)))) echo \' class="\' . %escape($_l->tmp) . \'"\'');
258:     }
259: 
260: 
261: 
262:     /**
263:      * n:attr="..."
264:      */
265:     public function macroAttr(MacroNode $node, $writer)
266:     {
267:         return $writer->write('echo Html::el(NULL, %node.array)->attributes()');
268:     }
269: 
270: 
271: 
272:     /**
273:      * {attr ...}
274:      * @deprecated
275:      */
276:     public function macroOldAttr(MacroNode $node)
277:     {
278:         return Strings::replace($node->args . ' ', '#\)\s+#', ')->');
279:     }
280: 
281: 
282: 
283:     /**
284:      * {dump ...}
285:      */
286:     public function macroDump(MacroNode $node, $writer)
287:     {
288:         $args = $writer->formatArgs();
289:         return $writer->write('Debugger::barDump(' . ($node->args ? "array(%var => $args)" : 'get_defined_vars()')
290:             . ', "Template " . str_replace(dirname(dirname($template->getFile())), "\xE2\x80\xA6", $template->getFile()))', $args);
291:     }
292: 
293: 
294: 
295:     /**
296:      * {debugbreak ...}
297:      */
298:     public function macroDebugbreak(MacroNode $node, $writer)
299:     {
300:         return $writer->write(($node->args == NULL ? '' : 'if (!(%node.args)); else')
301:             . 'if (function_exists("debugbreak")) debugbreak(); elseif (function_exists("xdebug_break")) xdebug_break()');
302:     }
303: 
304: 
305: 
306:     /**
307:      * {var ...}
308:      * {default ...}
309:      */
310:     public function macroVar(MacroNode $node, $writer)
311:     {
312:         $out = '';
313:         $var = TRUE;
314:         $tokenizer = $writer->preprocess();
315:         while ($token = $tokenizer->fetchToken()) {
316:             if ($var && ($token['type'] === MacroTokenizer::T_SYMBOL || $token['type'] === MacroTokenizer::T_VARIABLE)) {
317:                 if ($node->name === 'default') {
318:                     $out .= "'" . ltrim($token['value'], "$") . "'";
319:                 } else {
320:                     $out .= '$' . ltrim($token['value'], "$");
321:                 }
322:                 $var = NULL;
323: 
324:             } elseif (($token['value'] === '=' || $token['value'] === '=>') && $token['depth'] === 0) {
325:                 $out .= $node->name === 'default' ? '=>' : '=';
326:                 $var = FALSE;
327: 
328:             } elseif ($token['value'] === ',' && $token['depth'] === 0) {
329:                 $out .= $node->name === 'default' ? ',' : ';';
330:                 $var = TRUE;
331: 
332:             } elseif ($var === NULL && $node->name === 'default' && $token['type'] !== MacroTokenizer::T_WHITESPACE) {
333:                 throw new LatteException("Unexpected '$token[value]' in {default $node->args}");
334: 
335:             } else {
336:                 $out .= $writer->canQuote($tokenizer) ? "'$token[value]'" : $token['value'];
337:             }
338:         }
339:         return $node->name === 'default' ? "extract(array($out), EXTR_SKIP)" : $out;
340:     }
341: 
342: 
343: 
344:     /**
345:      * {= ...}
346:      * {? ...}
347:      */
348:     public function macroExpr(MacroNode $node, $writer)
349:     {
350:         return $writer->write(($node->name === '?' ? '' : 'echo ') . '%modify(%node.args)');
351:     }
352: 
353: 
354: 
355:     /********************* run-time helpers ****************d*g**/
356: 
357: 
358: 
359:     /**
360:      * Includes subtemplate.
361:      * @param  mixed      included file name or template
362:      * @param  array      parameters
363:      * @param  ITemplate  current template
364:      * @return Template
365:      */
366:     public static function includeTemplate($destination, $params, $template)
367:     {
368:         if ($destination instanceof ITemplate) {
369:             $tpl = $destination;
370: 
371:         } elseif ($destination == NULL) { // intentionally ==
372:             throw new InvalidArgumentException("Template file name was not specified.");
373: 
374:         } else {
375:             $tpl = clone $template;
376:             if ($template instanceof IFileTemplate) {
377:                 if (substr($destination, 0, 1) !== '/' && substr($destination, 1, 1) !== ':') {
378:                     $destination = dirname($template->getFile()) . '/' . $destination;
379:                 }
380:                 $tpl->setFile($destination);
381:             }
382:         }
383: 
384:         $tpl->setParams($params); // interface?
385:         return $tpl;
386:     }
387: 
388: 
389: 
390:     /**
391:      * Initializes local & global storage in template.
392:      * @param  ITemplate
393:      * @param  string
394:      * @return stdClass
395:      */
396:     public static function initRuntime($template, $templateId)
397:     {
398:         // local storage
399:         if (isset($template->_l)) {
400:             $local = $template->_l;
401:             unset($template->_l);
402:         } else {
403:             $local = (object) NULL;
404:         }
405:         $local->templates[$templateId] = $template;
406: 
407:         // global storage
408:         if (!isset($template->_g)) {
409:             $template->_g = (object) NULL;
410:         }
411: 
412:         return array($local, $template->_g);
413:     }
414: 
415: }
416: 
Nette Framework 2.0beta1 (for PHP 5.2) API API documentation generated by ApiGen 2.3.0