如何使用带有 craue/CraueFormFlowBundle 步进器的 Symfony4 FormEvent onChange 字段来更新或验证表单?
How to use Symfony4 FormEvent onChange field with craue/CraueFormFlowBundle stepper to update or validate form?
- 上下文:
我在 Symfony4 应用程序中使用 craue/CraueFormFlowBundle 包从基本的 SYmfony4 表单生成步进器,它工作正常,直到我尝试引入表单事件以根据表单更改修改我的表单:
- 代码:
控制器:
**
* @Route("/user/add", name="add_user")
* @param Request $request
*/
public function add(Request $request){
$employe = new Employe();
$flow = $this->addUserFlow;
$flow->bind($employe);
// form of the current step
$form = $flow->createForm();
if ($flow->isValid($form)) {
$flow->saveCurrentStepData($form);
if ($flow->nextStep()) {
// form for the next step
$form = $flow->createForm();
} else {
//Persist user
$this->manager->persist($employe);
$this->manager->flush();
//Reset flow to create new user
$flow->reset();
//Redirect to new user detail page
return $this->redirect($this->generateUrl('user_edit', array('id' => $employe->getId())));
}
}
return $this->render('app/users/users/add.html.twig', [
'form' => $form->createView(),
'flow' => $flow,
'employe' => $employe
]);
}
AddUserFlow.php
class AddUserFlow extends FormFlow
{
protected $allowDynamicStepNavigation = true;
protected function loadStepsConfig()
{
return [
[
'label' => 'Informations générales',
'form_type' => UserGeneralType::class,
],
[
'label' => 'Contact',
'form_type' => EmployeContactType::class,
],
[
'label' => 'Contrat',
'form_type' => EmployeContractType::class,
],
[
'label' => "Accès a l'application",
'form_type' => EmployeAccessType::class,
]
];
}
}
这是我的第 3 步表单,其中包含 FormEvent:
/**
* Class ContractType
* @package App\Form\User\Stepper
*/
class ContractType extends AbstractType
{
/**
* @var EntityManagerInterface
*/
private $manager;
/**
* ContractType constructor.
*/
public function __construct(EntityManagerInterface $manager)
{
$this->manager = $manager;
}
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('type', EntityType::class, [
"class" => TypeContract::class,
'label' => 'Type de contrat',
"required" => true
])
->add('startDate', DateType::class, [
'label' => 'Date de début',
'widget' => 'single_text',
"required" => false,
])
->add('endDate', DateType::class, [
'label' => 'Date de fin',
'widget' => 'single_text',
"required" => false,
])
->add('isInsertion', CheckboxType::class, [
'label' => 'Insertion professionnelle',
"required" => false,
])
->add('hourlyRate', MoneyType::class, [
'label' => 'Taux horaire',
"required" => false,
])
;
$formContractTypeModifier = function (FormInterface $form, $contractType = null) {
if($contractType != null && !$contractType instanceof TypeContract){
$contractType = $this->manager->getRepository(TypeContract::class)->find($contractType);
}
if($contractType != null && $contractType instanceof TypeContract && $contractType->getSlug() === ContractTypeEnum::INTERIM){
$form->add('company', EntityType::class, [
"class" => Company::class,
"label" => "Entreprise",
"required" => true,
]);
}
};
// Events listener to modify the form regarding PRE_SET_DATA datas
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($formContractTypeModifier){
/** @var array $data */
$data = $event->getData();
/** TypeContract $contractType */
$contractType = isset($data['type']) ? $data['type'] : null;
//Add elements to form
$formContractTypeModifier($event->getForm(), $contractType);
});
// Events listener to modify the form regarding PRE_SUBMIT
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) use ($formContractTypeModifier){
/** @var array $data */
$data = $event->getData();
/** TypeContract $contractType */
$contractType = isset($data['type']) ? $data['type'] : null;
//Add elements to form
$formContractTypeModifier($event->getForm(), $contractType);
});
}
/**
* @param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => null,
]);
}
}
这是我的 add_user.html.twig
观点:
{% if flow.getCurrentStepNumber() == 3 %}
{% include 'app/users/users/stepper/_step_3.html.twig' %}
{% else %}
{{ form_errors(form) }}
{{ form_rest(form) }}
{% endif %}
step_3.html.twig 视图是这样的:
{{ form_row(form.contracts.type) }}
{% if form.contracts.company is defined %}
{{ form_row(form.contracts.company) }}
{% endif %}
{{ form_row(form.contracts.startDate) }}
{{ form_row(form.contracts.endDate) }}
{{ form_row(form.contracts.hourlyRate) }}
{{ form_row(form.contracts.isInsertion) }}
<script>
$( document ).ready(function() {
$('#employe_contract_contracts_type').on('change', function() {
$.ajax({
url : $form.attr('action'),
type: $form.attr('method'),
data : data,
success: function(html) {
console.log(html);
console.log($(html));
$('#add_employe_step_3_container').replaceWith($(html).find('#add_employe_step_3_container'));
}
});
});
});
</script>
- 问题:
我的问题是我不确定 CraueFlow 是否按照我在 FormEvent 中使用它的方式工作,我没有找到任何文档。
当我尝试我刚刚在这个问题中提出的方法时,我从 Ajax 调用中得到了一个结果,其中包含我的 Flow 的第一步。结果是 $('#add_employe_step_3_container').replaceWith($(html).find('#add_employe_step_3_container'));
没有在我的容器中加载任何东西,因为它没有找到。
当我进入下一步然后返回到第三步时,新的 company
字段出现在我的第 3 步中,因为全局表单似乎已更新并且 formEvent 已正常工作。
有什么想法或例子吗?
要刷新表单并重新加载错误和控件,我只需要在不调用 $flow->nextStep()
的情况下呈现表单
/**
* @Route("/user/add", name="user_add")
*/
public function add(Request $request, UserPasswordEncoderInterface $encoder, UniquePasswordResetToken $uniqueToken){
$employe = new Employe();
$flow = $this->addUserFlow;
$flow->bind($employe);
// form of the current step
$form = $flow->createForm();
if ($flow->isValid($form)) {
$flow->saveCurrentStepData($form);
if ($request->isXmlHttpRequest()) {
$form = $flow->createForm();
} else {
if ($flow->nextStep()) {
// form for the next step
$form = $flow->createForm();
} else {
//Persist user
$this->manager->persist($employe);
$this->manager->flush();
//Persist change password user token
$this->manager->persist($uniqueToken->getToken($employe));
$this->manager->flush();
//Reset flow to create new user
$flow->reset();
//Redirect to new user detail page
return $this->redirect($this->generateUrl('user_edit_personnal_info', array('id' => $employe->getId())));
}
}
}
return $this->render('app/users/users/add.html.twig', [
'form' => $form->createView(),
'flow' => $flow,
'employe' => $employe
]);
}
- 上下文:
我在 Symfony4 应用程序中使用 craue/CraueFormFlowBundle 包从基本的 SYmfony4 表单生成步进器,它工作正常,直到我尝试引入表单事件以根据表单更改修改我的表单:
- 代码:
控制器:
**
* @Route("/user/add", name="add_user")
* @param Request $request
*/
public function add(Request $request){
$employe = new Employe();
$flow = $this->addUserFlow;
$flow->bind($employe);
// form of the current step
$form = $flow->createForm();
if ($flow->isValid($form)) {
$flow->saveCurrentStepData($form);
if ($flow->nextStep()) {
// form for the next step
$form = $flow->createForm();
} else {
//Persist user
$this->manager->persist($employe);
$this->manager->flush();
//Reset flow to create new user
$flow->reset();
//Redirect to new user detail page
return $this->redirect($this->generateUrl('user_edit', array('id' => $employe->getId())));
}
}
return $this->render('app/users/users/add.html.twig', [
'form' => $form->createView(),
'flow' => $flow,
'employe' => $employe
]);
}
AddUserFlow.php
class AddUserFlow extends FormFlow
{
protected $allowDynamicStepNavigation = true;
protected function loadStepsConfig()
{
return [
[
'label' => 'Informations générales',
'form_type' => UserGeneralType::class,
],
[
'label' => 'Contact',
'form_type' => EmployeContactType::class,
],
[
'label' => 'Contrat',
'form_type' => EmployeContractType::class,
],
[
'label' => "Accès a l'application",
'form_type' => EmployeAccessType::class,
]
];
}
}
这是我的第 3 步表单,其中包含 FormEvent:
/**
* Class ContractType
* @package App\Form\User\Stepper
*/
class ContractType extends AbstractType
{
/**
* @var EntityManagerInterface
*/
private $manager;
/**
* ContractType constructor.
*/
public function __construct(EntityManagerInterface $manager)
{
$this->manager = $manager;
}
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('type', EntityType::class, [
"class" => TypeContract::class,
'label' => 'Type de contrat',
"required" => true
])
->add('startDate', DateType::class, [
'label' => 'Date de début',
'widget' => 'single_text',
"required" => false,
])
->add('endDate', DateType::class, [
'label' => 'Date de fin',
'widget' => 'single_text',
"required" => false,
])
->add('isInsertion', CheckboxType::class, [
'label' => 'Insertion professionnelle',
"required" => false,
])
->add('hourlyRate', MoneyType::class, [
'label' => 'Taux horaire',
"required" => false,
])
;
$formContractTypeModifier = function (FormInterface $form, $contractType = null) {
if($contractType != null && !$contractType instanceof TypeContract){
$contractType = $this->manager->getRepository(TypeContract::class)->find($contractType);
}
if($contractType != null && $contractType instanceof TypeContract && $contractType->getSlug() === ContractTypeEnum::INTERIM){
$form->add('company', EntityType::class, [
"class" => Company::class,
"label" => "Entreprise",
"required" => true,
]);
}
};
// Events listener to modify the form regarding PRE_SET_DATA datas
$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($formContractTypeModifier){
/** @var array $data */
$data = $event->getData();
/** TypeContract $contractType */
$contractType = isset($data['type']) ? $data['type'] : null;
//Add elements to form
$formContractTypeModifier($event->getForm(), $contractType);
});
// Events listener to modify the form regarding PRE_SUBMIT
$builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) use ($formContractTypeModifier){
/** @var array $data */
$data = $event->getData();
/** TypeContract $contractType */
$contractType = isset($data['type']) ? $data['type'] : null;
//Add elements to form
$formContractTypeModifier($event->getForm(), $contractType);
});
}
/**
* @param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => null,
]);
}
}
这是我的 add_user.html.twig
观点:
{% if flow.getCurrentStepNumber() == 3 %}
{% include 'app/users/users/stepper/_step_3.html.twig' %}
{% else %}
{{ form_errors(form) }}
{{ form_rest(form) }}
{% endif %}
step_3.html.twig 视图是这样的:
{{ form_row(form.contracts.type) }}
{% if form.contracts.company is defined %}
{{ form_row(form.contracts.company) }}
{% endif %}
{{ form_row(form.contracts.startDate) }}
{{ form_row(form.contracts.endDate) }}
{{ form_row(form.contracts.hourlyRate) }}
{{ form_row(form.contracts.isInsertion) }}
<script>
$( document ).ready(function() {
$('#employe_contract_contracts_type').on('change', function() {
$.ajax({
url : $form.attr('action'),
type: $form.attr('method'),
data : data,
success: function(html) {
console.log(html);
console.log($(html));
$('#add_employe_step_3_container').replaceWith($(html).find('#add_employe_step_3_container'));
}
});
});
});
</script>
- 问题:
我的问题是我不确定 CraueFlow 是否按照我在 FormEvent 中使用它的方式工作,我没有找到任何文档。
当我尝试我刚刚在这个问题中提出的方法时,我从 Ajax 调用中得到了一个结果,其中包含我的 Flow 的第一步。结果是 $('#add_employe_step_3_container').replaceWith($(html).find('#add_employe_step_3_container'));
没有在我的容器中加载任何东西,因为它没有找到。
当我进入下一步然后返回到第三步时,新的 company
字段出现在我的第 3 步中,因为全局表单似乎已更新并且 formEvent 已正常工作。
有什么想法或例子吗?
要刷新表单并重新加载错误和控件,我只需要在不调用 $flow->nextStep()
/**
* @Route("/user/add", name="user_add")
*/
public function add(Request $request, UserPasswordEncoderInterface $encoder, UniquePasswordResetToken $uniqueToken){
$employe = new Employe();
$flow = $this->addUserFlow;
$flow->bind($employe);
// form of the current step
$form = $flow->createForm();
if ($flow->isValid($form)) {
$flow->saveCurrentStepData($form);
if ($request->isXmlHttpRequest()) {
$form = $flow->createForm();
} else {
if ($flow->nextStep()) {
// form for the next step
$form = $flow->createForm();
} else {
//Persist user
$this->manager->persist($employe);
$this->manager->flush();
//Persist change password user token
$this->manager->persist($uniqueToken->getToken($employe));
$this->manager->flush();
//Reset flow to create new user
$flow->reset();
//Redirect to new user detail page
return $this->redirect($this->generateUrl('user_edit_personnal_info', array('id' => $employe->getId())));
}
}
}
return $this->render('app/users/users/add.html.twig', [
'form' => $form->createView(),
'flow' => $flow,
'employe' => $employe
]);
}