/** * Tal extension to translate the values in an array. * * This Tal accepts an array and, via its helper function, returns a new * array with identical keys but with values translated using the current * translator. * * This Tal is most useful in translating an array before sorting it based * on the translated content. Note that variable replacement in the post- * translated string should still work but plurals won't. * * Example use within template: * <span * tal:define="translatedArray Ztal_Tales_Translation.translateArrayValues:originalArray" * tal:repeat="item translatedArray" * tal:content="item" * /> * * @param string $src The original string from the source template. * @param bool $nothrow Whether to throw an exception on error or not. * * @return string */ public static function translateArrayValues($src, $nothrow) { $break = strpos($src, '|'); if ($break !== false) { $src = substr($src, 0, $break); } return 'Ztal_Tales_Translation::arrayTranslationHelper(' . phptal_tale($src, $nothrow) . ', $_translator)'; }
function phptal_tales_calcxp($src, $nothrow) { $exp = Template::SplitSRC($src); $args = explode(' ', trim($src)); if (count($args) !== 2) { throw new PHPTAL_InvalidVariableNameException("calcxp takes two arguments, XP and CHG."); } $xp = phptal_tale($args[0]); $chg = phptal_tale($args[1]); array_unshift($exp, 'phptal_func_calcxp(' . $xp . ',' . $chg . ')'); return $exp; }
private function _getTranslationCode($key) { $code = '<?php '; if (preg_match_all('/\\$\\{(.*?)\\}/', $key, $m)) { array_shift($m); $m = array_shift($m); foreach ($m as $name) { $code .= "\n" . '$_translator->setVar(\'' . $name . '\',' . phptal_tale($name) . ');'; // allow more complex TAL expressions } $code .= "\n"; } // notice the false boolean which indicate that the html is escaped // elsewhere looks like an hack doesn't it ? :) $result = $this->tag->generator->escapeCode(sprintf('$_translator->translate(%s, false)', $key)); $code .= 'echo ' . $result . '?>'; return $code; }
function testTaleNeverReturnsArray() { $this->assertInternalType('string', phptal_tale('foo | bar | baz | nothing')); }
/** * urlencode: modifier. Escapes a string. */ public static function urlencode($src, $nothrow) { return 'rawurlencode(' . phptal_tale($src, $nothrow) . ')'; }
/** * Tal extension to inject slot content into a variable. * * Slot names cannot (currently) be dynamic in phptal so this tale * allows us to grab the content of a slot with a dynamic name and * assign it to a variable which we can then output. * * Example use within template: * <tal:block tal:define="slotContent Ztal\Tales\Form.getSlotContent:slotName" /> * * @param string $src The original template string. * @param bool $nothrow Whether to throw an exception on error. * * @return string */ public static function getSlotContent($src, $nothrow) { $break = strpos($src, '|'); if ($break === false) { $slotName = $src; $notTrue = 'NULL'; } else { $slotName = substr($src, 0, $break); $notTrue = substr($src, $break + 1); } return '($ctx->hasSlot(' . phptal_tale($slotName, $nothrow) . ')?$ctx->getSlot(' . phptal_tale($slotName, $nothrow) . '):' . phptal_tale($notTrue, $nothrow) . ')'; }
/** * Tal for doing PHP's array merging. * * Return an array of the items in array1 unioned with the items in array2. * * Note that if key mode is used, the php + operator is applied to merge * the arrays (which prefers array1's value for a key that exists in both * arrays) but the values are not compared and filtered for uniqueness. * If value mode is selected, keys are discarded and the arrays merged * using array_merge before filtered for uniqueness with array_unique. * * Example usage: * <span tal:define="complement Ztal\Tales\ArrayUtils.complement:mode,array1,array2" /> * * mode may be: * key - diff on keys * value - diff on values * * See the php array_diff and array_diff_key functions for more details * * @param string $src The original template string. * @param bool $nothrow Whether to throw an exception on error. * * @return string */ public static function union($src, $nothrow) { $break = strpos($src, '|'); if ($break !== false) { $src = substr($src, 0, $break); } $parts = explode(',', $src); return '(' . phptal_tale($parts[0], $nothrow) . ' == \'key\' ? (' . phptal_tale($parts[1], $nothrow) . '+' . phptal_tale($parts[2], $nothrow) . ')) : array_unique(array_values(' . phptal_tale($parts[1], $nothrow) . '), array_values(' . phptal_tale($parts[2], $nothrow) . ')))'; }
public static function nozero($src, $nothrow) { $exp = Template::SplitSRC($src, $nothrow); array_unshift($exp, 'Template_Tales::nozeroFUNC(' . phptal_tale($src, $nothrow) . ')'); return $exp; }
public static function json($src, $nothrow) { return 'json_encode(' . phptal_tale($src, $nothrow) . ')'; }
function phptal_tales_lang($attr) { list($index, $current) = explode(' ', $attr, 2); return 't(\'' . $index . '\'' . ($current ? ', ' . phptal_tale($current) : '') . ')'; }
/** * Tal to support filtering of an array. * * Example usage: * * <span * tal:define="keys string:key1,key2" * tal:repeat="arr Ztal_Tales_Generic.arrayFilter:string:mode,keys,array * /> * * mode may be: * key - Filter items by the array key. * value - Filter items by the array value. * * The last parameter is the original array to filter, this should be a * PHPTAL variable. * * @param string $src The original template string. * @param bool $nothrow Whether to throw an exception on error. * * @return string */ public static function arrayFilter($src, $nothrow) { $regex = "/([a-zA-Z:]+)\\s*?,\\s*?([a-zA-Z0-9:]+)\\s*?,\\s*?([^|\$]+)\$/"; $src = trim($src); // If we can't find a match for our parameters simply return NULL. if (!preg_match($regex, $src, $items)) { return phptal_tales('NULL', $nothrow); } // Call the array filtering helper with: // // $items[1] = Type of filtering (e.g. key or value). // $items[2] = PHPTAL variable (array) of items to filter with, or a // string of comma seperated items, // $items[3] = PHPTAL variable of haystack array. // true = Exclude rather than filter. return "Ztal_Tales_Generic::arrayFilterHelper(\n\n\t\t\t" . phptal_tale($items[1], $nothrow) . ",\n\t\t\t" . phptal_tale($items[2], $nothrow) . ",\n\t\t\t" . phptal_tale($items[3], $nothrow) . ")"; }
/** * returns PHP code that will evaluate given TALES expression. * e.g. "string:foo${bar}" may be transformed to "'foo'.phptal_escape($ctx->bar)" * * Expressions with alternatives ("foo | bar") will cause it to return array * Use PHPTAL_Php_TalesInternal::compileToPHPExpression() if you always want string. * * @param bool $nothrow if true, invalid expression will return NULL (at run time) rather than throwing exception * @return string or array */ public static function compileToPHPStatements($expression, $nothrow = false) { $expression = trim($expression); // Look for tales modifier (string:, exists:, etc...) //if (preg_match('/^([-a-z]+):(.*?)$/', $expression, $m)) { #if (preg_match('/^([_a-z][.a-z_-]*[a-z]):(.*)$/si', $expression, $m)) { if (preg_match('/^([a-z_][a-z0-9_]*):(.*)$/si', $expression, $m)) { list(, $typePrefix, $expression) = $m; } elseif (preg_match('/^\'((?:[^\']|\\\\.)*)\'$/s', $expression, $m)) { $expression = stripslashes($m[1]); $typePrefix = 'string'; } else { $typePrefix = 'path'; } // is a registered TALES expression modifier if (PHPTAL_TalesRegistry::getInstance()->isRegistered($typePrefix)) { $callback = PHPTAL_TalesRegistry::getInstance()->getCallback($typePrefix); return call_user_func($callback, $expression, $nothrow); } // class method if (strpos($typePrefix, '.')) { $classCallback = explode('.', $typePrefix, 2); $callbackName = null; if (!is_callable($classCallback, FALSE, $callbackName)) { throw new PHPTAL_UnknownModifierException("Unknown phptal modifier {$typePrefix}. Function {$callbackName} does not exists or is not statically callable"); } $ref = new ReflectionClass($classCallback[0]); if (!$ref->implementsInterface('PHPTAL_Tales')) { throw new PHPTAL_UnknownModifierException("Unable to use phptal modifier {$typePrefix} as the class {$callbackName} does not implement the PHPTAL_Tales interface"); } return call_user_func($classCallback, $expression, $nothrow); } // check if it is implemented via code-generating function $func = 'phptal_tales_' . str_replace('-', '_', $typePrefix); if (function_exists($func)) { return $func($expression, $nothrow); } elseif (function_exists($func2 = str_replace('-', '_', $typePrefix))) { return $func2 . '(' . phptal_tale($expression) . ')'; } // check if it is implemented via runtime function $runfunc = 'phptal_runtime_tales_' . str_replace('-', '_', $typePrefix); if (function_exists($runfunc)) { return "{$runfunc}(" . self::compileToPHPExpression($expression, $nothrow) . ")"; } throw new PHPTAL_UnknownModifierException("Unknown phptal modifier '{$typePrefix}'. Function '{$func}' does not exist"); }
/** * Generic tales modifier for Zend_View helpers * * @param string $exp * @param bool $nothrow */ function phptal_tales_helper($exp, $nothrow) { if (preg_match('/^([A-Za-z_]+)\\(([^)]*)\\)/', $exp, $m)) { $args = explode(',', $m[2]); foreach ($args as &$arg) { $arg = phptal_tale($arg, $nothrow); } $exp = 'php:this->' . $m[1] . '(' . implode(', ', $args) . ')'; } else { list($helper, $param) = explode(' ', $exp, 2); $exp = 'php:this->' . $helper . '(' . phptal_tales($param, $nothrow) . ')'; } return phptal_tale($exp, $nothrow); }
private function _interpolateTalesVarsEscaped($matches) { return '<?php echo phptal_escape(' . phptal_tale($matches[1]) . ', ENT_QUOTES, \'' . $this->_encoding . '\');?>'; }
function phptal_tales($expression, $nothrow = false) { $expression = trim($expression); // Look for tales modifier (string:, exists:, etc...) //if (preg_match('/^([-a-z]+):(.*?)$/', $expression, $m)) { if (preg_match('/^([a-z][-.a-z]*[a-z]):(.*?)$/i', $expression, $m)) { list(, $typePrefix, $expression) = $m; } else { if (preg_match('/^\'((?:[^\']|\\\\.)*)\'$/', $expression, $m)) { $expression = stripslashes($m[1]); $typePrefix = 'string'; } else { $typePrefix = 'path'; } } // is a registered TALES expression modifier if (PHPTAL_TalesRegistry::getInstance()->isRegistered($typePrefix)) { $callback = PHPTAL_TalesRegistry::getInstance()->getCallback($typePrefix); return call_user_func($callback, $expression, $nothrow); } // class method if (strpos($typePrefix, '.')) { $classCallback = explode('.', $typePrefix, 2); $callbackName = NULL; if (!is_callable($classCallback, FALSE, $callbackName)) { $err = 'Unknown phptal modifier %s function %s does not exists or is not statically callable.'; $err = sprintf($err, $typePrefix, $callbackName); throw new PHPTAL_Exception($err); } $ref = new ReflectionClass($classCallback[0]); if (!$ref->implementsInterface('PHPTAL_Tales')) { $err = 'Unable to use phptal modifier %s as the class %s does not implement the PHPTAL_Tales interface.'; $err = sprintf($err, $typePrefix, $callbackName); throw new PHPTAL_Exception($err); } return call_user_func($classCallback, $expression, $nothrow); } // check if it is implemented via code-generating function $func = 'phptal_tales_' . str_replace('-', '_', $typePrefix); if (function_exists($func)) { return $func($expression, $nothrow); } // check if it is implemented via runtime function $runfunc = 'phptal_runtime_tales_' . str_replace('-', '_', $typePrefix); if (function_exists($runfunc)) { return "{$runfunc}(" . phptal_tale($expression, $nothrow) . ")"; } throw new PHPTAL_Exception("Unknown phptal modifier '{$typePrefix}'. Function '{$func}' does not exist"); }
/** * Formats a number to a certain decimal place. * * Formats the number to the provided decimal place - that's numberwang! * Example use within template: * * <span * tal:content="Ztal\Tales\Generic.numberFormatDecimal:numberVar,string:2" * />. * * @param string $src The original template string. * @param bool $nothrow Whether to throw an exception on error. * * @return string */ public static function numberFormatDecimal($src, $nothrow) { $break = strpos($src, ','); $variable = substr($src, 0, $break); $src = substr($src, $break + 1); $break = strpos($src, '|'); if ($break === false) { $decimal = $src; } else { $decimal = substr($src, 0, $break); } return 'number_format(' . phptal_tale($variable, $nothrow) . ', ' . phptal_tale($decimal, $nothrow) . ')'; }