Ответ 1
Я решил изменить свой код:
-
data: new FormData($(this)[0])
вместоdata: $ (this).serialize()
-
Добавление запроса ajax:
processData: false,
contentType: false,
cache: false,
и файл отправлен правильно
У меня есть приложение Symfony2 с формой, где есть поле типа файла. Мне нужно загрузить изображение студента, поэтому я помог этой документации: Как загрузить файлы
Это мой код:
Контроллер:
public function createAction(Request $request)
{
if ($request->isXmlHttpRequest() && !$request->isMethod('POST')) {
throw new HttpException('XMLHttpRequests/AJAX calls must be POSTed');
}
$entity = new Student();
$form = $this->createCreateForm($entity);
$form->handleRequest($request);
if ($form->isValid()) {
$file = $entity->getPhoto();
$fileName = md5(uniqid()).'.'.$file->guessExtension();
$photoDir = $this->container->getParameter('kernel.root_dir').'/../web/uploads/images';
$file->move($photoDir, $fileName);
$entity->setPhoto($fileName);
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
if ($request->isXmlHttpRequest()) {
return new JsonResponse(array('message' => 'Success!','success' => true), 200);
}
if ($request->isMethod('POST')) {
return new JsonResponse(array('message' => 'Invalid form','success' => false), 400);
}
return $this->redirect($this->generateUrl('student_show', array('id' => $entity->getId())));
}
return $this->render('BackendBundle:Student:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView(),
));
}
Entity:
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
//...
/**
* @var string
*
* @ORM\Column(name="photo", type="string", length=255, nullable=true)
*
*/
private $photo;
public function setPhoto($photo)
{
$this->photo = $photo;
return $this;
}
public function getPhoto()
{
return $this->photo;
}
formtype:
//...
->add('photo', 'file', array('required' => false))
//...
JavaScript:
//...
$('.form_student').on("submit",function(event) {
event.preventDefault();
$.ajax({
type: 'POST',
url: Routing.generate('student_create'),
data: $(this).serialize(),
dataType: 'json',
success: function(response) {
alert(response.message);
},
error: function (response, desc, err){
if (response.responseJSON && response.responseJSON.message) {
alert(response.responseJSON.message);
}
else{
alert(desc);
}
}
});
});
Теперь проблема заключается в том, что я должен сделать это с помощью запроса Ajax, но не знаю, как отправить это поле файла, и его можно использовать тогда в контроллере Symfony.
Я видел несколько FormData()
, но не знаю, как он используется.
Не могли бы вы мне помочь?
Я решил изменить свой код:
data: new FormData($(this)[0])
вместо data: $ (this).serialize()
Добавление запроса ajax:
processData: false,
contentType: false,
cache: false,
и файл отправлен правильно
Я решил это следующим образом, если вы хотите сделать это с помощью Ajax.
В вашей организации объявите это:
/**
*@ORM\HasLifecycleCallbacks
*/
class Student
{
/**
* @ORM\Column(type="string", length=255, nullable=true)
*/
public $path;
/**
* @Assert\File(
* maxSize="60000",
* )
*/
private $file;
private $temp;
/**
* Sets file.
*
* @param UploadedFile $file
*/
public function setFile(UploadedFile $file = null)
{
$this->file = $file;
if (isset($this->path)) {
// store the old name to delete after the update
$this->temp = $this->path;
$this->path = null;
} else {
$this->path = 'initial';
}
}
/**
* Get file.
*
* @return UploadedFile
*/
public function getFile()
{
return $this->file;
}
public function getAbsolutePath()
{
return null === $this->path
? null
: $this->getUploadRootDirPath().'/'.$this->path;
}
public function getWebPath()
{
return null === $this->path
? null
: $this->getUploadDirPath().'/'.$this->path;
}
protected function getUploadRootDirPath()
{
// the absolute directory path where uploaded
// documents should be saved
return __DIR__.'/../../../../web/'.$this->getUploadDirPath();
}
protected function getUploadDirPath()
{
// get rid of the __DIR__ so it doesn't screw up
// when displaying uploaded doc/image in the view.
return 'uploads/student_photos';
}
/**
* @ORM\PrePersist()
* @ORM\PreUpdate()
*/
public function preUpload()
{
if (null !== $this->getFile()) {
// do whatever you want to generate a unique name
$filename = basename($this->getFile()->getClientOriginalName(),'.'.$this->getFile()->getClientOriginalExtension());
$this->path = $filename.'.'.$this->getFile()->getClientOriginalExtension();
if(file_exists($this->getUploadRootDirPath().'/'.$this->path)==1)
{
$date = date('-d_M_Y_H:i');
$this->path = $filename.$date.'.'.$this->getFile()->getClientOriginalExtension();
}
}
}
/**
* @ORM\PostPersist()
* @ORM\PostUpdate()
*/
public function upload()
{
if (null === $this->getFile()) {
return;
}
$this->getFile()->move($this->getUploadRootDirPath(), $this->path);
if (isset($this->temp)) {
// delete the old image
unlink($this->getUploadRootDirPath().'/'.$this->temp);
// clear the temp image path
$this->temp = null;
}
$this->file = null;
}
/**
* @ORM\PostRemove()
*/
public function removeUpload()
{
$file = $this->getAbsolutePath();
if ($file) {
unlink($file);
}
}
}
В вашем FormType:
->add('file', null, array('label' => 'Profile Picture', 'required' => false))
В контроллере:
$entity->setFile($request->files->get('photo')); //here you have get your file field name
$em->persist($entity);
$em->flush();
ваш ajax выглядит отлично, но если это не сработает, чем использование
data:new FormData(this),
вместо
data: $(this).serialize(),
и добавьте эти два параметра в ajax:
processData: false,
contentType: false
Вы можете изменить способ сохранения файла как свое требование и изменить путь к фотографии.
Update:
Я думаю, проблема заключается в том, что вы должны десериализовать полученное в вашем контроллере, если вы отправляете через ajax
Допустим, вы должны сериализовать форму явно и не сериализоваться с помощью этого this
var data= $('form.form_student').serialize();