diff --git a/src/Tpl.php b/src/Tpl.php index 02ed8af..dc5e493 100644 --- a/src/Tpl.php +++ b/src/Tpl.php @@ -233,6 +233,106 @@ class Tpl { self :: $smarty -> registerPlugin("function", $name, $callable); } + /** + * Register a callable usable from template files + * @param callable $callable The callable + * @param string|null $name The name of the callable exposed in template files + * (optional, default: the function/method name) + * @param string|null $type The type of method: + * - "display" (default): the result of the callable execution will be + * displayed + * - "output_variable": the result of the callable execution will be + * assign to the template variable (name specified using + * $output_variable) + * @param string|null $output_variable The name of the output variable (optional, required if + * $type == "output_variable") + * @return void + */ + public static function register_callable($callable, $name=null, $type=null, $output_variable=null) { + if (!is_callable($callable)) + self::fatal_error("Tpl::register_callable(): invalid callable provided"); + if (is_array($callable)) { + if (is_object($callable[0])) + self::fatal_error( + "Tpl::register_callable(): can't register template function from instantiated object." + ); + $class = new \ReflectionClass($callable[0]); + $method = $class->getMethod($callable[1]); + if (!$method->isStatic()) + self::fatal_error( + "Tpl::register_callable(): can't register template function from non-static method." + ); + $callable_txt = sprintf("['\\%s', '%s']", $callable[0], $callable[1]); + $params = $method->getParameters(); + $default_smarty_function_name = sprintf( + "smarty_%s_%s", + str_replace("\\", "_", $class->getName()), + $method->getName() + ); + $default_smarty_name = $method->getName(); + } + else { + $function = new \ReflectionFunction($callable); + $default_smarty_function_name = "smarty_$function"; + $default_smarty_name = $callable; + $callable_txt = $callable; + $params = $function->getParameters(); + } + $args = []; + foreach($params as $idx => $param) { + if ($param->isOptional()) { + $args[] = sprintf( + "\$params['%s'] ?? %s", + $param->getName(), + var_export($param->getDefaultValue(), true) + ); + } + else { + $args[] = sprintf("\$params['%s']", $param->getName()); + } + } + $idx = 0; + $smarty_function_name = $default_smarty_function_name; + while (function_exists($smarty_function_name)) + $smarty_function_name = $default_smarty_function_name . $idx++; + switch($type) { + case "output_variable": + if (!$output_variable) + self::fatal_error("Tpl::register_callable(): no output variable name specified"); + $code = sprintf( + "function %s(\$params, \$smarty) { + \$smarty->assign( + '%s', + call_user_func_array(%s, [%s]) + ); + }", + $output_variable, + $smarty_function_name, + $callable_txt, + implode(", ", $args) + ); + break; + case "display": + default: + $code = sprintf( + "function %s(\$params, \$smarty) { + echo call_user_func_array(%s, [%s]); + }", + $smarty_function_name, + $callable_txt, + implode(", ", $args) + ); + } + $smarty_name = $name ?? $default_smarty_name; + Log::debug( + "Tpl::register_callable(): register template function %s from %s with following middleware ". + "function:\n%s", + $smarty_name, format_callable($callable), $code + ); + eval($code); + self::register_function($smarty_name, $smarty_function_name); + } + /** * Register a modifier usable from template files * @param string $name The modifier name