Кажется, я нашел способ, действительно, это довольно простой код Synfony 4.
Надеюсь, это кому-нибудь пригодится.
(примечание: я использовал php bin/console make:entity/crud/form
для написания необходимых скриптов. Ниже описано, как мне нужно было изменить код, полученный из make
)
Итак, скажем, у меня есть альфа и бета сущности.
Я хочу иметь форму для создания нового альфа-объекта, для привязки к нему одного или нескольких бета-объектов и для заполнения значения стоимости для каждой альфа-бета-ассоциации. Я тоже хочу форму редактирования.
Сначала я создаю новый объект AlphaBeta, поля которого:
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Alpha", inversedBy="alphabetas", cascade={"persist"})
* @ORM\JoinColumn(nullable=false)
*/
private $alpha;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Beta", inversedBy="betaalphas", cascade={"persist"})
* @ORM\JoinColumn(nullable=false)
*/
private $beta;
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
private $cost;
В классе Alpha
мне нужно
/**
* @ORM\OneToMany(targetEntity="App\Entity\AlphaBeta", mappedBy="alpha", orphanRemoval=true, cascade={"persist"})
*/
private $alphabetas;
с обычными методами getAlphaBeta
, addAlphaBeta
и removeAlphaBeta
. (аналогично для Beta
)
Я создаю обычные контроллеры CRUD для нового объекта AlphaBeta
. Чтобы иметь форму AlphaBeta, которую тоже можно использовать как подчиненную форму, я определяю
class `AlphaBetaEmbeddedForm` extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder ->add('Beta', EntityType::class, array(
'class' => Beta::class,
'multiple' => false,
'expanded' => true,
'choice_label' => 'betaTitle' ))
->add('cost', TextType::class);
if(empty($options['remove_alpha_field'])) {
$builder->add('Alpha', EntityType::class, array(
'class' => Alpha::class,
'multiple' => false,
'expanded' => true,
'choice_label' => 'alphaTitle'
));}}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => AlphaBeta::class,
'remove_alpha_field' => false,
]);
}}
remove_alpha_field
- это трюк , который позволяет мне использовать вышеуказанную форму в качестве подчиненной формы внутри формы для создания Alpha
объекта:
class AlphaType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('alphaTitle')
->add('AlphaBetas', CollectionType::class, array(
'entry_type' => AlphaBetaEmbeddedForm ::class,
'entry_options' => ['label' => true, 'remove_alpha_field' => true],
'allow_add' => true,
'label' => 'Betas',
'by_reference' => false
));}
Чтобы отобразить подчиненные формы в главной форме, мне нужно добавить JS, как предложено здесь , для вставки в шаблоны new.html.twig
и edit.html.twig
для Alpha
:
{% block javascripts %} <script type="text/javascript">
jQuery(document).ready(function () {
$("#add-another-collection-widget").click(function(e){
var list = jQuery(jQuery(this).attr('data-list-selector'));
var counter = list.data('widget-counter') | list.children().length;
var newWidget = list.attr('data-prototype');
newWidget = newWidget.replace(/__name__/g, counter);
counter++;
list.data('widget-counter', counter);
var newElem = jQuery(list.attr('data-widget-tags')).html(newWidget);
newElem.appendTo(list);
});});</script>{% endblock %}
Чтобы применить последнее, кажется, вам нужно написать каждую строку в основном шаблоне формы _form.html.twig
:
{{ form_start(form) }}
<div class="my-custom-class-for-errors">
{{ form_errors(form) }}
</div>
<div id="alphaTitle">
{{ form_row(form.alphaTitle) }}
</div>
{% if form.AlphaBetas %}
<b>Betas</b> </br></br>
{% for Beta in form.AlphaBetas %}
{% for BetaField in Beta %}
{{ form_row(BetaField) }}
{% endfor %}
{% endfor %}
{% endif %}
<div id="AlphaBeta-fields-list"
data-prototype="{{ form_widget(form.AlphaBetas.vars.prototype)|e }}"
data-widget-tags="{{ '<p></p>' |e }}"
data-widget-counter="{{ form.children|length }}">
{% for AlphaBetaField in form.AlphaBetas.vars.prototype.children %}
{{ form_row(AlphaBetaField) }}
{% endfor %}
</div>
<button type="button" id="add-another-collection-widget" data-list-selector="#AlphaBeta-fields-list">Insert Beta</button>
</br>
<button class="btn">{{ button_label|default('Save') }}</button>
{{ form_end(form) }}
Вот и все.
Примечание: в основной форме для редактирования объекта Alpha я хотел бы вставить кнопки удаления для каждого объекта, связанного с бета-версией. Насколько я вижу, это невозможно, так как это означало бы вставку html-формы в html-форму. Поскольку я могу удалить ассоциацию AlphaBeta с помощью соответствующего действия по удалению AlphaBeta, это не имеет большого значения.
Если вы видите, как я могу улучшить свой код, вы можете сообщить мне об этом.