我正在关注这些指南:File upload tutorial和Collection form type guide。一切都很好,但“编辑”动作。在“编辑”操作中正确显示图像集合,但当我尝试提交表单(不添加任何新图像)时,我收到错误。
在null
上调用成员函数guessExtension()
这意味着集合中的图像具有空值,而不是UploadedFile。
我经常搜索并阅读许多关于处理带有学说的图像集的问题,但仍然没有线索。
如下问题:
所以问题是如何处理编辑图像?也需要搬迁。
控制器编辑操作
public function editAction(Request $request, Stamp $stamp)
{
if (!$stamp) {
throw $this->createNotFoundException('No stamp found');
}
$form = $this->createForm(AdminStampForm::class, $stamp);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
/** @var Stamp $stamp */
$stamp = $form->getData();
foreach ($stamp->getImages() as $image) {
$fileName = md5(uniqid()) . '.' . $image->getName()->guessExtension();
/** @var $image StampImage */
$image->getName()->move(
$this->getParameter('stamps_images_directory'),
$fileName
);
$image->setName($fileName)->setFileName($fileName);
}
$em = $this->getDoctrine()->getManager();
$em->persist($stamp);
$em->flush();
$this->addFlash('success', 'Successfully edited a stamp!');
return $this->redirectToRoute('admin_stamps_list');
}
return [
'form' => $form->createView(),
];
}
实体
<?php
namespace AppBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\JoinColumn;
use Doctrine\ORM\Mapping\JoinTable;
use Doctrine\ORM\Mapping\ManyToMany;
/**
* Class Stamp
* @package AppBundle\Entity
*
*
* @ORM\Entity(repositoryClass="AppBundle\Repository\StampRepository")
* @ORM\Table(name="stamp")
* @ORM\HasLifecycleCallbacks()
*/
class Stamp
{
/**
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
* @ORM\Column(type="integer")
*/
private $id;
// * @ORM\OneToMany(targetEntity="AppBundle\Entity\StampImage", mappedBy="id", cascade={"persist", "remove"})
/**
* @ManyToMany(targetEntity="AppBundle\Entity\StampImage", cascade={"persist"})
* @JoinTable(name="stamps_images",
* joinColumns={@JoinColumn(name="stamp_id", referencedColumnName="id")},
* inverseJoinColumns={@JoinColumn(name="image_id", referencedColumnName="id", unique=true)}
* ) */
private $images;
/**
* @ORM\Column(type="datetime")
*/
private $createdAt;
/**
* @ORM\Column(type="datetime")
*/
private $updatedAt;
public function __construct()
{
$this->images = new ArrayCollection();
}
/**
* @return mixed
*/
public function getId()
{
return $this->id;
}
public function addImage(StampImage $image)
{
$this->images->add($image);
}
public function removeImage(StampImage $image)
{
$this->images->removeElement($image);
}
/**
* @return mixed
*/
public function getImages()
{
return $this->images;
}
/**
* @param mixed $images
*
* @return $this
*/
public function setImages($images)
{
$this->images = $images;
return $this;
}
/**
* @return mixed
*/
public function getCreatedAt()
{
return $this->createdAt;
}
/**
* @param mixed $createdAt
*
* @return Stamp
*/
public function setCreatedAt($createdAt)
{
$this->createdAt = $createdAt;
return $this;
}
/**
* @return mixed
*/
public function getUpdatedAt()
{
return $this->updatedAt;
}
/**
* @param mixed $updatedAt
*
* @return Stamp
*/
public function setUpdatedAt($updatedAt)
{
$this->updatedAt = $updatedAt;
return $this;
}
/**
* @ORM\PrePersist
* @ORM\PreUpdate
*/
public function updateTimestamps()
{
$this->setUpdatedAt(new \DateTime('now'));
if (null == $this->getCreatedAt()) {
$this->setCreatedAt(new \DateTime());
}
}
}
StampImage实体
<?php
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity as UniqueEntity;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Class StampImage
* @package AppBundle\Entity
*
* @ORM\Entity()
* @ORM\Table(name="stamp_image")
* @UniqueEntity(fields={"name"}, message="This file name is already used.")
*/
class StampImage
{
/**
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
* @ORM\Column(type="integer")
*/
private $id;
/**
* @return mixed
*/
public function getId()
{
return $this->id;
}
private $name;
/**
* @ORM\Column(type="string")
*/
private $fileName;
/**
* @return mixed
*/
public function getFileName()
{
return $this->fileName;
}
/**
* @param mixed $fileName
*
* @return StampImage
*/
public function setFileName($fileName)
{
$this->fileName = $fileName;
return $this;
}
/**
* @return mixed
*/
public function getName()
{
return $this->name;
}
/**
* @param mixed $name
*
* @return StampImage
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
}
主要实体表格
<?php
namespace AppBundle\Form;
use AppBundle\Entity\Stamp;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class AdminStampForm extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('images', CollectionType::class, [
'entry_type' => AdminStampImageForm::class,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Stamp::class,
]);
}
public function getName()
{
return 'app_bundle_admin_stamp_form';
}
}
图片格式
<?php
namespace AppBundle\Form;
use AppBundle\Entity\StampImage;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class AdminStampImageForm extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', FileType::class, [
'image_name' => 'fileName',
'label' => false,
'attr' => [
],
]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => StampImage::class,
'required' => false
]);
}
public function getBlockPrefix()
{
return 'app_bundle_admin_stamp_image_form';
}
}
文件类型扩展程序
- extends 'form_div_layout.html.twig'
- block file_widget
- spaceless
- if image_url is not null
%img{:src => "#{image_url}"}
%div{:style => "display: none;"}
#{block('form_widget')}
- else
#{block('form_widget')}
答案 0 :(得分:2)
1)Multiupload(但不是OneToMany)。
2)编辑上传的图片:
# AppBundle/Entity/Stamp
/**
* @ORM\Column(type="string", length=255)
*/
private $image;
# AppBundle/Form/StampForm
->add('imageFile', FileType::class, [ //the $image property of Stamp entity class will store the path to the file, and this imageFile field will get the uploaded file
'data_class' => null, //important!
])
#AppBundle/Controller/StampController
/**
* @Route("/{id}/edit", name="stamp_edit")
* @Method({"GET", "POST"})
*/
public function editAction(Request $request, Stamp $stamp) {
$editForm = $this->createForm(StampType::class, $stamp, [
'action'=>$this->generateUrl('stamp_edit',['id'=>$stamp->getId()]),
'method'=>'POST'
]);
$editForm->handleRequest($request);
if($editForm->isSubmitted() && $form->isValid()) {
$imageFile = $editForm->get('imageFile')->getData();
if (null != $imageFile) { //this means that for the current record that needs to be edited, the user has chosen a different image
//1. remove the old image
$oldImg = $this->getDoctrine()->getRepository('AppBundle:Stamp')->find($stamp);
$this->get('app.file_remove')->removeFile($oldImg->getImage());
//2. upload the new image
$img = $this->get('app.file_upload')->upload($imageFile);
//3. update the db, replacing the path to the old file with the path to the new uploaded file
$stamp->setImage($img);
$this->getDoctrine()->getManager()->flush();
//4. add a success flash, and anything else you need, and redirect to a route
} else { //if the user has chosen to edit a different field (but not the image one)
$this->getDoctrine()->getManager()->flush();
//add flash message, and redirect to a route
}
}
return $this->render(...);
}
#AppBundle/Services/FileRemove
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Filesystem\Exception\IOExceptionInterface;
class FileRemove {
private $targetDir;
public function __construct($targetDir) {
$this->targetDir = $targetDir;
}
public function removeFile($path) {
$fs = new Filesystem();
$file = $this->targetDir . '/' . $path;
try{
if($fs->exists($file)){
$fs->remove($file);
return true;
}
return false;
} catch(IOExceptionInterface $e){
//log error for $e->getPath();
}
}
}
#app/config/services.yml
app.file_remove:
class: AppBundle/Services/FileRemove
arguments: ['%stamp_dir%']
#app/config/config.yml
parameters:
stamp_dir: '%kernel.root_dir%/../web/uploads/stamps' //assuming this is how you've set up the upload directory
#AppBundle/Services/FileUpload
use Symfony\Component\HttpFoundation\File\UploadedFile;
class FileUpload{
private $targetDir;
public function __construct($targetDir) {
$this->targetDir = $targetDir;
}
public function upload(UploadedFile $file) {
$file_name = empty($file->getClientOriginalName()) ? md5(uniqid()).'.'.$file->guessExtension() : $file->getClientOriginalName();
$file->move($this->targetDir, $file_name);
return $file_name;
}
}
#app/config/services.yml
app.file_upload:
class: AppBundle\Services\FileUpload
arguments: ['%stamp_dir%']
对不起打字错误,如果我的情况适合你的情况,请告诉我这是否有效。
答案 1 :(得分:0)
检查您是否在foreach
之前上传了图片。
if ($form->isSubmitted() && $form->isValid()) {
/** @var Stamp $stamp */
$stamp = $form->getData();
if(!empty($stamp->getImages()) && count($stamp->getImages()) > 0){ // Check uploaded image
foreach ($stamp->getImages() as $image) {
$fileName = md5(uniqid()) . '.' . $image->guessExtension();
/** @var $image StampImage */
$image->getName()->move(
$this->getParameter('stamps_images_directory'),
$fileName
);
$image->setName($fileName)->setFileName($fileName);
}
}
$em = $this->getDoctrine()->getManager();
$em->persist($stamp);
$em->flush();
$this->addFlash('success', 'Successfully edited a stamp!');
return $this->redirectToRoute('admin_stamps_list');
}
更新#1
替换
$fileName = md5(uniqid()) . '.' . $image->getName()->guessExtension();
与
$fileName = md5(uniqid()) . '.' . $image->guessExtension();