Я модернизирую устаревшее приложение, используя компоненты Symfony2.
Я пытался (и в основном не получилось) заменить старые шаблоны php ветками.
Часть, с которой я борюсь, состоит в следующем: каждый подшаблон имеет свой собственный класс, содержащий свою собственную логику (Сказал, что это все о наследии).
Итак, я создал расширение ветки, которое вызывает класс шаблона, а затем включает в себя суб-шаблон, передавая ему переменные, определенные классом (Вот код расширения).
например:
{% template "NavBlockTemplate" %}
NavBlockTemplate
пример.
getTemplateName
чтобы получить файл шаблона ветки для включенияgetVariables
чтобы получить переменные, необходимые для шаблонаTwig_Node_Include
указанного шаблона с данными переменнымиГрустная часть здесь такова: каждый шаблон может передавать переменные в свой конструктор подшаблонов …
Итак, что мне нужно, но не уверен, что это вообще возможно, это что-то вроде:
{% template "NavBlockTemplate" with { 'varName': value, 'var_id': otherVar.id }
Twig_Expression
объекты в php varsNavBlockTemplate
экземпляр с php компилирует vars
getTemplateName
чтобы получить файл шаблона ветки для включенияgetVariables
чтобы получить переменные, необходимые для шаблонаTwig_Node_Include
указанного шаблона с данными переменнымиТак это возможно? Любые советы о том, как этого добиться?
Значения переменных не могут быть доступны во время компиляции шаблона. Они еще не доступны.
Twig имеет 2 отдельных фазы, когда вы звоните render($name, $context)
:
2 шага легко увидеть при реализации Twig_Environment::render()
:
public function render($name, array $context = array())
{
return $this->loadTemplate($name)->render($context);
}
Ваш пользовательский тег должен учитывать это. Потребуется создать специальный класс узлов, который будет скомпилирован в необходимую логику. Вы можете посмотреть, как реализованы существующие теги Twig.
Даже имя класса, которое вы включаете, может быть доступно во время компиляции, как и вы. $expr->getAttribute('value')
будет работать, только если выражение является константным выражением, и вы не применяете его в своем парсере.
С другой стороны, использование тега в этом случае, вероятно, не лучшее решение (хотя и самое сложное). Согласно семантике Twig, функция была бы лучше. Именно поэтому Twig также ввел include()
функция как она подходит лучше. Вот как это будет выглядеть.
в шаблоне:
{{ include_legacy("NavBlockTemplate", { 'varName': value, 'var_id': otherVar.id }) }}
в расширении:
class LegacyIncludeExtension extends \TwigExtension
{
public function getFunctions()
{
return array(
new \Twig_SimpleFunction(
'include_legacy',
array($this, 'includeLegacy'),
array('is_safe' => array('all'), 'needs_environment' => true, 'needs_context' => true)
),
);
}
public function includeLegacy(\Twig_Environment $env, array $context, $name, array $variables = array())
{
$fqcn = // determine the class name
$instance = new fqcn();
$template = $instance->getTemplateName();
$variables = array_merge($instance->getVariables(), $variables);
return $env->resolveTemplate($template)->render(array_merge($context, $variables));
}
}
Последняя строка метода выполняет основную работу twig_include
. Если вам нужна поддержка для выделения контекста, это довольно просто (сделайте объединение массива шаблона условным). Поддержка ignore_missing — это больше работы, и вам было бы лучше звонить twig_include
непосредственно в таком случае:
public function includeLegacy(\Twig_Environment $env, array $context, $name, array $variables = array(), $withContext = true, $ignoreMissing = false)
{
$fqcn = // determine the class name
$instance = new fqcn();
$template = $instance->getTemplateName();
$variables = array_merge($instance->getVariables(), $variables)
return twig_include($env, $context, $template, $variables, $withContext, $ignoreMissing);
}
Других решений пока нет …