2012-05-04 9 views
13

Tôi đang tạo một ứng dụng Symfony2 cần có tùy chọn tải lên nhiều hình ảnh. Tôi đã thực hiện tải lên một tệp bằng cách sử dụng mục nhập sổ nấu ăn: How to handle File Uploads with Doctrine hoạt động tốt. Tôi đã triển khai lifecyclecallbacks để tải lên và xóa.Sự cố với nhiều tệp tải lên trong Symfony2

Bây giờ tôi cần phải biến điều này thành hệ thống tải lên nhiều. Tôi đã đọc một vài câu trả lời từ Stack Overflow là tốt, nhưng không có gì có vẻ làm việc.

Stack Overflow Câu hỏi:

  1. Multiple file upload with Symfony2
  2. multiple file upload symfony 2

Tôi có đoạn mã sau vào lúc này:

file Entity:

<?php 
namespace Webmuch\ProductBundle\Entity; 

use Doctrine\ORM\Mapping as ORM; 
use Symfony\Component\Validator\Constraints as Assert; 
use Symfony\Component\HttpFoundation\File\UploadedFile; 


/** 
* @ORM\Entity 
* @ORM\HasLifecycleCallbacks 
*/ 
class File 
{ 
    /** 
    * @ORM\Id 
    * @ORM\Column(type="integer") 
    * @ORM\GeneratedValue(strategy="AUTO") 
    */ 
    public $id; 

    /** 
    * @ORM\Column(type="string", length=255, nullable=true) 
    */ 
    public $path; 

    /** 
    * @Assert\File(maxSize="6000000") 
    */ 
    public $file = array(); 

    public function __construct() 
    { 

    } 

    /** 
    * Get id 
    * 
    * @return integer 
    */ 
    public function getId() 
    { 
     return $this->id; 
    } 

    /** 
    * Set path 
    * 
    * @param string $path 
    */ 
    public function setPath($path) 
    { 
     $this->path = $path; 
    } 

    /** 
    * Get path 
    * 
    * @return string 
    */ 
    public function getPath() 
    { 
     return $this->path; 
    } 


    public function getAbsolutePath() 
    { 
     return null === $this->path ? null : $this->getUploadRootDir().'/'.$this->path; 
    } 

    public function getWebPath() 
    { 
     return null === $this->path ? null : $this->getUploadDir().'/'.$this->path; 
    } 

    protected function getUploadRootDir() 
    { 
     // the absolute directory path where uploaded documents should be saved 
     return __DIR__.'/../../../../web/'.$this->getUploadDir(); 
    } 

    protected function getUploadDir() 
    { 
     // get rid of the __DIR__ so it doesn't screw when displaying uploaded doc/image in the view. 
     return 'uploads'; 
    } 

    /** 
    * @ORM\PrePersist() 
    * @ORM\PreUpdate() 
    */ 
    public function preUpload() 
    { 
     if (null !== $this->file) { 
      // do whatever you want to generate a unique name 
      $this->path[] = uniqid().'.'.$this->file->guessExtension(); 
     } 
    } 

    /** 
    * @ORM\PostPersist() 
    * @ORM\PostUpdate() 
    */ 
    public function upload() 
    { 
     if (null === $this->file) { 
      return; 
     } 

     // if there is an error when moving the file, an exception will 
     // be automatically thrown by move(). This will properly prevent 
     // the entity from being persisted to the database on error 
     $this->file->move($this->getUploadRootDir(), $this->path); 

     unset($this->file); 
    } 

    /** 
    * @ORM\PostRemove() 
    */ 
    public function removeUpload() 
    { 
     if ($file = $this->getAbsolutePath()) { 
      unlink($file); 
     } 
    } 
} 

FileController:

<?php 

namespace Webmuch\ProductBundle\Controller; 

use Symfony\Bundle\FrameworkBundle\Controller\Controller; 
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; 
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; 
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; 

use Webmuch\ProductBundle\Entity\File; 


/** 
* File controller. 
* 
* @Route("/files") 
*/ 
class FileController extends Controller 
{ 
    /** 
    * Lists all File entities. 
    * 
    * @Route("/", name="file_upload") 
    * @Template() 
    */ 
    public function uploadAction() 
    { 
     $file = new File(); 
     $form = $this->createFormBuilder($file) 
      ->add('file','file',array(
        "attr" => array(
         "accept" => "image/*", 
         "multiple" => "multiple", 
        ) 
       )) 
      ->getForm() 
     ; 

     if ($this->getRequest()->getMethod() === 'POST') { 
      $form->bindRequest($this->getRequest()); 
       $em = $this->getDoctrine()->getEntityManager(); 

       $em->persist($file); 
       $em->flush(); 

       $this->redirect($this->generateUrl('file_upload')); 
     } 

     return array('form' => $form->createView()); 
    } 
} 

upload.html.twig:

{% extends '::base.html.twig' %} 

{% block body %} 
<h1>Upload File</h1> 

<form action="#" method="post" {{ form_enctype(form) }}> 

    {{ form_widget(form.file) }} 

    <input type="submit" value="Upload" /> 
</form> 
{% endblock %} 

Tôi không biết phải làm gì để thực hiện công việc này như một hệ thống nhiều tập tin tải lên . Tôi đã giữ những bình luận như chúng từ những hướng dẫn mà tôi đã theo để tôi có thể nhớ những gì đang làm.

UPDATE:

New Form Code:

$images_form = $this->createFormBuilder($file) 
    ->add('file', 'file', array(
      "attr" => array(
       "multiple" => "multiple", 
       "name" => "files[]", 
      ) 
     )) 
    ->getForm() 
; 

New Form Twig Code:

<form action="{{ path('file_upload') }}" method="post" {{ form_enctype(images_form) }}> 

    {{ form_label(images_form.file) }} 
    {{ form_errors(images_form.file) }} 
    {{ form_widget(images_form.file, { 'attr': {'name': 'files[]'} }) }} 

    {{ form_rest(images_form) }} 
    <input type="submit" /> 
</form> 
+0

Điều gì hiện không hoạt động với tính năng này? – halfer

+0

Cảm ơn bạn đã trả lời. Nếu tôi chọn cho ví dụ 5 tệp, chỉ tệp cuối cùng mới được tải lên. –

+0

À vâng - điều khiển đầu vào của bạn cần phải có một tên riêng lẻ - vì nó không có tên tại thời điểm này, nó sử dụng một tên mặc định cho tất cả các điều khiển. – halfer

Trả lời

15

Đây là một vấn đề được biết as referenced on GitHub.

Khi họ nói, bạn nên thêm [] vào thuộc tính full_name trong mẫu của bạn:

{{ form_widget(images_form.file, { 'full_name': images_form.file.get('full_name') ~ '[]' }) }} 
+4

Trong symfony 2.5 bạn có thể đạt được nó bằng cách sử dụng: '{{form_widget (images_form.file, {'full_name': images_form.file.vars.full_name ~ '[]'})}}' – ezpn

+0

tuyệt vời! đây là câu trả lời đúng và nó phải được đánh dấu là hợp lệ. – xger86x

+0

Cảm ơn bạn đã liên kết vấn đề github. Nó thực sự đã giúp tôi với vấn đề xác nhận của tôi. Tôi cũng đã thêm một giải pháp khác làm câu trả lời, nó cũng hoạt động hoàn hảo. – func0der

3

tôi đã cùng một vấn đề thời gian gần đây, tiếp theo những gợi ý ở đây, nhưng có một lỗi, bởi vì các validator 'file' không thể xử lý mảng.

Vì vậy, tôi phải viết trình xác thực của riêng mình, trình xác thực có thể xử lý nhiều tệp. Đối với điều đó, tôi đã theo dõi this tutorial from Symfony.com, sao chép/dán mã từ tệp 'trình xác thực' hợp lệ vào trong đó, đóng gói nó bằng vòng lặp foreach và thay đổi các biến khi cần.

Nếu bạn làm điều này, bạn có thể sử dụng nó cho $file trong thực thể của bạn.

+4

Bạn có thể chia sẻ mã đó để tôi có thể xem không? Thnx. –

4

Tôi không biết liệu điều đó có thể thực hiện được với cú pháp chú thích hay không.Vì vậy, tôi sẽ viết nó bằng đồng bằng PHP trong bộ điều khiển

$images_form = $this->createFormBuilder($file) 
    ->add('file', 'file', array(
     'constraints' => array(
      new NotBlank(), // Makes sure it is filled at all. 
      new All(array(// Validates each an every entry in the array that is uploaded with the given constraints. 
       'constraints' => array(
        new File(array(
         'maxSize' => 6000000 
        )), 
       ), 
      )), 
     ), 
     'multiple' => TRUE, 
    )) 
    ->getForm(); 

Điều này sẽ hoạt động hoàn hảo vì Symfony 2.4. Trước đó, bạn sẽ phải đặt thuộc tính multiple trong khóa attr như bạn đã làm.

Như tôi đã nói, bạn phải thực hiện công việc này bằng chú thích. Nó có thể làm việc nhưng có thể ít đọc được nếu bạn phải đặt tất cả trong một dòng.

Vui chơi;)

+0

về các chú thích: đây là ví dụ trên trang web của symfony. http://symfony.com/doc/current/reference/constraints/All.html lớp 'tài { /** * @Assert \ Tất cả ({ * @Assert \ NotBlank, * @Assert \ Chiều dài (min = 5) *}) */ được bảo vệ $ favoriteColors = array(); } ' – nexana