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);
}
}
}
我有一堆公司,其中有一个徽标字段。我在编辑页面的想法是,如果在编辑表单中,该字段为空,保留我们之前在数据库中的徽标,因为这是一个必填字段。
我的想法是获取之前要提交的表单的数据,检查该字段是否为空,从数据库中获取数据进行更新。我用过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);
}
}
}