使用ArrayCollection进行表单编辑

时间:2017-02-08 10:54:59

标签: php forms symfony symfony-forms

主题的快速解释:

  • A"项目"可以有几个"活动"

  • 我必须同时创建尽可能多的"活动"根据需要(你点击一个按钮"添加一个活动"你有一个新的线,这意味着一个新的活动)。我设法通过在我的领域进行收藏来做到这一点。

这是formBuilder的代码:

namespace CoreBundle\Form\Type;

use CoreBundle\Entity\Activities;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class CreateNewActivitiesType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add(
                'aeAmount',
                CollectionType::class,
                array(
                    'entry_type'    => TextType::class,
                    'allow_add'     => true,
                    'allow_delete'  => true,
                    'label'         => 'Montant de l\'AE',
                    'label_attr'    => array(
                        'class'     => 'aeAmount visuallyhidden'
                    ),
                    'entry_options' => array(
                        'attr'      => array(
                            'placeholder'   => '80 000 €'
                        ),

                    ),
                    'required'      => true
                )
            )
            ->add(
                'amountSpent',
                CollectionType::class,
                array(
                    'entry_type'    => TextType::class,
                    'allow_add'     => true,
                    'allow_delete'  => true,
                    'label'         => 'RDP : ',
                    'label_attr'    => array(
                        'class'     => 'amountSpent visuallyhidden'
                    ),
                    'entry_options' => array(
                        'attr'      => array(
                            'placeholder'   => '35 000 €'
                        )
                    ),
                    'required'      => true,
                )
            )
            ->add(
                'afName',
                CollectionType::class,
                array(
                    'entry_type'    => TextType::class,
                    'allow_add'     => true,
                    'allow_delete'  => true,
                    'required'      => true,
                    'label'         => 'AF : ',
                    'label_attr'    => array(
                        'class'     => 'afName visuallyhidden',
                    ),
                    'entry_options' => array(
                        'attr'      => array(
                            'placeholder'   => 'AERT-496'
                        )
                    )
                )
            )
            ->add(
                'year',
                CollectionType::class,
                array(
                    'entry_type'    => TextType::class,
                    'allow_delete'  => true,
                    'allow_add'     => true,
                    'required'      => true,
                    'entry_options' => array(
                        'attr'      => array(
                            'readonly'  => true
                        )
                    ),
                    'label'         => 'Année : ',
                    'label_attr'    => array(
                        'class'     => 'year visuallyhidden'
                    )
                )
            )
        ;
    }

    /**
     * {@inheritdoc}
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'CoreBundle\Entity\Activities'
        ));
    }

    /**
     * {@inheritdoc}
     */
    public function getBlockPrefix()
    {
        return 'corebundle_collection_activities';
    }
}

(我知道我可以做得更短,但重构将会更晚。)

所以,这个目前正在使用,他的相关控制器可以添加我的活动,这里是:

/**
     * @param integer $projectId
     * @param string $projectType
     * @param integer $rdId
     *
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function createNewActivityAction($projectId, $projectType, $rdId)
    {
        $activity = new Activities();
        $request = $this->get('request_stack')->getCurrentRequest();

        $form = $this->createForm(CreateNewActivitiesType::class, $activity);
        $form->handleRequest($request);
        $em = $this->getDoctrine()->getManager();


        if ($form->isSubmitted() && $form->isValid()) {
            $rdAffiliated = $em->getRepository('CoreBundle:DecisionStatement')->findOneBy(['id' => $rdId]);

            $formData = $form->getData();
            $yearList = $formData->getYear();
            $aeAmountList = $formData->getAeAmount();
            $afNameList = $formData->getAfName();
            $amountSpentList = $formData->getAmountSpent();

            for ($i = 0; $i < count($yearList); $i++) {
                $yearDatetime = new DateTime($yearList[$i] . '-01-01 00:00:00');
                $existingActivity = $em->getRepository('CoreBundle:Activities')->getExistingActivityWithoutIdentifier(
                    $yearDatetime,
                    $rdAffiliated
                );

                if ($existingActivity) {
                    /**
                     * @var Activities $currentActivity
                     */
                    $currentActivity = $existingActivity[0];
                    $currentActivity->setAeAmount(
                        $currentActivity->getAeAmount() + $aeAmountList[$i]
                    );
                    $currentActivity->setAmountSpent(
                        $currentActivity->getAmountSpent() + $amountSpentList[$i]
                    );

                    $em->persist($currentActivity);
                } else {
                    $newActivity = new Activities();
                    $newActivity->setYear($yearDatetime)
                        ->setAeAmount($aeAmountList[$i])
                        ->setAfName($afNameList[$i])
                        ->setAmountSpent($amountSpentList[$i])
                        ->setAfReception(false)
                        ->setDecisionStatement($rdAffiliated)
                        ->setPeopleByMonth(0);

                    $em->persist($newActivity);
                }
            }

            $em->flush();

            return $this->redirectToRoute('rd_show_activities', array(
                'rdId'          => $rdId,
                'projectType'   => $projectType,
                'projectId'     => $projectId
            ));
        }

        return $this->render('@Core/html/13-edit-activite.html.twig', array(
            'page'                 => 'activities_creation',
            'createActivitiesForm' => $form->createView(),
            'projectParentId'      => $projectId,
            'projectParentType'    => $projectType,
            'rdId'                 => $rdId
        ));
    }

以下是提交活动表格时var_dump的屏幕截图:

Spinning Cursor

但是我的问题在哪里开始,就是我想要编辑的时候,因为我的表单基于实体&#34;活动&#34;。但我想编辑所有现有的&#34;活动&#34;对于给定的项目,我将有一个包含我的&#34;活动&#34;对象(由findBy方法找到),所以我不能将我的数组传递给我的表单,这会导致错误。 如何转换这些数组&#34;活动&#34;对象只进入一个&#34;活动&#34;对象

3 个答案:

答案 0 :(得分:0)

我不明白为什么你只有一个对象&#34;活动&#34;包含几个集合。 您应该创建一个包含多个活动的对象活动。 每个活动只有一个属性&#34;年&#34;,&#34; amountSpent&#34; ... 当你编辑你的对象&#34; ActivitieS&#34;使用适当的表单,您将能够编辑与此对象链接的每个活动。

答案 1 :(得分:0)

嵌入表格集合

要正确管理此类问题,您需要在Symfony中构建Collection of forms

  
      
  1. “项目”可以有多个“活动”
  2.   
  3. 我必须同时创建所需数量的“活动” [...]
  4.   

首先,您需要构建一个 Project 实体,该实体将包含所有 Activities 作为Doctrine ArrayCollection,如下所示:

的src /的appbundle /实体/ Project.php

namespace AppBundle\Entity;

use Doctrine\Common\Collections\ArrayCollection;

class Project
{

    protected $activities;

    public function __construct()
    {
        $this->activities = new ArrayCollection();
    }

    public function getTags()
    {
        return $this->tags;
    }
}

的src /的appbundle /窗体/类型/ ProjectType.php

namespace AppBundle\Form\Type;

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

class ProjectType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('tags', CollectionType::class, array(
            'entry_type' => ActivitiesType::class,
            'allow_add'    => true,
        ));
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => Project::class,
        ));
    }
}

然后,您需要允许用户使用Twig和JavaScript动态地向项目添加活动,以便利用prototype变量。

答案 2 :(得分:0)

我已经考虑了你所做的所有评论,并决定审查整个事情。

DecisionStatement.php:

  • 在__construct()方法中添加了一个新的ArrayCollection,用于为给定的DecisionStatement附属的活动。
  • 返回附属活动的方法已经在这里。

documents = new ArrayCollection();             $ this-&gt; activitiesAffiliated = new ArrayCollection();         }

/**
 * Get activitiesAffiliated
 *
 * @return \Doctrine\Common\Collections\Collection
 */
public function getActivitiesAffiliated()
{
    return $this->activitiesAffiliated;
}

我已经创建了一个新的FormType(DecisionStatementType.php),以获得我的表单集合:

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

class DecisionStatementType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add(
                'activitiesAffiliated',
                CollectionType::class,
                array(
                    'entry_type'    => NewActivityType::class,
                    'allow_add'     => true,
                    'allow_delete'  => true
                )
            )
        ;
    }

    /**
     * {@inheritdoc}
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => DecisionStatement::class
        ));
    }

    /**
     * {@inheritdoc}
     */
    public function getBlockPrefix()
    {
        return 'corebundle_collection_decisionstatement';
    }
}

这是“subForm”,newActivityType.php:

use CoreBundle\Entity\Activities;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class NewActivityType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add(
                'aeAmount',
                TextType::class,
                array(
                    'label'         => 'Montant de l\'AE',
                    'label_attr'    => array(
                        'class'     => 'aeAmount visuallyhidden'
                    ),
                    'attr'      => array(
                        'placeholder'   => '80 000 €'
                    ),
                    'required'      => true
                )
            )
            ->add(
                'amountSpent',
                TextType::class,
                array(
                    'label'         => 'RDP : ',
                    'label_attr'    => array(
                        'class'     => 'amountSpent visuallyhidden'
                    ),
                    'attr'      => array(
                        'placeholder'   => '35 000 €'
                    ),
                    'required'      => true,
                )
            )
            ->add(
                'afName',
                TextType::class,
                array(
                    'required'      => true,
                    'label'         => 'AF : ',
                    'label_attr'    => array(
                        'class'     => 'afName visuallyhidden',
                    ),
                    'attr'      => array(
                        'placeholder'   => 'AERT-496'
                    )
                )
            )
        ;
    }

    /**
     * {@inheritdoc}
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'CoreBundle\Entity\Activities'
        ));
    }

    /**
     * {@inheritdoc}
     */
    public function getBlockPrefix()
    {
        return 'corebundle_collection_activities';
    }
}

在我看来的DOM中,我现在有了这个:

FormCollection Data-Prototype in DOM

那么,这有点清洁吗?