Namespaces

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

Classes

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