У меня есть форма Symfony 3.3 с двумя уровнями коллекции типов вложенности.
как проследить валидацию полей со второго уровня на первый. как отследить валидацию последнего уровня вложенности, т.е. поля $ amount
, равного PricingMissionTypeEquipmentType
. only @Assert\valid()
не работает. Вот мой код
BillingSetting
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();
}
}
PricingMissionType
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();
}
PricingMissionTypeEquipmentType
<?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;
BillingSettingType
<?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';
}
}
PricingMissionTypeType
<?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';
}
}
PricingMissionTypeEquipmentTypeType
<?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'],
]
);
}