twig - передать функцию в шаблон - PullRequest
22 голосов
/ 29 августа 2010

В настоящее время я помещаю свою функцию в класс, передаю экземпляр этого класса в шаблон и вызываю требуемую функцию как метод класса.

{{ unneededclass.blah() }}

Мне нужно сделать, как показано ниже

{{ blah() }}

Возможно ли это?

Ответы [ 5 ]

32 голосов
/ 29 августа 2010

Обновление 5/14/2015

Комментаторы указывают, что я в основном неправ. Если вам действительно нужна функция, а не фильтр или макрос, вы можете сделать это так, как указано в документе Twig :

$twig = new Twig_Environment($loader);
$function = new Twig_SimpleFunction('blah', function () {
   // ...
});
$twig->addFunction($function);

И использовать как

{{ blah() }}

Короче, нет, это невозможно.

Однако надежда не потеряна!

Фильтры

Если ваша функция blah() предназначена для изменения существующей переменной, то это filter .

Пример:

//in your PHP
function format_date($date_string,$format_string) {
    return date($format_string,strtotime($date_string));
}
$twig_env->addFilter('format_date',new Twig_Filter_Function('format_date'));

{# in your template #}
{{ some_date|format_date('n/j/Y') }}

(первый аргумент - это фильтруемая вами переменная, второй - обычным способом)

Макросы

Если, как вы указали выше, ваша функция просто выводит HTML, то это хороший кандидат на макрос .

Пример:

{# in your template #}
{% macro say_hello() %}
<p>Oh! Hello, world!</p>
{% endmacro %}

{# ... later on ... #}
{{ _self.say_hello() }}

или с параметрами:

{% macro input(name,value,type) %}
<input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value }}">
{% endmacro %}

{{ _self.input('phone_number','867-5309') }}
{{ _self.input('subscribe','yes','checkbox') }}

Почему?

Следует помнить, что шаблоны Twig представляют представление в терминах MVC. Это означает, что они изолированы с точки зрения своего окружения и могут представлять только контекст , который вы передаете им через массив данных, который вы передаете в методе $template->render().

Это хорошая вещь, поскольку она отделяет вашу презентацию от вашей логики и данных. Если вы можете произвольно вызывать функции, то вы вдруг увеличиваете эту связь, что является плохой вещью.

Другая причина этого - способ, которым PHP обрабатывает обратные вызовы. Подумайте, как вам нужно передать эту функцию в ваш шаблон ... Возможно, что-то вроде этого:

function blah() {
    return "<p>Oh! Hello, world!</p>";
}

$template = $twig_env->loadTemplate('template.html');
echo $template->render(array('blah'=>'blah'));

В вашем шаблоне контекстная переменная blah теперь представляет собой просто строку, содержащую 'blah'.

В обычном PHP, когда вы используете переменные функции, подобные этой (попробуйте использовать строковую переменную, например, функцию), она (более или менее) выполняет поиск этой функции, а затем вызывает ее. Вы не передаете функцию, просто ее имя.

Дело в том, что вы не можете передать функцию в шаблон, потому что единственным механизмом PHP для этого является строка имени, и, попав в шаблон, это имя больше не является именем функции и просто строка.

Немного затянуто, но я надеюсь, что это поможет!

Если вам нужна дополнительная документация, официальные документы: здесь .

6 голосов
/ 25 марта 2014

Хотя вы не можете напрямую вызывать PHP, ветка расширяема.Вы можете добавить вызываемый фильтр, чтобы можно было применять к функциям PHP, переданным в шаблон.

namespace My\Twig\Extension;

class LambdaFilter extends \Twig_Extension {

    public function getName() {
        return 'lambda_filter';
    }

    public function getFilters() {
        return array(
            new \Twig_SimpleFilter('call', array($this, 'doCall'))
        );
    }

    public function doCall() {
        $arguments = func_get_args();
        $callable = array_shift($arguments);
        if(!is_callable($callable)) {
            throw new InvalidArgumentException();
        }
        return call_user_func_array($callable, $arguments);
    }

}

Теперь, если вы передадите переменную my_func в шаблон, вы можете сделать my_func|call(arg1, arg2).Вы можете даже выполнять функции более высокого порядка "array_filter"|call(my_array, my_func), и вы всегда можете делать больше вещей в фильтре, например, принимать массив в качестве параметров и т. Д.

6 голосов
/ 15 августа 2012

Я был так же потерян, как и ты, мой друг, но после поиска в Интернете ответа и не нашел ни одного, я решил посмотреть, смогу ли я сделать это сам. Поэтому я хотел опубликовать свое решение здесь (хотя я знаю, что это сообщение старое), потому что это первое попадание в Google, если вы ищете эту проблему.

Вот так, на самом деле все довольно просто:

Я создал класс, который содержит мои функции и переменные, например:

class functionContainer{
        function getRandomNumber()
        {
                return rand();
        }
}
$values = array(
'functions'=> new functionContainer()
);

Итак, теперь у нас есть $ values ​​в виде массива, который содержит этот объект с функцией «getRandomNumber ()».

При отображении файла шаблона включите этот класс в качестве значения:

$twig->render('random.html', $values);

Таким образом, внутри файла шаблона вы можете просто вызвать этот метод для вызова функции и получения результата:

{{ functions.getRandomNumber }}
2 голосов
/ 30 сентября 2013

Полный ответ: http://twig.sensiolabs.org/doc/advanced.html#id2

Я предпочитаю использовать Twig Extension следующим образом:

namespace Some\Twig\Extensions;

class MenuExtensions extends \Twig_Extension
{
    public function getFunctions()
    {
        return array(
            new \Twig_SimpleFunction('sidebar_menu', [$this, 'generate_sidebar_menu']),
        );
    }

    public function generate_sidebar_menu($menu){
        return $menu;
    }

    public function getName()
    {
        return 'menu';
    }
}

В шаблоне:

{{ sidebar_menu('some text') }}
1 голос
/ 16 мая 2018

Использование Анонимный класс

Создание анонимного класса в менеджере / контроллере / службе ..

     $functions = new class($router)
    {
        public function __construct($router)
        {
            $this->router = $router;
        }

    public function getRowUrl(FileManager $fileManager)
    {
        if ($fileManager->isNode()) {
            return $this->router->generate('...', ['parent' => ...]);
        }
        return $this->router->generate('...', ['entity' => ...]);
    }
};

Вставка параметра в представление

$params=[
            'functions' => $functions

        ];



    return new Response($this->twig->render('...:index.html.twig', $params));

Используйте функцию в поле зрения

 {% set rowUrl = functions.rowUrl(entity) %}
...