Symfony 动态表单:"string"、"NULL" 类型的预期参数在 属性 路径 "civilite" 处给出
Symfony Dynamic Form : Expected argument of type "string", "NULL" given at property path "civilite"
我尝试编写一个动态表单来编辑用户。
里面有邮政编码(codePostal)。如果有人更改邮政编码,它应该更改城市列表(公社)。
我使用 Symfony 推荐的动态形式。这适用于我的 RegisterForm,但不适用于此 editForm。
我想,我想念从用户那里获取信息的东西?
因此,每次我更改邮政编码时,它都无法获取动态表单并在我的控制台中创建此异常(ajax):"string"、"NULL" 类型的预期参数在 属性路径"civilite".
这个异常是在$form->handleRequest($request); 上产生的;我的控制器,但就在我更改邮政编码时,而不是在第一次加载表单时。
这是我的代码:
//Form/EditUserFormType.php
class EditUserFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$user = $options['data'];
$builder
->add('civilite',ChoiceType::class, array(
'choices' => array('M.' => '1', 'Mme' => '2'),
'required' => true,
'expanded' => true,
'multiple' => false,
'data' => $user->getCivilite()
))
->add('nom')
->add('prenom')
->add('societe')
->add('telephone')
->add('adresse')
->add("codePostalAutoComplete", TextType::class, [
"mapped"=>false,
'required' => false,
"label"=>"Code postal",
])
->add('codePostal', EntityType::class, [
'class' => 'App\Entity\CodePostal',
'placeholder' => ''/
])
->add('email');
$formModifier = function (FormInterface $form, CodePostal $codePostal = null) {
$communes = null === $codePostal ? [] : $codePostal->getCommunes();
$form->add('commune', EntityType::class, [
'class' => 'App\Entity\Commune',
'placeholder' => 'Choisir une commune',
'choices' => $communes,
]);
};
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($formModifier) {
// this would be your entity, i.e. SportMeetup
$data = $event->getData();
$formModifier($event->getForm(), $data->getCodePostal());
}
);
$builder->get('codePostal')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) use ($formModifier) {
$codePostal = $event->getForm()->getData();
$formModifier($event->getForm()->getParent(), $codePostal);
}
);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => User::class,
]);
}
}
//Controller/AccountController.php
public function edit(Request $request): Response
{
$em = $this->getDoctrine()->getManager();
$user = $this->getUser();
$form = $this->createForm(EditUserFormType::class,$user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
$this->addFlash('notice', 'Vos modifications on bien été prises en compte !');
return $this->redirectToRoute('app_account_dashboard');
}
return $this->render('account/edit.html.twig', array(
'user' => $user,
'form' => $form->createView(),
));
}
//templates/account/edit.html.twig
{% extends 'base.html.twig' %}
{% block stylesheets %}
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script>
$(document).ready(function () {
var $codePostalAutoComplete = $('#edit_user_form_codePostalAutoComplete');
var $codePostal = $('#edit_user_form_codePostal');
$codePostalAutoComplete.change(function () {
$newValue = $codePostalAutoComplete.val();
$('#edit_user_form_codePostal option').filter(function () {
return($(this).text() == $newValue); // To select Blue
}).prop('selected', true);
// ... retrieve the corresponding form.
var $form = $(this).closest('form');
// Simulate form data, but only include the selected codepostal value.
console.log($form);
var data = {};
data[$codePostal.attr('name')] = $codePostal.val();
// Submit data via AJAX to the form's action path.
$.ajax({
url: $form.attr('action'),
type: $form.attr('method'),
data: data,
success: function (html) { // Replace current position field ...
$('#edit_user_form_commune').replaceWith(
// ... with the returned one from the AJAX response.
$(html).find('#edit_user_form_commune')
);
// Position field now displays the appropriate positions.
}
});
})
});
</script>
{% endblock %}
{% block title %}Modifier mon compte
{% endblock %}
{% block body %}
<h1>Modifier mon compte</h1>
{{ form_start(form) }}
{{ form_row(form.civilite) }}
{{ form_row(form.nom) }}
{{ form_row(form.prenom) }}
{{ form_row(form.societe) }}
{{ form_row(form.adresse) }}
{{ form_row(form.codePostalAutoComplete) }}
<div style="none;">{{ form_row(form.codePostal) }}</div>
{{ form_row(form.commune) }}
{{ form_row(form.telephone) }}
{{ form_row(form.email) }}
</p>
<button class="btn" type="submit">Valider</button>
{{ form_end(form) }}{% endblock %}
有什么想法吗?谢谢
正如@msg 在评论中所说,我需要使用另一个控制器来获取我需要的子表单;
//AccountController.php
public function editCommunesFieldByCodePostal(Request $request, CodePostalRepository $codePostalRepository)
{
$codePostal = $codePostalRepository->find($request->query->get('codePostalId'));
if (isset($codePostal)){
$user = new User();
$user->setCodePostal($codePostal);
$form = $this->createForm(EditUserFormType::class, $user);
//dump($form);
//die();
if (!$form->has('user')) {
return new Response(null, 204);
}
return $this->render('account/_specific_commune.html.twig', [
'form' => $form->createView(),
]);
}
}
//account/edit.html.twig
{% block body %}
<h1>Modifier mon compte</h1>
{{ form_start(form) }}
{{ form_row(form.civilite) }}
{{ form_row(form.nom) }}
{{ form_row(form.prenom) }}
{{ form_row(form.societe) }}
{{ form_row(form.adresse) }}
{{ form_row(form.codePostalAutoComplete) }}
<div style="display:none;">
{{ form_row(form.codePostal, {
attr: {
'data-specific-location-url': path('app_account_edit_communes_by_codepostal'),
'class': 'js-user-form-codePostal'
}
}) }}
</div>
<div class="js-specific-commune-target">
{% if form.commune is defined %}
{{ form_row(form.commune, {
attr: {
'class': 'js-user-form-commune'
}
}) }}
{% endif %}
</div>
{{ form_row(form.telephone) }}
{{ form_row(form.email) }}
</p>
<button class="btn" type="submit">Valider</button>
{{ form_end(form) }}
{% endblock %}
{% block javascripts %}
{{ parent() }}
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script>
$(document).ready(function() {
$('#edit_user_form_codePostalAutoComplete').on('change', function(e) {
$newValue = $('#edit_user_form_codePostalAutoComplete').val();
$('#edit_user_form_codePostal option').filter(function() {
return ($(this).text() == $newValue); //To select Blue
}).prop('selected', true);
var $codePostalSelect = $('.js-user-form-codePostal');
var $specificLocationTarget = $('.js-specific-commune-target');
$.ajax({
url: $codePostalSelect.data('specific-location-url'),
data: {
codePostalId: $codePostalSelect.val()
},
success: function (html) {
if (!html) {
$specificLocationTarget.find('select').remove();
$specificLocationTarget.addClass('d-none');
return;
}
// Replace the current field and show
$specificLocationTarget
.html(html)
.removeClass('d-none')
}
});
});
});
</script>
{% endblock %}
我尝试编写一个动态表单来编辑用户。
里面有邮政编码(codePostal)。如果有人更改邮政编码,它应该更改城市列表(公社)。 我使用 Symfony 推荐的动态形式。这适用于我的 RegisterForm,但不适用于此 editForm。
我想,我想念从用户那里获取信息的东西? 因此,每次我更改邮政编码时,它都无法获取动态表单并在我的控制台中创建此异常(ajax):"string"、"NULL" 类型的预期参数在 属性路径"civilite".
这个异常是在$form->handleRequest($request); 上产生的;我的控制器,但就在我更改邮政编码时,而不是在第一次加载表单时。
这是我的代码:
//Form/EditUserFormType.php
class EditUserFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$user = $options['data'];
$builder
->add('civilite',ChoiceType::class, array(
'choices' => array('M.' => '1', 'Mme' => '2'),
'required' => true,
'expanded' => true,
'multiple' => false,
'data' => $user->getCivilite()
))
->add('nom')
->add('prenom')
->add('societe')
->add('telephone')
->add('adresse')
->add("codePostalAutoComplete", TextType::class, [
"mapped"=>false,
'required' => false,
"label"=>"Code postal",
])
->add('codePostal', EntityType::class, [
'class' => 'App\Entity\CodePostal',
'placeholder' => ''/
])
->add('email');
$formModifier = function (FormInterface $form, CodePostal $codePostal = null) {
$communes = null === $codePostal ? [] : $codePostal->getCommunes();
$form->add('commune', EntityType::class, [
'class' => 'App\Entity\Commune',
'placeholder' => 'Choisir une commune',
'choices' => $communes,
]);
};
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($formModifier) {
// this would be your entity, i.e. SportMeetup
$data = $event->getData();
$formModifier($event->getForm(), $data->getCodePostal());
}
);
$builder->get('codePostal')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) use ($formModifier) {
$codePostal = $event->getForm()->getData();
$formModifier($event->getForm()->getParent(), $codePostal);
}
);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => User::class,
]);
}
}
//Controller/AccountController.php
public function edit(Request $request): Response
{
$em = $this->getDoctrine()->getManager();
$user = $this->getUser();
$form = $this->createForm(EditUserFormType::class,$user);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
$this->addFlash('notice', 'Vos modifications on bien été prises en compte !');
return $this->redirectToRoute('app_account_dashboard');
}
return $this->render('account/edit.html.twig', array(
'user' => $user,
'form' => $form->createView(),
));
}
//templates/account/edit.html.twig
{% extends 'base.html.twig' %}
{% block stylesheets %}
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script>
$(document).ready(function () {
var $codePostalAutoComplete = $('#edit_user_form_codePostalAutoComplete');
var $codePostal = $('#edit_user_form_codePostal');
$codePostalAutoComplete.change(function () {
$newValue = $codePostalAutoComplete.val();
$('#edit_user_form_codePostal option').filter(function () {
return($(this).text() == $newValue); // To select Blue
}).prop('selected', true);
// ... retrieve the corresponding form.
var $form = $(this).closest('form');
// Simulate form data, but only include the selected codepostal value.
console.log($form);
var data = {};
data[$codePostal.attr('name')] = $codePostal.val();
// Submit data via AJAX to the form's action path.
$.ajax({
url: $form.attr('action'),
type: $form.attr('method'),
data: data,
success: function (html) { // Replace current position field ...
$('#edit_user_form_commune').replaceWith(
// ... with the returned one from the AJAX response.
$(html).find('#edit_user_form_commune')
);
// Position field now displays the appropriate positions.
}
});
})
});
</script>
{% endblock %}
{% block title %}Modifier mon compte
{% endblock %}
{% block body %}
<h1>Modifier mon compte</h1>
{{ form_start(form) }}
{{ form_row(form.civilite) }}
{{ form_row(form.nom) }}
{{ form_row(form.prenom) }}
{{ form_row(form.societe) }}
{{ form_row(form.adresse) }}
{{ form_row(form.codePostalAutoComplete) }}
<div style="none;">{{ form_row(form.codePostal) }}</div>
{{ form_row(form.commune) }}
{{ form_row(form.telephone) }}
{{ form_row(form.email) }}
</p>
<button class="btn" type="submit">Valider</button>
{{ form_end(form) }}{% endblock %}
有什么想法吗?谢谢
正如@msg 在评论中所说,我需要使用另一个控制器来获取我需要的子表单;
//AccountController.php
public function editCommunesFieldByCodePostal(Request $request, CodePostalRepository $codePostalRepository)
{
$codePostal = $codePostalRepository->find($request->query->get('codePostalId'));
if (isset($codePostal)){
$user = new User();
$user->setCodePostal($codePostal);
$form = $this->createForm(EditUserFormType::class, $user);
//dump($form);
//die();
if (!$form->has('user')) {
return new Response(null, 204);
}
return $this->render('account/_specific_commune.html.twig', [
'form' => $form->createView(),
]);
}
}
//account/edit.html.twig
{% block body %}
<h1>Modifier mon compte</h1>
{{ form_start(form) }}
{{ form_row(form.civilite) }}
{{ form_row(form.nom) }}
{{ form_row(form.prenom) }}
{{ form_row(form.societe) }}
{{ form_row(form.adresse) }}
{{ form_row(form.codePostalAutoComplete) }}
<div style="display:none;">
{{ form_row(form.codePostal, {
attr: {
'data-specific-location-url': path('app_account_edit_communes_by_codepostal'),
'class': 'js-user-form-codePostal'
}
}) }}
</div>
<div class="js-specific-commune-target">
{% if form.commune is defined %}
{{ form_row(form.commune, {
attr: {
'class': 'js-user-form-commune'
}
}) }}
{% endif %}
</div>
{{ form_row(form.telephone) }}
{{ form_row(form.email) }}
</p>
<button class="btn" type="submit">Valider</button>
{{ form_end(form) }}
{% endblock %}
{% block javascripts %}
{{ parent() }}
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script>
$(document).ready(function() {
$('#edit_user_form_codePostalAutoComplete').on('change', function(e) {
$newValue = $('#edit_user_form_codePostalAutoComplete').val();
$('#edit_user_form_codePostal option').filter(function() {
return ($(this).text() == $newValue); //To select Blue
}).prop('selected', true);
var $codePostalSelect = $('.js-user-form-codePostal');
var $specificLocationTarget = $('.js-specific-commune-target');
$.ajax({
url: $codePostalSelect.data('specific-location-url'),
data: {
codePostalId: $codePostalSelect.val()
},
success: function (html) {
if (!html) {
$specificLocationTarget.find('select').remove();
$specificLocationTarget.addClass('d-none');
return;
}
// Replace the current field and show
$specificLocationTarget
.html(html)
.removeClass('d-none')
}
});
});
});
</script>
{% endblock %}