twig - передать функцию в шаблон

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

{{ unneededclass.blah() }}

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

{{ blah() }}

Является ли это возможным?


person StoneHeart    schedule 29.08.2010    source источник
comment
У меня есть функция blah(), как я ее передаю и вызываю в ветке (используя синтаксис шаблона ветки?)   -  person StoneHeart    schedule 29.08.2010
comment
Что делает эта функция? Я только начал использовать Twig несколько недель назад, но я уверен, что вы не сможете этого сделать. Если blah() изменяет существующую переменную, лучше использовать фильтры.   -  person Austin Hyde    schedule 29.08.2010
comment
Он распечатывает некоторый html. Кстати, спасибо, я вставлю свою функцию в класс.   -  person StoneHeart    schedule 29.08.2010
comment
В таком случае, видели ли вы макросы? (Они примерно на полпути вниз по странице) Это может быть именно то, что вы ищете, и, вероятно, его проще реализовать, чем помещать вещи в класс. Я использую их для простых элементов формы и ссылок.   -  person Austin Hyde    schedule 29.08.2010


Ответы (5)


Обновление 14.05.2015

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

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

И используйте как

{{ blah() }}

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

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

Фильтры

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

Пример:

//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 для этого — это строка имени, а внутри шаблона это имя больше не является именем функции, а просто строкой.< /удар>

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

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

person Austin Hyde    schedule 29.08.2010
comment
Twig также поддерживает функции, в некоторых случаях это необходимо twig.sensiolabs.org/doc/advanced. html#функции - person dvb; 15.05.2012
comment
формы сделаны с функциями, чувак - person GorillaApe; 16.07.2012
comment
вы не можете передать функцию в шаблон - вы должны были написать это до того, как существовали замыкания. - person mpen; 14.05.2015
comment
@Mark: Черт возьми, о чем я думал? Закрытие было в версии 5.3 в 2009 году. Я обновлю свой ответ, чтобы отразить это. - person Austin Hyde; 14.05.2015
comment
Это уже не актуально. Twig_SimpleFunction устарела. Теперь используйте TwigFunction. - person HTMLGuy; 06.07.2019

Хотя вы не можете вызывать PHP напрямую, twig является расширяемым. Вы можете добавить вызываемый фильтр, чтобы вы могли применять функции 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), и вы всегда можете делать больше вещей в фильтре, например, принимать массив в качестве параметров и так далее.

person Plamen Dragiyski    schedule 25.03.2014

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

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

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

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

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

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

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

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

{{ functions.getRandomNumber }}
person Corrensanders    schedule 15.08.2012


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

Создайте анонимный класс в менеджере/контроллере/сервисе..

     $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) %}
person Ajsti.pl - Maciej Szewczyk    schedule 16.05.2018