Что у меня есть ...
Получил операционную форму, содержащую коллекцию PaymentEmbeddedForm.
Что я намерен сделать
Я хочу добавить несколько зависимых полей в свой записи внутри коллекции PaymentEmbeddedForm.
Стена, которую я бью.
Если некоторые поля динамически добавляются в одну из моих PaymentEmbeddedForm, тогда когда передается OperationForm (форма root) , он не распознает новые данные, только поле, из которого связаны другие зависимые поля.
Пример
- OperationFrom
- field1
- field2
- field3: (Коллекция PaymentEmbeddedForm)
- Payment1 (PaymentEmbeddedForm)
- Payment1.field1
- Payment1.field2
- Payment1.field3 (динамически добавляется)
- Payment2 (PaymentEmbeddedForm)
- Payment2.field1
- Payment2.field2
В этом случае e, данные Payment1.field3 не будут связаны в моей форме ....
То, что я пробовал
Манипулирование событиями внутри PaymentEmbeddedForm
Если я создаю Независимый PaymentEmbeddedForm, проблем нет, поля зависимостей в моей форме хорошо связаны.
Манипулирование событиями внутри OperationForm
Когда я отлаживаю данные формы с помощью dump ($ data ) , я не вижу данных полей зависимых. Они всегда равны нулю при первой передаче. Но как только форма была отправлена хотя бы один раз, следующая субмиссия в порядке, данные хорошо связаны.
Мой код
//****************************************
//PaymentEmbeddedForm.php
//****************************************
class PaymentEmbeddedForm extends AbstractType
{
/** @var AccountRepository $accountRepo*/
private $accountRepo;
public function buildForm(FormBuilderInterface $builder, array $options)
{
/** @var Organization $org */
$org = $options['organization'];
$builder
->add('method', EntityType::class, [
'placeholder' => '-- Choississez un moyen de paiement --',
'class' => PaymentMethod::class,
'choice_label' => 'displayName',
'choice_value' => 'name'
])
;
$builder
->addEventListener(FormEvents::PRE_SET_DATA, function(FormEvent $event) use ($org) {
return $this->onPreSetData($event, $org);
})
->get('method')->addEventListener(FormEvents::POST_SUBMIT, function(FormEvent $event) use ($org) {
return $this->methodOnPostSubmit($event, $org);
})
;
}
public function configureOptions(OptionsResolver $resolver)
{
parent::configureOptions($resolver);
$resolver->setDefaults([
'data_class' => Payment::class,
'organization' => false
]);
$resolver->setAllowedTypes('organization', 'App\Entity\Core\Organization');
}
public function onPreSetData(FormEvent $event, Organization $org)
{
/** @var Payment $payment */
$payment = $event->getData();
if (!$payment)
return;
$this->setupSpecificMethodFields($event->getForm(), $payment->getMethod(), $org);
return;
}
public function methodOnPostSubmit(FormEvent $event, ?Organization $org)
{
$form = $event->getForm();
$this->setupSpecificMethodFields(
$form->getParent(),
$form->getData(),
$org
);
}
private function setupSpecificMethodFields(FormInterface $form, ?PaymentMethod $method, ?Organization $org)
{
// $form
// ->remove('account')
// ->remove('amount')
// ->remove('iban')
// ->remove('number')
// ->remove('paidAt')
// ->remove('isPaid')
// ;
if (null === $method) {
return;
}
$this->setupAmountField($form);
$this->setupPaidAtField($form);
$this->setupIsPaidField($form);
if (in_array($method->getName(), ['cash', 'credit_card', 'check', 'transfer', 'direct_debit', 'direct_debit_in_installments', 'interbank_payment_order']))
$this->setupAccountField($form, $method, $org);
if (in_array($method->getName(), ['check', 'voucher']))
$this->setupNumberField($form);
if (in_array($method->getName(), ['direct_debit', 'direct_debit_in_installments']))
$this->setupIbanField($form);
}
private function setupPaidAtField(FormInterface $form): void
{
$form->add('paidAt', DateType::class);
return;
}
private function setupIsPaidField(FormInterface $form): void
{
$form->add('isPaid');
return;
}
private function setupAccountField(FormInterface $form, PaymentMethod $method, Organization $org): void
{
$accountChoices = new ArrayCollection();
switch($method->getName()) {
case 'cash':
$accountChoices = $org->getBankAccounts();
break;
case 'credit_card':
case 'check':
case 'transfer':
case 'direct_debit':
case 'direct_debit_in_installments':
case 'interbank_payment_order':
$accountChoices = $org->getBankAccounts();
break;
}
$form->add('account', AccountType::class, [
'choices' => $accountChoices
]);
}
private function setupAmountField(FormInterface $form): void
{
$form->add('amount', MoneyType::class);
return;
}
private function setupIbanField(FormInterface $form): void
{
$form->add('iban');
}
private function setupNumberField(FormInterface $form): void
{
$form->add('number');
}
}
//****************************************
// OperationFormType.php
//****************************************
class OperationFormType extends AbstractType
{
/** @var AccountRepository $accountRepo*/
private $accountRepo;
public function __construct(EntityManagerInterface $em)
{
$this->accountRepo = $em->getRepository(Account::class);
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('amount', MoneyType::class)
->add('description', TextareaType::class)
->add('account', AccountType::class, [
'choices' => $this->accountRepo->getChildren($this->accountRepo->findOneBy([
'code' => $options['type'] == 'income' ? 7 : 6,
'chart' => $options['organization']->getChart()->getId()
]), false, null, 'ASC', false)
])
->add('operateAt', DateType::class)
->add('payments', CollectionType::class, [
'entry_options' => [
'organization' => $options['organization']
],
'entry_type' => PaymentEmbeddedForm::class,
'allow_delete' => true,
'allow_add' => true,
'prototype' => true
])
->add('reset', ResetType::class, [
'label' => 'Réinitialiser'
])
->add('submit', SubmitType::class, [
'label' => 'Enregistrer'
])
;
$builder->addEventListener(FormEvents::PRE_SET_DATA, array($this, 'onPreSetData'));
parent::buildForm($builder, $options);
}
public function configureOptions(OptionsResolver $resolver)
{
parent::configureOptions($resolver);
$resolver->setDefaults([
'data_class' => OperationFormModel::class,
'organization' => false,
'type' => null
]);
$resolver
->setAllowedTypes('organization', 'App\Entity\Core\Organization')
->setAllowedTypes('type', ['string', 'null'])
->setAllowedValues('type', ['expense', 'income', null])
;
}
public function onPreSetData(FormEvent $event)
{
/** @var OperationFormModel $data */
$data = $event->getData();
if ($data->getPayments()->isEmpty()) {
$newPayment = new Payment();
$newPayment->setPaidAt(new DateTime());
$data->addPayment($newPayment);
}
}
}
Спасибо за вашу помощь.
Бдисклаз