У меня есть переднее приложение Symfony, которое принимает сериализованную форму Symfony из API, анализирует ее и, наконец, отображает ее.
Это приложение должно быть глупым и не должно каким-либо образом знать логику какого-либо удаленного приложения. Он просто принимает форму json и отображает ее после анализа.
Поля в сериализованной форме имеют настраиваемые (определенные удаленным приложением) имена блоков, которые затем используются в темах форм переднего приложения для построения структур полей.
Указанный пример поля:
"field_1": {
"options": {
"block_name": "block_name_example",
"label": "Example",
"required": true,
"disabled": false,
"choices": {
"Choice 1": "1",
"Choice 2": "2"
},
"help_description": "",
"attr": {
"name": "field_name_1",
"short_name": "fieldName1"
}
},
"type": "Symfony\\Component\\Form\\Extension\\Core\\Type\\ChoiceType"
}
Я хотел бы в блоке form_theme добавить что-то «при первом совпадении этого имени блока» (например), без какой-либо логики, добавленной на стороне удаленного приложения, что-то вроде:
{% block _form_block_name_example %}
{% if match_occurrence = 1 %}
{# do something here #}
{% endif %}
{{ form_widget(form) }}
{% endblock %}
Я знаю, что есть много способов (дополнительная опция поля формы, обернуть его в поле типа коллекции ...), чтобы решить эту проблему с помощью удаленного редактирования кода приложения, но я не хочу этого по разным причинам, основная из которых заключается в том, чтобы избежать каких-либо дополнительная сложность кода удаленного приложения.
Не удалось найти чистый способ решить эту проблему. Ты будешь моим героем?




Я придумал довольно простой способ справиться с этим только на лицевой стороне приложения. Максимально убрал классы из несвязанного кода и переименовал некоторые вещи, чтобы сделать его как можно более универсальным для вас.
Я добавил новую дополнительную опцию first_of_type в свои поля через расширение формы, которое я установил при создании формы. Затем я использую его как случайный вариант в блоке моей темы формы. Код ниже.
Расширение формы:
class ExtraOptionsExtension extends AbstractTypeExtension
{
/**
* Add the width option.
*
* @param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefined([
/* ... */
'first_of_type'
]);
}
public function buildView(FormView $view, FormInterface $form, array $options)
{
/* ... */
$view->vars['first_of_type'] = false;
if (!empty($options['first_of_type'])) {
$view->vars['first_of_type'] = true;
}
}
/**
* Returns the name of the type being extended.
*
* @return string The name of the type being extended
*/
public function getExtendedType()
{
return FormType::class;
}
}
Тип формы:
abstract class AbstractType extends BaseAbstractType
{
/* ... */
/**
* {@inheritdoc}
*
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$blockNames = [];
if (is_array($this->fields)) {
foreach ($this->fields as $property => $data) {
$type = $data['type'] ?? null;
$opts = $data['options'] ?? [];
if (!in_array($type, $this::TYPES_WITHOUT_EXTRA) &&
isset($data['options']['block_name']) &&
!in_array($data['options']['block_name'], $blockNames)) {
$blockNames[] = $data['options']['block_name'];
$opts['first_of_type'] = true;
}
$builder->add($property, $type, $opts);
}
}
}
/* ... */
}
Блок темы формы:
{% block custom_block %}
<div class = "form-group form-inline {% if not first_of_type %} hide {% else %}">
{{ form_label(form, null, {'label_attr': {'class': 'control-label'}}) }}
{{ form_widget(form) }}
</div>
{% endblock %}
Все еще можно улучшить, чтобы предоставить больше информации о положении элемента по сравнению с его парами (не только тем, что он первый).