Symfony2:从 Ajax 表单提交中保存记录
Symfony2: Save Record From Ajax Form Submission
我完全迷路了。在一切开始变得零意义之前,人们只能阅读这么多文档。
我希望能够保存从我的 Symfony 应用程序外部传递的表单数据。我已经安装了 FOSRestBundle、JMSSerializerBundle、NelmioCorsBundle 等
首先,我有一个如下所示的 FormType:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title')
->add('requestDate')
->add('deliverDate')
->add('returnDate')
->add('created')
->add('updated')
->add('contentChangedBy')
;
}
然后我有一个包含 POST 方法的 REST 控制器,该方法应该存储新记录:
class AvRequestController extends Controller
{
...
public function postAvrequestAction(Request $request){
$entity = new AvRequest();
$form = $this->createForm(new AvRequestType(), $entity);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return new \Symfony\Component\HttpFoundation\JsonResponse($entity, Codes::HTTP_CREATED);
}
return new \Symfony\Component\HttpFoundation\JsonResponse($request, 400);
}
}
这是使用模拟 ajax 表单数据的测试:
$('#postform').submit(function(event){
event.preventDefault();
console.log("submitted");
ajaxObject = {
url: $("#postform").attr("action"),
type: 'POST', // Can be GET, PUT, POST or DELETE only
dataType: 'json',
xhrFields: {
withCredentials: true
},
crossDomain: true,
contentType: "application/json; charset=UTF-8",
data: JSON.stringify({"id":2, "title":"billabong", "requestDate":"2000-01-01 11:11:11", "deliverDate": "2000-01-01 11:11:11", "returnDate": "2000-01-01 11:11:11", "created": "2000-01-01 11:11:11", "updated": "2000-01-01 11:11:11", "content_changed_by":"cpuzzuol"})
};
// ... Add callbacks depending on requests
$.ajax(ajaxObject)
.done(function(data,status,xhr) {
console.log( two );
})
.fail(function(data,status,xhr) {
console.log( status );
})
.always(function(data,status,xhr) {
console.log( data );
});
console.log("END");
});
当我提交表单时,400 Bad Request 在我的 POST 方法中被触发。更糟糕的是,我的 $request 包总是空的:
{"attributes":{},"request":{},"query":{},"server":{},"files":{},"cookies":{},"headers":{}}
如果我这样做
$request->getContent()
我得到了我的字符串化数据:
"{\u0022id\u0022:2,\u0022title\u0022:\u0022billabong\u0022,\u0022requestDate\u0022:\u00222000-01-01 11:11:11\u0022,\u0022deliverDate\u0022:\u00222000-01-01 11:11:11\u0022,\u0022returnDate\u0022:\u00222000-01-01 11:11:11\u0022,\u0022created\u0022:\u00222000-01-01 11:11:11\u0022,\u0022updated\u0022:\u00222000-01-01 11:11:11\u0022,\u0022content_changed_by\u0022:\u0022cpuzzuol\u0022}"
我读到这可能与 FOSRestBundle 的 "body listener" 有关,但我已经启用了它:
body_listener: true
更新
body_listener好像一点作用都没有。正如下面的答案所述,您必须创建一个名称为空的表单,因为您从系统外部提交的表单不会具有它在 Symfony 内部制作时通常具有的名称。另外,如果您一开始没有设置 CSRF,请务必关闭它。
表格 isValid
也检查 CSRF token validation
。您可以在 AvRequestType
中关闭 csrf token validation
。
//...
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\AvRequest',
'csrf_protection' => false
));
}
//...
此外,我建议您的表格有 name
。 isValid 还会检查您的 form name
。
// form without name
public function getName()
{
return '';
}
或
$form = $this->get('form.factory')->createNamed('', new AvRequestType(), $avRequest);
如果你想创建实体,你应该发送 data
不带 id(来自 JS)。
我已经使用 "JMS serializer" 将我的实体序列化为 json。
//控制器
public function postAvRequestAction(Request $request)
{
$avRequest = new AvRequest();
$form = $this->createForm(new AvRequestType(), $avRequest);
$form->handleRequest($request);
$form = $this->get('form.factory')->createNamed('', new AvRequestType(), $avRequest);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($avRequest);
$em->flush();
$serializer = $this->get('serializer');
$serialized = $serializer->serialize($avRequest, 'json');
return new Response($serialized);
}
return new JsonResponse(array(
'errors' => $this->getFormErrors($form)
));
}
protected function getFormErrors(Form $form)
{
$errors = array();
foreach ($form->getErrors() as $error) {
$errors['global'][] = $error->getMessage();
}
foreach ($form as $field) {
if (!$field->isValid()) {
foreach ($field->getErrors() as $error) {
$errors['fields'][$field->getName()] = $error->getMessage();
}
}
}
return $errors;
}
我完全迷路了。在一切开始变得零意义之前,人们只能阅读这么多文档。
我希望能够保存从我的 Symfony 应用程序外部传递的表单数据。我已经安装了 FOSRestBundle、JMSSerializerBundle、NelmioCorsBundle 等
首先,我有一个如下所示的 FormType:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title')
->add('requestDate')
->add('deliverDate')
->add('returnDate')
->add('created')
->add('updated')
->add('contentChangedBy')
;
}
然后我有一个包含 POST 方法的 REST 控制器,该方法应该存储新记录:
class AvRequestController extends Controller
{
...
public function postAvrequestAction(Request $request){
$entity = new AvRequest();
$form = $this->createForm(new AvRequestType(), $entity);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return new \Symfony\Component\HttpFoundation\JsonResponse($entity, Codes::HTTP_CREATED);
}
return new \Symfony\Component\HttpFoundation\JsonResponse($request, 400);
}
}
这是使用模拟 ajax 表单数据的测试:
$('#postform').submit(function(event){
event.preventDefault();
console.log("submitted");
ajaxObject = {
url: $("#postform").attr("action"),
type: 'POST', // Can be GET, PUT, POST or DELETE only
dataType: 'json',
xhrFields: {
withCredentials: true
},
crossDomain: true,
contentType: "application/json; charset=UTF-8",
data: JSON.stringify({"id":2, "title":"billabong", "requestDate":"2000-01-01 11:11:11", "deliverDate": "2000-01-01 11:11:11", "returnDate": "2000-01-01 11:11:11", "created": "2000-01-01 11:11:11", "updated": "2000-01-01 11:11:11", "content_changed_by":"cpuzzuol"})
};
// ... Add callbacks depending on requests
$.ajax(ajaxObject)
.done(function(data,status,xhr) {
console.log( two );
})
.fail(function(data,status,xhr) {
console.log( status );
})
.always(function(data,status,xhr) {
console.log( data );
});
console.log("END");
});
当我提交表单时,400 Bad Request 在我的 POST 方法中被触发。更糟糕的是,我的 $request 包总是空的:
{"attributes":{},"request":{},"query":{},"server":{},"files":{},"cookies":{},"headers":{}}
如果我这样做
$request->getContent()
我得到了我的字符串化数据:
"{\u0022id\u0022:2,\u0022title\u0022:\u0022billabong\u0022,\u0022requestDate\u0022:\u00222000-01-01 11:11:11\u0022,\u0022deliverDate\u0022:\u00222000-01-01 11:11:11\u0022,\u0022returnDate\u0022:\u00222000-01-01 11:11:11\u0022,\u0022created\u0022:\u00222000-01-01 11:11:11\u0022,\u0022updated\u0022:\u00222000-01-01 11:11:11\u0022,\u0022content_changed_by\u0022:\u0022cpuzzuol\u0022}"
我读到这可能与 FOSRestBundle 的 "body listener" 有关,但我已经启用了它:
body_listener: true
更新
body_listener好像一点作用都没有。正如下面的答案所述,您必须创建一个名称为空的表单,因为您从系统外部提交的表单不会具有它在 Symfony 内部制作时通常具有的名称。另外,如果您一开始没有设置 CSRF,请务必关闭它。
表格 isValid
也检查 CSRF token validation
。您可以在 AvRequestType
中关闭 csrf token validation
。
//...
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\AvRequest',
'csrf_protection' => false
));
}
//...
此外,我建议您的表格有 name
。 isValid 还会检查您的 form name
。
// form without name
public function getName()
{
return '';
}
或
$form = $this->get('form.factory')->createNamed('', new AvRequestType(), $avRequest);
如果你想创建实体,你应该发送 data
不带 id(来自 JS)。
我已经使用 "JMS serializer" 将我的实体序列化为 json。 //控制器
public function postAvRequestAction(Request $request)
{
$avRequest = new AvRequest();
$form = $this->createForm(new AvRequestType(), $avRequest);
$form->handleRequest($request);
$form = $this->get('form.factory')->createNamed('', new AvRequestType(), $avRequest);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($avRequest);
$em->flush();
$serializer = $this->get('serializer');
$serialized = $serializer->serialize($avRequest, 'json');
return new Response($serialized);
}
return new JsonResponse(array(
'errors' => $this->getFormErrors($form)
));
}
protected function getFormErrors(Form $form)
{
$errors = array();
foreach ($form->getErrors() as $error) {
$errors['global'][] = $error->getMessage();
}
foreach ($form as $field) {
if (!$field->isValid()) {
foreach ($field->getErrors() as $error) {
$errors['fields'][$field->getName()] = $error->getMessage();
}
}
}
return $errors;
}