Pre_submit 在 Symfony3 上保存数据时出现问题

Pre_submit problem saving data on Symfony3

我有一堆公司,其中有一个徽标字段。我在编辑页面的想法是,如果在编辑表单中,该字段为空,保留我们之前在数据库中的徽标,因为这是一个必填字段。

我的想法是获取之前要提交的表单的数据,检查该字段是否为空,从数据库中获取数据进行更新。我用过eventListener,但是当数据提交时,它并没有改变为null。我几乎是这个 symfony 版本的新手,但我无法做到这一点。你可以帮帮我吗。谢谢,

/**
    * @Route("/admin/companies/edit/{id}", name="edit_company")
    * Method({"GET", "POST"})
    */
    public function editCompany(Request $request, $id){

        $company = new Company();
        $company = $this->getDoctrine()->getRepository(Company::class)->find($id);      

        $form = $this->createFormBuilder($company)
            ->add('name', TextType::class, array('attr' => array('class' => 'form-control')))
            ->add('description', TextAreaType::class, array('attr' => array('class' => 'form-control summernote')))
            ->add('telephone', TextType::class, array('attr' => array('class' => 'form-control')))
            ->add('city', TextType::class, array('attr' => array('class' => 'form-control')))
            ->add('web', UrlType::class, array('attr' => array('class' => 'form-control')))
            ->add('image', FileType::class, array('data_class' => null, 'label' => false, 'required' => false, 'attr' => array('class' => 'form-control d-none')))            
            ->add('save', SubmitType::class, ['label' => 'Edit Company', 'attr' => array('class' => 'btn btn-success p-2 mt-5')])`enter code here`
            ->addEventListener(FormEvents::PRE_SUBMIT, function(FormEvent $event) {
                $data = $event->getData();
                $form = $event->getForm();
                $image = $data['image'];
                if ($image == null){
                    $company_tmp = $this->getDoctrine()->getRepository(Company::class)->find($form->getData()->getId());
                    $data['image'] = $company_tmp->getImage();           
                    $event->setData($data);
                }               

            })          
            ->getForm();

        $form->handleRequest($request);


        if ( ($form->isSubmitted()) && ( $form->isValid() ) ){          

            $company = $form->getData();

            $file = $form->get('image')->getData();

            if ($file !== null){
                $fileName = 'company-'.$this->generateUniqueFileName().'.'.$file->guessExtension();                         
                // Move the file to the directory where brochures are stored
                try {
                    $moved = $file->move( $this->get('kernel')->getProjectDir() . '/public/uploads', $fileName );
                } catch (FileException $e) {
                   throw new HttpNotFoundException("Page not found");
                }
                $company->setImage($fileName);
            }

            $entityManager= $this->getDoctrine()->getManager();     
            $entityManager->flush();
            $flashbag = $this->get('session')->getFlashBag();           
            $flashbag->add("success", "Company Edited Correctly");  

            return $this->redirectToRoute('companies_list');
        }

        return $this->render('admin/edit_company.html.twig', 
            array(
                'form' => $form->createView(),
                'company' => $company,
            )
        );
    }

例如,如果先前要保存的图像的名称是company122121.jpg,而编辑表单数据为空,则在数据库中保留company122121.jpg。但结果总是空的。我已经检查了监听器上的 $event->getData() 并且数据是正确的,但是当我在 isSubmitted() 之后获取数据时,数据为空。

Result with dump listener and image after submit

来自官方文档: https://symfony.com/doc/current/controller/upload_file.html

When creating a form to edit an already persisted item, the file form type still expects a File instance. As the persisted entity now contains only the relative file path, you first have to concatenate the configured upload path with the stored filename and create a new File class:

use Symfony\Component\HttpFoundation\File\File;
// ...

$product->setBrochure(
    new File($this->getParameter('brochures_directory').'/'.$product->getBrochure())
);

所以我认为你应该添加

$company->setImage(new File($pathToYourImage));

之后
$company = $this->getDoctrine()->getRepository(Company::class)->find($id);      

我还建议通过 Doctrine 事件订阅者包含的服务处理图像上传。

我还将图像作为媒体对象保存到数据库中,其中包含已通过 postLoad 侦听器正确解析的上传图像的文件名。

参考: Doctrine Event Subscriber File Upload Service

class UploadHandler
{
    /** @var string */
    private $fileDirectory;

    /**
     * FileUploader constructor.
     *
     * @param string $fileDirectory
     */
    public function __construct(
        string $fileDirectory
    ) {
        $this->fileDirectory = $fileDirectory;
    }

    /**
     * Move the file to the upload directory.
     *
     * @param UploadedFile $file
     *
     * @return string
     */
    public function upload(UploadedFile $file) {
        $fileName = md5(uniqid() . '.' . $file->guessExtension());

        $file->move($this->getFileDirectory(), $fileName);

        return $fileName;
    }

    /**
     * @return string
     */
    public function getFileDirectory(): string {
        return $this->fileDirectory;
    }
}
class UploadEventSubscriber
{
    /**
     * @var FileUploader
     */
    private $uploader;

    /**
     * UploadEventSubscriber constructor.
     * @param FileUploader $uploader
     */
    public function __construct(
        FileUploader $uploader
    )
    {
        $this->uploader = $uploader;
    }

    /**
     * Returns an array of events this subscriber wants to listen to.
     *
     * @return string[]
     */
    public function getSubscribedEvents()
    {
        return [
            'prePersist',
            'preUpdate',
            'postLoad'
        ];
    }

    /**
     * Pre-Persist method for Media.
     *
     * @param LifecycleEventArgs $args
     */
    public function prePersist(LifecycleEventArgs $args) {
        /** @var Media $entity */
        $entity = $args->getEntity();

        if (!$this->validInstance($entity)) {
            return;
        }

        $this->uploadFile($entity);
    }

    /**
     * Pre-Update method for Media.
     *
     * @param LifecycleEventArgs $args
     */
    public function preUpdate(LifecycleEventArgs $args) {
        /** @var Media $entity */
        $entity = $args->getEntity();

        if (!$this->validInstance($entity)) {
            return;
        }

        $this->uploadFile($entity);
    }

    /**
     * Post-Load method for Media
     *
     * @param LifecycleEventArgs $args
     */
    public function postLoad(LifecycleEventArgs $args) {
        /** @var Media $entity */
        $entity = $args->getEntity();

        if (!$this->validInstance($entity)) {
            return;
        }

        $fileName = $entity->getImage();
        if($fileName) {
            $entity->setImage(new File($this->uploader->getFileDirectory() . '/' . $fileName));
        }
    }

    /**
     * Check if a valid entity is given.
     *
     * @param object $entity
     * @return bool
     */
    private function validInstance($entity)
    {
        return $entity instanceof Media;
    }

    /**
     * Upload the file
     * @param Media $entity
     */
    private function uploadFile(Media $entity)
    {
        $file = $entity->getImage();

        if($file instanceof UploadedFile) {
            $fileName = $this->uploader->upload($file);
            $entity->setImage($fileName);
        }
    }
}