I'm having a hard time figuring out how to handle a JSON request with Symfony forms (using v3.0.1).
我很难弄清楚如何使用Symfony表单处理JSON请求(使用v3.0.1)。
Here is my controller:
这是我的控制器:
/**
* @Route("/tablet")
* @Method("POST")
*/
public function tabletAction(Request $request)
{
$tablet = new Tablet();
$form = $this->createForm(ApiTabletType::class, $tablet);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($tablet);
$em->flush();
}
return new Response('');
}
And my form:
我的表格:
class ApiTabletType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('macAddress')
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => 'AppBundle\Entity\Tablet'
]);
}
}
When I send a POST request with the Content-Type header properly set to application/json, my form is invalid... all fields are null.
当我发送POST请求并将Content-Type标头正确设置为application / json时,我的表单无效...所有字段都为空。
Here is the exception message I get if I comment the if ($form->isValid())
line :
如果我评论if($ form-> isValid())行,这是我得到的异常消息:
An exception occurred while executing 'INSERT INTO tablet (mac_address, site_id) VALUES (?, ?)' with params [null, null]:
使用params [null,null]执行'INSERT INTO tablet(mac_address,site_id)VALUES(?,?)'时发生异常:
I've tried sending different JSON with the same result each time:
我每次尝试发送不同的JSON,结果相同:
{"id":"9","macAddress":"5E:FF:56:A2:AF:15"}
{"api_tablet":{"id":"9","macAddress":"5E:FF:56:A2:AF:15"}}
"api_tablet" being what getBlockPrefix
returns (Symfony 3 equivalent to form types getName
method in Symfony 2).
“api_tablet”是getBlockPrefix返回的内容(Symfony 3相当于Symfony 2中的表单类型getName方法)。
Can anyone tell me what I've been doing wrong?
谁能告诉我我做错了什么?
UPDATE:
I tried overriding getBlockPrefix in my form type. The form fields have no prefix anymore, but still no luck :/
我尝试在表单类型中覆盖getBlockPrefix。表单字段不再有前缀,但仍然没有运气:/
public function getBlockPrefix()
{
return '';
}
3 个解决方案
#1
8
$data = json_decode($request->getContent(), true);
$form->submit($data);
if ($form->isValid()) {
// and so on…
}
#2
0
I would recommend you use the FOSRestBundle.
我建议你使用FOSRestBundle。
Here's an example config I use at the moment:
这是我目前使用的示例配置:
fos_rest:
view:
view_response_listener: force
force_redirects:
html: true
formats:
jsonp: true
json: true
xml: false
rss: false
templating_formats:
html: true
jsonp_handler: ~
body_listener: true
param_fetcher_listener: force
allowed_methods_listener: true
access_denied_listener:
json: true
format_listener:
enabled: true
rules:
- { path: ^/, priorities: [ 'html', 'json' ], fallback_format: html, prefer_extension: true }
routing_loader:
default_format: ~
include_format: true
exception:
enabled: true
codes:
'Symfony\Component\Routing\Exception\ResourceNotFoundException': 404
'Doctrine\ORM\OptimisticLockException': HTTP_CONFLICT
messages:
'Symfony\Component\Routing\Exception\ResourceNotFoundException': true
Make sure you have getBlockPrefix defined with something (I haven't tried empty strings so it might work):
确保你已经定义了getBlockPrefix(我没有尝试过空字符串,所以它可能有效):
public function getBlockPrefix()
{
return 'api_tablet'
}
Disable CSRF protection for good measure:
禁用CSRF保护措施:
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'csrf_protection' => false,
'data_class' => 'AppBundle\Entity\Tablet'
]);
}
You can then POST the following data to the form:
然后,您可以将以下数据发布到表单:
{"api_tablet":{"macAddress":"5E:FF:56:A2:AF:15"}}
Notes / caveats:
备注/警告:
-
You need to make sure your Form is configured with all the fields of the Entity. You can configure what you need in a validator.
您需要确保您的表单配置了实体的所有字段。您可以在验证器中配置所需的内容。
-
You have to post in camelCase. FOSRestBundle supports Array Normalization, which I haven't tried, but apparently that will let you post in underscores.
你必须在camelCase中发帖。 FOSRestBundle支持阵列规范化,我还没有尝试过,但显然会让你发布下划线。
#3
0
I guess you can drop forms and populate->validate entities
我想你可以删除表单并填充 - >验证实体
$jsonData = $request->getContent();
$serializer->deserialize($jsonData, Entity::class, 'json', [
'object_to_populate' => $entity,
]);
$violations = $validator->validate($entity);
if (!$violations->count()) {
return Response('Valid entity');
}
return new Response('Invalid entity');
https://symfony.com/doc/current/components/serializer.html#deserializing-in-an-existing-object
#1
8
$data = json_decode($request->getContent(), true);
$form->submit($data);
if ($form->isValid()) {
// and so on…
}
#2
0
I would recommend you use the FOSRestBundle.
我建议你使用FOSRestBundle。
Here's an example config I use at the moment:
这是我目前使用的示例配置:
fos_rest:
view:
view_response_listener: force
force_redirects:
html: true
formats:
jsonp: true
json: true
xml: false
rss: false
templating_formats:
html: true
jsonp_handler: ~
body_listener: true
param_fetcher_listener: force
allowed_methods_listener: true
access_denied_listener:
json: true
format_listener:
enabled: true
rules:
- { path: ^/, priorities: [ 'html', 'json' ], fallback_format: html, prefer_extension: true }
routing_loader:
default_format: ~
include_format: true
exception:
enabled: true
codes:
'Symfony\Component\Routing\Exception\ResourceNotFoundException': 404
'Doctrine\ORM\OptimisticLockException': HTTP_CONFLICT
messages:
'Symfony\Component\Routing\Exception\ResourceNotFoundException': true
Make sure you have getBlockPrefix defined with something (I haven't tried empty strings so it might work):
确保你已经定义了getBlockPrefix(我没有尝试过空字符串,所以它可能有效):
public function getBlockPrefix()
{
return 'api_tablet'
}
Disable CSRF protection for good measure:
禁用CSRF保护措施:
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'csrf_protection' => false,
'data_class' => 'AppBundle\Entity\Tablet'
]);
}
You can then POST the following data to the form:
然后,您可以将以下数据发布到表单:
{"api_tablet":{"macAddress":"5E:FF:56:A2:AF:15"}}
Notes / caveats:
备注/警告:
-
You need to make sure your Form is configured with all the fields of the Entity. You can configure what you need in a validator.
您需要确保您的表单配置了实体的所有字段。您可以在验证器中配置所需的内容。
-
You have to post in camelCase. FOSRestBundle supports Array Normalization, which I haven't tried, but apparently that will let you post in underscores.
你必须在camelCase中发帖。 FOSRestBundle支持阵列规范化,我还没有尝试过,但显然会让你发布下划线。
#3
0
I guess you can drop forms and populate->validate entities
我想你可以删除表单并填充 - >验证实体
$jsonData = $request->getContent();
$serializer->deserialize($jsonData, Entity::class, 'json', [
'object_to_populate' => $entity,
]);
$violations = $validator->validate($entity);
if (!$violations->count()) {
return Response('Valid entity');
}
return new Response('Invalid entity');
https://symfony.com/doc/current/components/serializer.html#deserializing-in-an-existing-object