Условно скрыть некоторые поля (коллекции) встроенных форм в Symfony

Я использую Symfony 3.4.

У меня есть страны и вопросы. Затем у меня есть объект ответов, который связан как с странами, так и с вопросами.

В вопросе я определяю ожидаемый тип ответа (логический, строковый и т. д.).

Чтобы зафиксировать это в сущности ответов, у меня есть несколько полей, соответствующих нескольким типам полей, которые я определил.

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

Для этого я использую форму collectionType из страны.

Но у меня две проблемы:

  • как отображать сами вопросы во встроенных формах
  • как в каждом ответе я могу скрыть поля, которые не являются обязательными (не того типа, который соответствует вопросу).

То, что кажется очень простым при рассмотрении одного вопроса, кажется непонятным, когда приходится обрабатывать все вопросы / ответы для данной страны.

Вот мой код:

страна

    <?php

namespace cwt\psmdbBundle\Entity;

use APY\DataGridBundle\Grid\Mapping as GRID;
use Doctrine\ORM\Mapping as ORM;

/**
 * countries
 *
 * @ORM\Table()
 * @ORM\Entity(repositoryClass = "cwt\psmdbBundle\Entity\Repository\countriesRepository")
 */
class countries
{
    /**
     * @var integer
     *
     * @ORM\Column(name = "id", type = "integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy = "AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name = "name", type = "string", length=100)
     */
    private $name;

    /**
     * @ORM\OneToMany(targetEntity = "cwt\psmdbBundle\Entity\CcdbServicesAnswers", mappedBy = "country", cascade = {"persist", "remove"})
     */
    private $ccdbServicesAnswers;

сущность вопросов:

    <?php

namespace cwt\psmdbBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use APY\DataGridBundle\Grid\Mapping as GRID;

/**
 * CcdbServicesQuestions
 *
 * @ORM\Table(name = "ccdb_services_questions")
 * @ORM\Entity(repositoryClass = "cwt\psmdbBundle\Repository\CcdbServicesQuestionsRepository")
 */
class CcdbServicesQuestions
{
    /**
     * @var int
     *
     * @ORM\Column(name = "id", type = "integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy = "AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name = "question", type = "string", length=255)
     */
    private $question;

    /**
     * @ORM\ManyToOne(targetEntity = "cwt\psmdbBundle\Entity\CcdbServicesCategories")
     * @ORM\JoinColumn(nullable=false)
     * @GRID\Column(field = "category.name", title = "Category")
     */
    private $category;

    /**
     * @ORM\ManyToOne(targetEntity = "cwt\psmdbBundle\Entity\FieldTypes")
     * @ORM\JoinColumn(nullable=false)
     * @GRID\Column(field = "fieldType.name", title = "Field Type")
     */
    private $fieldType;

    /**
     * @ORM\OneToMany(targetEntity = "cwt\psmdbBundle\Entity\CcdbServicesAnswers", mappedBy = "question", cascade = {"persist", "remove"})
     */
    private $ccdbServicesAnswers;

отвечает объект:

    <?php

namespace cwt\psmdbBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;

/**
 * CcdbServicesAnswers
 *
 * @ORM\Table(name = "ccdb_services_answers")
 * @ORM\Entity(repositoryClass = "cwt\psmdbBundle\Repository\CcdbServicesAnswersRepository")
 */
class CcdbServicesAnswers
{
    /**
     * @var int
     *
     * @ORM\Column(name = "id", type = "integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy = "AUTO")
     */
    private $id;

    /**
     * @var string|null
     *
     * @ORM\Column(name = "stringField", type = "string", length=255, nullable=true)
     */
    private $stringField;

    /**
     * @var string|null
     *
     * @ORM\Column(name = "textField", type = "text", nullable=true)
     */
    private $textField;

    /**
     * @var bool|null
     *
     * @ORM\Column(name = "booleanField", type = "boolean", nullable=true)
     */
    private $booleanField;

    /**
     * @var int|null
     *
     * @ORM\Column(name = "integerField", type = "integer", nullable=true)
     */
    private $integerField;

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

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

    /**
     * @var string|null
     *
     * @ORM\Column(name = "comment", type = "string", length=255, nullable=true)
     */
    private $comment;

    /**
     * @ORM\ManyToOne(targetEntity = "countries", inversedBy = "ccdbServicesAnswers")
     * @ORM\JoinColumn(nullable=false)
     */
    private $country;

    /**
     * @ORM\ManyToOne(targetEntity = "cwt\psmdbBundle\Entity\CcdbServicesQuestions", inversedBy = "ccdbServicesAnswers")
     * @ORM\JoinColumn(nullable=false)
     */
    private $question;

Вот форма для моей страны:

<?php

namespace cwt\psmdbBundle\Form;

use cwt\psmdbBundle\Entity\countries;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;

class countriesCCDBServicesAnswersType extends AbstractType
{

    /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('ccdbServicesAnswers', CollectionType::class, array(
                'entry_type' => CcdbServicesAnswersType::class,
                'entry_options' => array('label' => false),
            ))
        ;

    }

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'cwt\psmdbBundle\Entity\countries'
        ));
    }

    /**
     * @return string
     */
    public function getBlockPrefix()
    {
        return 'cwt_psmdbbundle_countries';
    }
}

Вот моя форма ответов:

<?php

namespace cwt\psmdbBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
//use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\Extension\Core\Type\TextType;

class CcdbServicesAnswersType extends AbstractType
{
        /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('stringField')
            ->add('textField')
            ->add('booleanField')
            ->add('integerField')
            ->add('floatField')
            ->add('percentageField')
            ->add('comment')
//            ->add('country')
//            ->add('question')
        ;
    }

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'cwt\psmdbBundle\Entity\CcdbServicesAnswers'
        ));
    }

    /**
     * @return string
     */
    public function getName()
    {
        return 'cwt_psmdbbundle_ccdbservicesanswers';
    }
}

На данный момент довольно простой контроллер (я пытался получить доступ к полям формы, но не знаю, что оттуда делать):

    /**
     * Show answers for a given country.
     * @Route("/countries/{countryID}/edit", name = "editCountryCcdbServicesAnswers", methods = {"GET"})
     * @Security("has_role('ROLE_USER')")
     *
     */
    public function editCountriesCcdbServicesAnswers($countryID)
    {


//        // Get categories
        $em = $this->getDoctrine()->getManager();
        $categories = $em->getRepository('psmdbBundle:CcdbServicesCategories')->findAll();

        // $questions = $em->getRepository('psmdbBundle:CcdbServicesQuestions')->findAll();

        // Get all answers for this country
        $country = $em->getRepository('psmdbBundle:countries')->find($countryID);

        $form = $this->createCountryEditForm($country);

        foreach ($form as $field) {

            $fieldClass = get_class($field);

            if (get_class($field)=='Symfony\Component\Form\Form') {
                foreach ($field as $answerForm) {

                    foreach ($answerForm as $answerField) {

                    }

                }
            }

        }



        return $this->render('psmdbBundle:ccdb_services_answers:edit_country.html.twig', array(
            'categories' => $categories,
            'form' => $form->createView(),
            'entity' => $country,
//            'delete_form' => $deleteForm->createView(),
            'show' => 'ccdbservicesanswers_show',
            'cancel' => 'ccdbservicesanswers_show',
            'title' => 'CCDB Services',
        ));

    }

И вот шаблон (довольно бесполезный, поскольку он отображает все поля для каждого ответа и не отображает вопросы ...):

{% extends 'psmdbBundle:templates:edit.html.twig' %}

    {% block form_body -%}
        <div class = "col-lg-5">

            {{ form(form) }}

        </div>
    {% endblock form_body %}

Одно из решений, о котором я думаю, - это добавить поля вопросов в мою форму ответов, чтобы иметь возможность использовать их в теме формы. Но я понятия не имею, лучший ли это подход, и меня беспокоит производительность.

Другое решение - использовать вызовы ajax в представлении шоу, чтобы создать форму на лету после нажатия кнопки «изменить» по конкретному вопросу, но я не уверен в удобстве использования!

Для информации более 100 вопросов.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Symfony Station Communiqué - 17 февраля 2023 г
Symfony Station Communiqué - 17 февраля 2023 г
Это коммюнике первоначально появилось на Symfony Station , вашем источнике передовых новостей Symfony, PHP и кибербезопасности.
Управление ответами api для исключений на Symfony с помощью KernelEvents
Управление ответами api для исключений на Symfony с помощью KernelEvents
Много раз при создании api нам нужно возвращать клиентам разные ответы в зависимости от возникшего исключения.
0
0
1 016
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Я нашел решение этих двух проблем.

Чтобы отобразить текст вопросов, мне просто нужно было добавить его в форму (отключено), а затем оформить так, чтобы он выглядел как текст, а не ввод.

Затем, чтобы отобразить только нужные мне поля ответа, я использовал события формы, как вы можете видеть ниже. Я извлекаю fieldType из вопроса и условно добавляю обязательные поля.

Вот моя окончательная форма:

<?php

namespace cwt\psmdbBundle\Form;

use FOS\CKEditorBundle\Form\Type\CKEditorType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\PercentType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\OptionsResolver;
//use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use cwt\psmdbBundle\Form\GpscSwitchType;

class CcdbServicesAnswersType extends AbstractType
{
        /**
     * @param FormBuilderInterface $builder
     * @param array $options
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder

            ->add('question', textType::class, array(
                    'disabled' => true,
                    'label'     => false,
                    'attr' => array('class' => 'ccdb-form-question'),
                )
            );
        $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
            $answer = $event->getData();
            $question = $answer->getQuestion();
            $fieldType = $question->getFieldType()->getName();
            $form = $event->getForm();


            switch ($fieldType) {
                case 'boolean':
                    $form->add('booleanField', GpscSwitchType::class, array(
                        'label' => false,
                        'horizontal_label_class' => 'col-lg-12',
                        'horizontal_input_wrapper_class' => 'col-lg-3',
                        'attr' => array('class' => 'ccdb-form-answer boolean-type'),
                        'required'  => false,
                    ));
                    break;
                case 'string':
                    $form->add('stringField', textAreaType::class, array(
                        'label' => false,
                        'horizontal_label_class' => 'col-lg-12',
                        'horizontal_input_wrapper_class' => 'col-lg-12',
                        'attr' => array('class' => 'ccdb-form-answer'),
                        'required'  => false,
                        ));
                    break;
                case 'integer':
                    $form->add('integerField', null, array(
                        'label' => false,
                        'horizontal_label_class' => 'col-lg-12',
                        'horizontal_input_wrapper_class' => 'col-lg-2',
                        'attr' => array('class' => 'ccdb-form-answer'),
                        'required'  => false,
                        ));
                    break;
                case 'percentage':
                    $form->add('percentageField', percentType::class, array(
                        'label' => false,
                        'scale' => 2,
                        'horizontal_label_class' => 'col-lg-12',
                        'horizontal_input_wrapper_class' => 'col-lg-2',
                        'attr' => array('class' => 'ccdb-form-answer'),
                        'required'  => false,
                        ));
                    break;
                case 'float':
                    $form->add('floatField', null, array(
                        'label' => false,
                        'horizontal_label_class' => 'col-lg-12',
                        'horizontal_input_wrapper_class' => 'col-lg-2',
                        'attr' => array('class' => 'ccdb-form-answer'),
                        'required'  => false,
                        ));
                    break;
                case 'text':
                    $form->add('textField', CKEditorType::class, array(
                        'label' => false,
                        'horizontal_label_class' => 'col-lg-12',
                        'horizontal_input_wrapper_class' => 'col-lg-12',
                        'attr' => array('class' => 'ccdb-form-answer'),
                        'required'  => false,
                        ));
                    break;
            }

            $form->add('comment', textAreaType::class, array(
                'label' => 'Comment:',
                'horizontal_label_class' => 'col-lg-12',
                'horizontal_input_wrapper_class' => 'col-lg-12',
                'attr' => array('class' => 'ccdb-form-answer ccdb-form-comment'),
                'required'  => false,
                ));


        });
    }

    /**
     * @param OptionsResolver $resolver
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'cwt\psmdbBundle\Entity\CcdbServicesAnswers'
        ));
    }

    /**
     * @return string
     */
    public function getName()
    {
        return 'cwt_psmdbbundle_ccdbservicesanswers';
    }
}

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