首页 > 解决方案 > Symfony 3.3 如何为两个嵌套的 collectionType 添加约束

问题描述

我有一个带有两层嵌套类型集合的 symfony 3.3 表单。如何跟踪从第二级到第一级的字段验证。如何跟踪最后一级嵌套的验证,即$ amount. 不起作用。这是我的代码PricingMissionTypeEquipmentTypeonly @Assert\valid()

计费设置

namespace AppBundle\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * BillingSetting.
 *
 * @ORM\Table(name="billing_setting")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\BillingSettingRepository")
 */
class BillingSetting
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\OneToOne(targetEntity="Pricing")
     * @ORM\JoinColumn(name="pricing_id", referencedColumnName="id")
     * @Assert\Valid()
     */
    private $pricing;

    /**
     * @ORM\OneToMany(targetEntity="PricingMissionType")
     *@Assert\Valid()
     */
    private $pricingMissionTypes;

    /**
     * Constructor.
     */
    public function __construct()
    {
        $this->pricingMissionTypes = new ArrayCollection();
    }

}

定价任务类型

use AppBundle\Entity\Traits\MigratedAtTrait;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * PricingMissionType.
 *
 * @ORM\Table(name="pricing_mission_type")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\PricingMissionTypeRepository")
 */
class PricingMissionType
{
    /**
     * @var int
     *
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="Pricing")
     */
    private $pricing;

    /**
     * @ORM\ManyToOne(targetEntity="MissionType")
     */
    private $missionType;

    /**
     * @ORM\OneToMany(targetEntity="PricingMissionTypeEquipmentType")
     * @Assert\Valid()
     */
    private $pricingMissionTypeEquipmentTypes;

    /**
     * @var float
     *
     * @ORM\Column(type="float")
     * @Assert\NotBlank()
     */
    private $displacementCost;

    /**
     * @ORM\ManyToOne(targetEntity="BillingSetting")
     */
    private $billingSetting;

    /**
     * Constructor.
     */
    public function __construct()
    {
        $this->pricingMissionTypeEquipmentType = new ArrayCollection();
    }

定价任务类型设备类型

    <?php

namespace AppBundle\Entity;

use AppBundle\Entity\Traits\MigratedAtTrait;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * PricingMissionTypeEquipmentType.
 * @ORM\Entity(repositoryClass="AppBundle\Repository\PricingMissionTypeEquipmentTypeRepository")
 */
class PricingMissionTypeEquipmentType
{
    /**
     * @var int
     *
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

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

    /**
     * @ORM\ManyToOne(targetEntity="PricingMissionType")
     */
    private $pricingMissionType;

    /**
     * @var float
     *
     * @ORM\Column(type="float")
     * @Assert\NotBlank()
     * @Assert\GreaterThan(0)
     */
    private $amount;

    /**
     * @ORM\ManyToOne(targetEntity="EquipementType")
     */
    private $equipementType;

计费设置类型

    <?php

namespace AppBundle\Form;

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

class BillingSettingType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('pricing', PricingType::class)
        ->add('pricingMissionTypes', CollectionType::class,
            [
                'entry_type' => PricingMissionTypeType::class,
            ])
        ;
    }

    /**
     * {@inheritdoc}
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => 'AppBundle\Entity\BillingSetting',
        ]);
    }

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

定价任务类型类型

<?php

namespace AppBundle\Form;

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

class PricingMissionTypeType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('displacementCost', IntegerType::class, [
            'label' => 'billing_settings.displacement_cost',
            'error_bubbling' => true,
             'scale' => 2,
             'required' => true,
            'attr' => [
                'min' => 0,
                'step' => 0.1,
            ],
        ])
            ->add('pricingMissionTypeEquipmentType', CollectionType::class,
                [
                    'entry_type' => PricingMissionTypeEquipmentTypeType::class,
                    'error_bubbling' => true,
                    'entry_options' => [
                        'label' => false,
                    ],
                ]);
    }

    /**
     * {@inheritdoc}
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => 'AppBundle\Entity\PricingMissionType',
        ]);
    }

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

定价任务类型设备类型类型

    <?php

namespace AppBundle\Form;

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

class PricingMissionTypeEquipmentTypeType extends AbstractType
{
    /**
     * {@inheritdoc}
     */
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('amount', IntegerType::class,
            [
                'label' => '(€)',
                'required' => true,
                'scale' => 3,
                'attr' => [
                    'min' => 0,
                    'step' => 0.1,
                ],
            ]);
    }

    /**
     * {@inheritdoc}
     */
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => 'AppBundle\Entity\PricingMissionTypeEquipmentType',
        ]);
    }

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

在我的控制器中

    /**
 * @Route("/add", name="billing_settings_add")
 */
public function buildBillingSettingForm(Request $request)
{
    $form = $this->createForm(BillingSettingType::class, $this->addFormFields());
    $form->handleRequest($request);
    if ($form->isSubmitted() and $form->isValid()) {
        $em = $this->getDoctrine()->getManager();
        /** @var BillingSetting $billingSetting */
        $billinSetting = $form->getData();
        foreach ($billinSetting->getPricingMissionTypes() as $pricingMissionType) {
            /* @var PricingMissionType $pricingMissionType */
            $pricingMissionType->setBillingSetting($billinSetting);
            $pricingMissionType->setPricing($billinSetting->getPricing());
            $em->persist($pricingMissionType);
            foreach ($pricingMissionType->getPricingMissionTypeEquipmentType() as $pricingMissionTypeEquipmentType) {
                /* @var PricingMissionTypeEquipmentType $pricingMissionTypeEquipmentTypes */
                $pricingMissionTypeEquipmentType->setPricingMissionType($pricingMissionType);
                $em->persist($pricingMissionTypeEquipmentType);
            }
            $em->persist($form->getData());
            $em->flush();
            $message = $this->get('translator')->trans('billing_settings.success.add_billing_setting');
            $this->get('session')->getFlashBag()->set('success', $message);

            return $this->redirectToRoute('billing_setting_list');
        }
    }

    return $this->render(
        '@App/page/billingSettings/edit.html.twig',
        [
            'form' => $form->createView(),
            'missionTypeLabels' => $this->getLabels()['missionTypeLabels'],
            'pricingMissionTypeEquipmentTypeLabels' => $this->getLabels()['pricingMissionTypeEquipmentTypeLabels'],
        ]
    );
}

/**
 * @return BillingSetting
 */
public function addFormFields()
{
    $billingSetting = new BillingSetting();
    $missionTypes = $this->getDoctrine()->getRepository(MissionType::class)->findAll();
    $equipementTypes = $this->getDoctrine()->getRepository(EquipementType::class)->findAll();
    foreach ($missionTypes as $missionType) {
        $pricingMissionType = new PricingMissionType();
        $pricingMissionType->setMissionType($missionType);
        foreach ($equipementTypes as $equipementType) {
            $pricingMissionTypeEquipmentType = new PricingMissionTypeEquipmentType();
            $pricingMissionTypeEquipmentType->setEquipementType($equipementType);
            $pricingMissionType->addPricingMissionTypeEquipmentType($pricingMissionTypeEquipmentType);
        }
        $pricingMissionType->setBillingSetting($billingSetting);
        $billingSetting->addPricingMissionType($pricingMissionType);
    }

    return $billingSetting;
}

/**
 * @return array
 */
private function getLabels()
{
    $missionTypes = $this->getDoctrine()->getRepository(MissionType::class)->findAll();
    $EquipementTypes = $this->getDoctrine()->getRepository(EquipementType::class)->findAll();
    $missionTypeLabels = [];
    $pricingMissionTypeEquipmentTypeLabels = [];
    foreach ($missionTypes as $missionType) {
        $missionTypeLabels[] = $missionType->getName();
    }
    foreach ($EquipementTypes as $EquipementType) {
        $pricingMissionTypeEquipmentTypeLabels[] = $EquipementType->getCode();
    }

    return [
        'pricingMissionTypeEquipmentTypeLabels' => $pricingMissionTypeEquipmentTypeLabels,
        'missionTypeLabels' => $missionTypeLabels,
        ];
}

验证:

 /**
 * @Route("/edit/{id}", name="billing_setting_edit")
 */
public function editAction(Request $request, BillingSetting $billinSetting)
{
    $entityManager = $this->getDoctrine()->getManager();
    $oldName = $billinSetting->getPricing()->getName();
    $oldMinPrice = $billinSetting->getPricing()->getMinPrice();
    $oldUnnecessaryDisplacements = $billinSetting->getPricing()->getUnnecessaryDisplacements();
    $oldDiscountByEquipement = $billinSetting->getPricing()->getDiscountByEquipement();
    $oldMaxEquipmentDiscount = $billinSetting->getPricing()->getMaxEquipmentDiscount();

    $editForm = $this->createForm(BillingSettingType::class, $billinSetting);
    $editForm->handleRequest($request);

    if ($editForm->isValid()) {
        $entityManager->flush();
        $message = $this->get('translator')->trans('billing_settings.update.update_billing_setting');
        $this->get('session')->getFlashBag()->set('success', $message);
        // Force doctrine to refresh object
        $entityManager->refresh($billinSetting);
        // For updating Elasticsearch data
        ...

        return $this->redirectToRoute('billing_setting_list');
    }

    return $this->render(
        '@App/page/billingSettings/edit.html.twig',
        [
            'billingSetting' => $billinSetting,
            'form' => $editForm->createView(),
            'missionTypeLabels' => $this->getLabels()['missionTypeLabels'],
            'pricingMissionTypeEquipmentTypeLabels' => $this->getLabels()['pricingMissionTypeEquipmentTypeLabels'],
        ]
    );
}

标签: validationdoctrine-ormconstraintssymfony-3.3

解决方案


推荐阅读