Symfony 4. Ассоциация ManyToMany с атрибутом.Пользовательская форма для вставки значения атрибута, как мне? - PullRequest
0 голосов
/ 19 мая 2019

Проект Symfony 4.Я не могу видеть, как кодировать следующую спецификацию.

Скажем, у меня есть две сущности Альфа и Бета.Когда я создаю альфа-объект альфа, я хочу связать (ManyToMany) с ним один или несколько бета-объектов.Я знаю, как создавать новые и редактировать формы для этого.

Я хочу обогатить таблицу соединений AlphaBeta атрибутом, скажем, Стоимость , чтобы связать бета-версию с альфой.Проблема в том, что я не могу обогатить формы выше, чтобы вставить или отредактировать значение Cost , когда я создаю объект Alpha и ассоциирую с ним объект Beta.

Существует ли стандартный способ кодирования ситуации такого рода?

Я читал, что путь состоит в том, чтобы иметь две ассоциации OneToMany Alpha-> AlphaBeta и Beta-> AlphaBeta, но даже при этом я не могу определить / отобразить форму для Alpha, чтобы создатьновый альфа-объект, чтобы связать с ним бета-объект (или более) и назначить для такой ассоциации значение стоимости.

Ваш совет очень приветствуется.Спасибо

Ответы [ 2 ]

1 голос
/ 20 мая 2019

Как правило, если сама связь / ассоциация должна иметь атрибут, то сопоставления «многие ко многим» в доктрине больше не достаточно, поскольку ассоциации не могут хранить дополнительные данные. Таким образом, вы правильно заметили, что вам нужен дополнительный AlphaBeta объект / класс, который содержит данные. (Как уже писал Али Каземи, есть учебник для этого )

Но вы удивляетесь, как поле стоимости может быть добавлено в вашу форму ...

Поскольку cost является частью AlphaBeta сущности / класса в вашем случае, поле формы должно иметь тип формы AlphaBetaType, который - вероятно, в зависимости от предоставленных опций - должен отображать AlphaType и / или BetaType субформа и поле формы cost. Темы пользовательской формы могут отображать ее таким образом, чтобы она не выглядела так, как если бы она была подчиненной, если это вызывает озабоченность. (Тем не менее, следует заметить, что темы пользовательских форм иногда могут раздражать ...)

В общем, структура / иерархия форм обычно очень напоминает структуру / иерархию сущностей. И только время от времени скрывая данные или отображая / преобразовывая их для отображения или обработки по-другому.

В качестве альтернативы вы можете добавить не отображенное поле формы и позже сохранить его в вашем AlphaBeta, но это в среднем не проще, так как оно включает "ручную" обработку.

0 голосов
/ 21 мая 2019

Кажется, я нашел способ, действительно, это довольно простой код 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, это не имеет большого значения.

Если вы видите, как я могу улучшить свой код, вы можете сообщить мне об этом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...