2016-01-20 10 views
5

Mam aplikację Symfony2 z formularzem, w którym znajduje się pole typu pliku. Muszę przesłać obraz tam student, więc pomogłem tej dokumentacji: How to Upload FilesSymfony2: Przesyła plik za pomocą Ajax i jQuery

To jest mój kodu:

Kontroler:

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(), 
    )); 
} 

Podmiot:

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); 
     } 
    } 
}); 
}); 

Problem mam teraz jest muszę zrobić to z żądania Ajax, ale nie wiem, jak wysłać to pole pliku i może być stosowany wówczas kontroler Symfony.

Widziałem niektóre FormData(), ale nie wiem, w jaki sposób jest używany.

Czy możesz mi pomóc?

+0

Czy możesz mi pomóc? Nie chcę iść gdzie indziej, aby spojrzeć na twój kod. –

+0

Witam @MadPhysicist. Przepraszamy, dodałem kod. – Joseph

+1

@Joseph IIRC możesz dodać odpowiedź i zaakceptować ją. –

Odpowiedz

7

I został rozwiązany zmianę w moim kodu:

  • data: new FormData($(this)[0]) zamiast data: $ (this).serialize()

  • Dodanie żądania ajax:

    processData: false, contentType: false, cache: false,

, a plik zostanie wysłany poprawnie

+0

Element 'new FormData()' HTML5 łamie kompatybilność z IE8/9 - serializacja nie powinna stanowić problemu. To, co naprawia problem, to: '{processData: false, contentType: false}' – maschmann

0

Aktualizacja:

Myślę, że problemem jest to, że trzeba deserializowania odebrany w kontrolerze w przypadku, gdy złożenie poprzez AJAX

Addentionally należy szeregować formę wyraźnie i nie serializacji przy użyciu tej this

var data= $('form.form_student').serialize(); 
+0

Witam @ Nickolaus. Wybacz mojej niewiedzy, ale jaką część mojego kodu mogę sprawdzić? Przypisałem go bezpośrednio do kontrolera plików zmiennej $ i podążam za tym samym komunikatem o błędzie. – Joseph

+0

Po wyświetleniu komunikatu o błędzie ... pomocne byłoby ustalenie przyczyny błędu. – Nickolaus

+0

Po otrzymaniu komunikatu o błędzie: "Nie można znaleźć pliku" @Nickolaus, myślę, że to dlatego, że Ajax musi wysłać plik w inny sposób, widziałem tam, ale nie wiem. Bez żądania Ajax jest poprawnie zapisany. – Joseph

2

Mam rozwiązać to w następujący sposób, jeśli chcesz to zrobić za pomocą Ajax.

W swojej jednostce zadeklarować tak:

/** 
*@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); 
     } 
    } 
} 

W swojej FormType:

->add('file', null, array('label' => 'Profile Picture', 'required' => false)) 

W Tobie Kontroler:

$entity->setFile($request->files->get('photo')); //here you have get your file field name 
    $em->persist($entity); 
    $em->flush(); 

Twój ajax wygląda w porządku, ale jeśli to nie zadziała niż używać

data:new FormData(this), 

zamiast

data: $(this).serialize(), 

i dodać te dwa parametry w Ajax:

 processData: false, 
     contentType: false 

Można zmienić sposób zapisać plik jako wymóg i zmienić polu Ścieżka do fotografii.

+0

Witam @herr, dziękuję za odpowiedź, na koniec Właśnie poprawiam swój kod zmieniając 'dane: $ (this) .serialize()' z 'data: new FormData ($ (this) [0])' – Joseph

+0

Sorry @ Josepe zapomniałem dodać w odpowiedzi te dwa parametry processData: false, contentType: false. wymagane do wysyłania plików w ajax. – herr

+0

Hi @herr, mam problem, teraz nie mogę pozostawić pustego wartości pliku w moim kodzie w formularzu, ponieważ daje mi ten błąd: 'Błąd: Wywołanie funkcji member guessExtension() na obiekcie niebędącym obiektem w ... '. Dodałem warunek, aby przetestować kontroler, który jest nieważny, a nie fragment kodu do przesłania pliku do uruchomienia, ale nadal daje mi ten błąd, może nie robię dobrze. Próbowałem również Twojego kodu, ale otrzymałem komunikat potwierdzający, który już pokazał mi inne kody: "Ten formularz nie może mieć dodatkowych pól". Czy wiesz, jak to naprawić, aby pozostawić puste pole w formularzu? – Joseph