Как настроить форму Symfony для отношений «многие ко многим» только с добавлением, без редактирования или удаления

У меня есть много-много отношений между двумя объектами, пользователем и курсом. У меня есть таблица соединений UserCourse для отношений, в которых есть дополнительные поля для даты начала и даты истечения срока действия. Если я настрою отношения ManyToMany в Doctrine, я могу создать форму EntityTypeform, позволяющую добавлять и удалять курсы от пользователя, но я не могу заставить ее установить срок действия UserCourse, который необходимо установить с использованием даты создания записи UserCourse + a Значение термина subScriptionExpiry из сущности «Курс» (строка типа «+1 год»). Я пробовал через PrePersist, но он не срабатывает при обновлении коллекции.

/**
 * User
 *
 * @ORM\Table(name = "user")
 */
class User
{
    /**
     * @ORM\ManyToMany(targetEntity = "Course", inversedBy = "users")
     * @JoinTable(name = "course_user",
     *      joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id")},
     *      inverseJoinColumns = {@JoinColumn(name = "course_id", referencedColumnName = "id")}
     *      )
     */
    private $courses;
/**
 * Course
 *
 * @ORM\Table(name = "course")
 */
class Course

    /**
     * @ORM\ManyToMany(targetEntity = "User", mappedBy = "users")
     */
    private $users;

    /**
     * @var string|null
     *
     * @ORM\Column(name = "subscription_expiry", type = "string", length=20, nullable=true)
     */
    private $subscriptionExpiry;
/**
 * CourseUser
 *
 * @ORM\Table(name = "course_user")
 * @ORM\HasLifecycleCallbacks()
 */
class CourseUser
{
    /**
     * @var DateTime
     *
     * @Gedmo\Timestampable(on = "create")
     * @ORM\Column(name = "created_at", type = "datetime", nullable=false, options = {"default": "CURRENT_TIMESTAMP"})
     */
    private $createdAt;

    /**
     * @var DateTime|null
     *
     * @ORM\Column(name = "expiry", type = "datetime", nullable=true)
     */
    private $expiry;

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->createdAt = new DateTime();
    }

    /**
     * @ORM\PrePersist
      */
    public function updateExpiry()
    {
        $this->expiry = new DateTime($this->getCourse()->getSubscriptionExpiry());
    }
// UserController Create form
$form = $this->createForm(UserFormType::class, $user);
...
        return $this->render('user/editb.html.twig', [
            'userForm' => $form->createView()
        ]);

// UserFormType
   public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add(...) // some user fields
            ->add('courses', EntityType::class, [
                'class' => Course::class,
                'multiple' => true,
                'expanded' => true,
                'choice_label' => 'name',
                'label' => 'Courses',
                'query_builder' => function(CourseRepository $repo) {
                    return $repo->createIsActiveQueryBuilder();
                }
            ])
        ;
{{ form_start(userForm) }}
...
{{ form_row(userForm.courses) }}
<button type = "submit" class = "btn btn-primary" formnovalidate>Save</button>

{{ form_end(userForm) }}

Как настроить форму Symfony для отношений «многие ко многим» только с добавлением, без редактирования или удаления

Если я настрою его как OneToMany/ManyToOne, я смогу создать встроенную форму CollectionType, но мне нужно запретить редактирование существующих записей UserCourse, а CollectionType отображает поле курса записей UserCourse как поля выбора, в которых курс можно изменить.

/**
 * User
 *
 * @ORM\Table(name = "user")
 */
class User
{
    /**
     * @var Collection
     *
     *  @ORM\OneToMany(targetEntity = "CourseUser", mappedBy = "user", fetch = "EXTRA_LAZY", orphanRemoval=true, cascade = {"persist"})
     */
    private $userCourses;
/**
 * Course
 *
 * @ORM\Table(name = "course")
 */
class Course

    /**
     * @var Collection
     *
     * @ORM\OneToMany(targetEntity = "CourseUser", mappedBy = "course", fetch = "EXTRA_LAZY", orphanRemoval=true, cascade = {"persist"})
     */
    private $courseUsers;
// UserFormType
   public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add(...) // some user fields
            ->add('userCourses',CollectionType::class, [
                'entry_type' => UserCourseEmbeddedForm::class,
                'allow_delete' => true,
                'allow_add' => true,
                'by_reference' => false,
                'label' => false
            ])
        ;
// UserCourseEmbeddedForm
        $builder
            ->add('course', EntityType::class, [
                'class' => Course::class,
                'choice_label' => 'name',
                'label' => false,
                'query_builder' => function(CourseRepository $repo) {
                    return $repo->createIsActiveQueryBuilder();
                }
            ])
{{ form_start(userForm) }}
...
<h3>Courses</h3>
<div class = "row js-user-course-wrapper"
     data-prototype = "{{ form_widget(userForm.userCourses.vars.prototype)|e('html_attr') }}"
     data-index = "{{ userForm.userCourses|length }}"
>
    {% for userCourseForm in userForm.userCourses %}
        <div class = "col-xs-4 js-user-course-item">
            {{ form_errors(userCourseForm) }}
            {{ form_row(userCourseForm.course) }}
     </div>
    {% endfor %}
    <a href = "#" class = "js-user-course-add">
        <span class = "fa fa-plus-circle"></span>
        Add Another Course
    </a>
</div>

<button type = "submit" class = "btn btn-primary" formnovalidate>Save</button>

{{ form_end(userForm) }}

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

Как настроить форму Symfony для отношений «многие ко многим» только с добавлением, без редактирования или удаления

Есть ли способ исправить эти проблемы? Или лучший способ сделать модель данных или формы, чтобы сделать эту работу более плавной?

JS - События опций формы
JS - События опций формы
В продолжение предыдущей статьи CSS - стили, связанные с вводом формы , в этой статье мы будем использовать JS для взаимодействия с формами, на этот...
CSS - Стили, связанные с вводом формы
CSS - Стили, связанные с вводом формы
Общими стилями ввода для форм являются Input (включая Text, Radio, checkbox), Select и Textarea, из которых Input относительно прост, поэтому в этой...
Создание многостраничной формы заявления о приеме на работу с помощью Angular
Создание многостраничной формы заявления о приеме на работу с помощью Angular
Наличие на корпоративном сайте форм заявлений о приеме на работу, или "трудовых анкет", экономит время и деньги как для соискателей, так и для...
0
0
65
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Используя ваш последний подход (ManyToOne/OneToMany), используйте css, чтобы пометить раскрывающиеся списки как отключенные (во встроенной форме используйте 'attr' => ['disabled' => true], затем включите вновь отображаемые select элементы с помощью javascript. Вы также можете пометить 'allowDelete' => false в своем UserFormType, в противном случае вам может потребоваться повторно включить все элементы select при отправке формы.

разве нельзя было бы просто включить раскрывающийся список с помощью элемента проверки, если вы сделаете это таким образом?

Liam roels 02.05.2019 09:21

Что вы подразумеваете под «включить недавно отображаемые выбранные элементы с помощью javascript»? Вы имеете в виду форму «Добавить другой курс»?

Charlotte Moller 03.05.2019 19:13

@CharlotteMoller - предположительно, у вас есть код javascript, который запускается, когда вы нажимаете «Добавить другой курс», который создает новый элемент select с параметрами курса. Поскольку по моему предложению они будут отмечены как disabled, вам придется удалить атрибут disabled для вновь отображаемого элемента.

ehymel 05.05.2019 15:19

@LiamRoels - я не знаю, о каком «элементе проверки» вы упоминаете?

ehymel 05.05.2019 15:19

@ehymel, если бы кто-то просто изменил html / css в используемом им браузере и включил раскрывающийся список, чтобы выбрать то, что он хочет. Затем он мог отправить форму с некоторыми значениями, которые вы не хотели видеть отправленными. Это проблема безопасности, я думаю

Liam roels 06.05.2019 09:04

@ehymel с этим я просто имею в виду, что css здесь не правильное решение ...

Liam roels 06.05.2019 09:04

@LiamRoels - хороший момент, это легко обойти. Я полагаю, что некоторая внутренняя проверка могла бы проверить это. Я не знаю другого предложения.

ehymel 06.05.2019 17:32

@LiamRoels, ваши предложения работают, TX! Я бы предпочел отображать выбранные курсы в виде текста, а не отключенного поля выбора, которое не так привлекательно визуально. Должны ли назначенные встроенные формы курса быть элементами выбора для обработки при отправке формы для работы? Мне также нужно выяснить, как отображать только неназначенные курсы в форме «Добавить другой курс», какие-либо предложения?

Charlotte Moller 09.05.2019 20:22

Другие вопросы по теме