具有文件类型字段editAction的Symfony 3表单集合实体
Symfony 3 form collection entity with filetype field editAction
当存在具有 fileType 字段的实体集合时,如何正确处理表单更新。我根据
Symfony upload docs。实体创建工作完美,但编辑操作失败,因为没有选择文件并且 symfony 尝试用文件字段上的空值更新集合实体。
AppBundle\Entity\Product:
type: entity
# ...
oneToMany:
images:
targetEntity: Image
mappedBy: product
表格:
// AppBundle\Form\ProductType
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
// ...
->add(
'images',
CollectionType::class,
[
'entry_type' => ImageType::class,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'entry_options' => ['label' => false],
'label_attr' => [
'data-feature' => 'editable',
],
]
);
}
// AppBundle\Form\ImageType
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('file', FileType::class, ['required' => false])
// another fields...
}
操作:
// AppBundle\Controller\Backend\ProductController
// ...
public function editAction(Request $request, EntityManagerInterface $em, Product $product)
{
$editForm = $this->createForm('AppBundle\Form\ProductType', $product);
$editForm->handleRequest($request);
$originalImages = new ArrayCollection();
foreach ($product->getImages() as $image) {
$originalImages->add($image);
}
if ($editForm->isSubmitted()) {
if ($editForm->isValid()) {
foreach ($originalImages as $image) {
if (false === $product->getImages()->contains($image)) {
$em->remove($image);
}
}
$em->flush();
$this->addFlash('success', 'Success');
} else {
$this->addFlash('warning', 'Error saving');
}
return $this->redirectToRoute('backend_product_edit', ['id' => $product->getId()]);
}
}
// ...
我认为我需要在某处取消设置空文件字段,但我不知道在哪里...(
P.S。我知道我可以使用像 VichUploaderBundle
这样的包,但我想了解它是如何工作的,以及我做错了什么!
P.P.S。对不起我的英语
一周前我遇到了同样的问题。在阅读了很多关于这个问题的帖子后,出于安全原因,您似乎无法预先填写表格的 "file field"。
我实施的简单解决方案:
在您的 "editAction method" 中:在呈现表单之前 "edit" 在用户会话中分配当前文件字段的值。
然后当用户提交 "update" 表单时,您可以使用预更新事件(例如原则生命周期)在会话中查找这些文件名,并在持久化之前将它们重新分配给您的实体.
基本上你应该做这样的事情(我给你我的实体的代码你需要根据你的逻辑调整它)
在我的案例中,学说关系是 1 个新闻有 1 个图像文件。
在您的 editAction 中:
protected function editNewsAction()
{
//some code
if (!$response instanceof RedirectResponse)
{
$entityId = $this->request->query->get('id'); //the id of my entity was in the query string in my logic
$repo = $this->getDoctrine()->getManager()->getRepository('AppBundle:News');
$oldEntity = $repo->findOneBy(['id' => $entityId]);
$oldEntityImage = $oldEntity->getImage(); // I had oneToOne Relation so adapt it for your own logic
$session = $this->get('session');
$session->set('newsImage', $oldEntityImage);
}
// some code
}
然后在预更新事件中:
protected function preUpdateNewsEntity($entity)
{
//some code
if (!$entity->getImageFile())
{
$session = $this->get('session');
$entity->setImage($session->get('newsImage'));
//don't forget to remove the value in session
$session->remove('newsImage');
}
//some code
}
希望对您有所帮助。
修改ImageType形式彻底解决了我的问题
// AppBundle\Form\ImageType
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('file', FileType::class, ['required' => false, 'data_class' => null]])
// another fields...
;
// adding this forces to use old file if there is no file uploaded
$builder->get('file')->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
if (null === $event->getData()) {
$event->setData($event->getForm()->getData());
}
});
}
当存在具有 fileType 字段的实体集合时,如何正确处理表单更新。我根据 Symfony upload docs。实体创建工作完美,但编辑操作失败,因为没有选择文件并且 symfony 尝试用文件字段上的空值更新集合实体。
AppBundle\Entity\Product:
type: entity
# ...
oneToMany:
images:
targetEntity: Image
mappedBy: product
表格:
// AppBundle\Form\ProductType
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
// ...
->add(
'images',
CollectionType::class,
[
'entry_type' => ImageType::class,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'entry_options' => ['label' => false],
'label_attr' => [
'data-feature' => 'editable',
],
]
);
}
// AppBundle\Form\ImageType
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('file', FileType::class, ['required' => false])
// another fields...
}
操作:
// AppBundle\Controller\Backend\ProductController
// ...
public function editAction(Request $request, EntityManagerInterface $em, Product $product)
{
$editForm = $this->createForm('AppBundle\Form\ProductType', $product);
$editForm->handleRequest($request);
$originalImages = new ArrayCollection();
foreach ($product->getImages() as $image) {
$originalImages->add($image);
}
if ($editForm->isSubmitted()) {
if ($editForm->isValid()) {
foreach ($originalImages as $image) {
if (false === $product->getImages()->contains($image)) {
$em->remove($image);
}
}
$em->flush();
$this->addFlash('success', 'Success');
} else {
$this->addFlash('warning', 'Error saving');
}
return $this->redirectToRoute('backend_product_edit', ['id' => $product->getId()]);
}
}
// ...
我认为我需要在某处取消设置空文件字段,但我不知道在哪里...(
P.S。我知道我可以使用像 VichUploaderBundle
这样的包,但我想了解它是如何工作的,以及我做错了什么!
P.P.S。对不起我的英语
一周前我遇到了同样的问题。在阅读了很多关于这个问题的帖子后,出于安全原因,您似乎无法预先填写表格的 "file field"。
我实施的简单解决方案:
在您的 "editAction method" 中:在呈现表单之前 "edit" 在用户会话中分配当前文件字段的值。
然后当用户提交 "update" 表单时,您可以使用预更新事件(例如原则生命周期)在会话中查找这些文件名,并在持久化之前将它们重新分配给您的实体.
基本上你应该做这样的事情(我给你我的实体的代码你需要根据你的逻辑调整它)
在我的案例中,学说关系是 1 个新闻有 1 个图像文件。
在您的 editAction 中:
protected function editNewsAction()
{
//some code
if (!$response instanceof RedirectResponse)
{
$entityId = $this->request->query->get('id'); //the id of my entity was in the query string in my logic
$repo = $this->getDoctrine()->getManager()->getRepository('AppBundle:News');
$oldEntity = $repo->findOneBy(['id' => $entityId]);
$oldEntityImage = $oldEntity->getImage(); // I had oneToOne Relation so adapt it for your own logic
$session = $this->get('session');
$session->set('newsImage', $oldEntityImage);
}
// some code
}
然后在预更新事件中:
protected function preUpdateNewsEntity($entity)
{
//some code
if (!$entity->getImageFile())
{
$session = $this->get('session');
$entity->setImage($session->get('newsImage'));
//don't forget to remove the value in session
$session->remove('newsImage');
}
//some code
}
希望对您有所帮助。
修改ImageType形式彻底解决了我的问题
// AppBundle\Form\ImageType
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('file', FileType::class, ['required' => false, 'data_class' => null]])
// another fields...
;
// adding this forces to use old file if there is no file uploaded
$builder->get('file')->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $event) {
if (null === $event->getData()) {
$event->setData($event->getForm()->getData());
}
});
}