对于我目前正在构建的API,我希望能够使用具有以下内容的JSON正文发送请求
{"title": "foo"}
为被调用的实体创建新的数据库记录Project
.
我做了一个子类控制器FOSRestController
.为了创建一个项目,我做了一个动作
/** * @Route("/") * * @ApiDoc( * section="Project", * resource=true, * input={"class"="AppBundle\Form\API\ProjectType"}, * description="Creates a new project", * statusCodes={ * 201="Returned when successful", * } * ) * * @Method("POST") * @Rest\View(statusCode=201) */ public function createProjectAction(Request $request) { $project = new Project(); $form = $this->createForm(ProjectType::class, $project); $form->submit(($request->request->get($form->getName()))); if ($form->isSubmitted() && $form->isValid()) { return $project; } return View::create($form, 400); }
在ProjectType
这个样子的
class ProjectType extends AbstractType { public function buildForm(FormBuilderInterface $builder, array $options) { $builder->add('title'); } public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults(array( 'data_class' => 'AppBundle\Entity\Project' )); } }
但是,当我尝试将所述JSON发布到API时,它会响应该title
属性不能为空,这很好,因为这是为其设置的验证规则.但是,它是设置的.我突然意识到我必须发送以实际对象名称为前缀的JSON才能使其工作:
{"project":{"title": "bla"}}
公平地感觉有点奇怪,它应该足以发布属性.
所以,基于这些信息我只有两个问题:
为什么我需要"提交"这个表格($request->request->get($form->getName()))
,应该$request
不够?
我需要更改FormType以按原样验证实体,而不是为其添加实体名称前缀?
编辑1:data_class
在默认选项中添加或删除不会改变行为.
这是因为Symfony Controller"createForm"辅助方法的工作原理.其背后的推理是多个表单可以具有相同的目标URL.通过使用表单名称作为前缀,Symfony可以知道提交了哪个表单.
通过查看"createForm"方法实现可以看出:
public function createForm($type, $data = null, array $options = array()) { return $this->container->get('form.factory')->create($type, $data, $options); }
如果您不想要这种行为,那么更改它真的很容易:
public function createProjectAction(Request $request) { $project = new Project(); $form = $this->get('form.factory')->createNamed(null, new ProjectType(), $project); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { return $project; } return View::create($form, 400); }
所以你基本上创建了一个"无名"形式.由于您正在构建API,因此createNamelessForm($type, $data, $options)
在基本控制器中将其拉入辅助方法可能是个好主意,这样您就不必一直明确地从容器中获取Form Factory并使其更容易实现.
包装密钥不是由"data_class"选项生成的,而是由表单类型上的"getName()"方法生成的.