Symfony2使用添加/删除方法上传多个文件


Symfony2 multiple file upload with add / remove method

我试图将现有的、正在运行的单文件上传表单升级为具有添加和删除功能的多文件上传。因此,我使用了这个文档:http://symfony.com/doc/current/cookbook/form/form_collections.html#allowing-带有原型的新标签

我的实体不叫标签,而是附件。

我可以通过Javascript添加无限的名称+文件字段。添加后,我得到了这个异常:

致命错误异常:错误:对/Applications/MAMP/htdocs/Seotool/src/Seotool/MainBundle/Entity/Attachments.php行232 中非对象的成员函数contains()的调用

我还认为,当我尝试升级到多上传功能时,并不是所有的代码都是正确的。也许有人能帮我搞定?

这是我当前的代码,从我的控制器开始,他正在生成表单

 /**
@Route(
 *     path = "/taskmanager/user/{user_id}",
 *     name = "taskmanager"
 * )
 * @Template()
 */
public function taskManagerAction($user_id, Request $request)
{
    /* #### NEW TASK #### */
    $task = new Task();
    $attachment = new Attachments();
    $task->getAttachments()->add($attachment);
    $addTaskForm = $this->createForm(new TaskType(), $task);
    $addTaskForm->handleRequest($request);
    if($addTaskForm->isValid()):
        /* User Object of current Users task list */
        $userid = $this->getDoctrine()
            ->getRepository('SeotoolMainBundle:User')
            ->find($user_id);
        $task->setDone(FALSE);
        $task->setUser($userid);
        $task->setDateCreated(new 'DateTime());
        $task->setDateDone(NULL);
        $task->setTaskDeleted(FALSE);
        $attachment->setTask($task);
        $attachment->setUser($userid);
        $attachment->upload();
        $em = $this->getDoctrine()->getManager();
        $em->persist($task);
        $em->flush();
        $this->log($user_id, $task->getId(), 'addTask');
        return $this->redirect($this->generateUrl('taskmanager', array('user_id' => $user_id)));
    endif;
    .....

这是我的Task.php实体的特定代码片段

<?php
namespace Seotool'MainBundle'Entity;
use Doctrine'Common'Collections'ArrayCollection;
use Symfony'Component'Validator'Constraints as Assert;
use Doctrine'ORM'Mapping as ORM;
/**
 * @ORM'Entity
 * @ORM'Table(name="tasks")
 */
class Task {
    ....
/**
 * @ORM'OneToMany(targetEntity="Attachments", mappedBy="task", cascade={"persist"})
 */
protected $attachments;

....
/**
 * Constructor
 */
public function __construct()
{
    $this->log = new 'Doctrine'Common'Collections'ArrayCollection();
    $this->attachments = new 'Doctrine'Common'Collections'ArrayCollection();
}
....
/**
 * Add attachments
 *
 * @param 'Seotool'MainBundle'Entity'Attachments $attachments
 * @return Task
 */
public function addAttachment('Seotool'MainBundle'Entity'Attachments $attachments)
{
    $attachments->addTask($this);
    $this->attachments->add($attachments);
}
/**
 * Remove attachments
 *
 * @param 'Seotool'MainBundle'Entity'Attachments $attachments
 */
public function removeAttachment('Seotool'MainBundle'Entity'Attachments $attachments)
{
    $this->attachments->removeElement($attachments);
}
/**
 * Get attachments
 *
 * @return 'Doctrine'Common'Collections'Collection 
 */
public function getAttachments()
{
    return $this->attachments;
}

这是我的附件.php实体

<?php
namespace Seotool'MainBundle'Entity;
use Doctrine'Common'Collections'ArrayCollection;
use Symfony'Component'HttpFoundation'File'UploadedFile;
use Symfony'Component'Validator'Constraints as Assert;
use Doctrine'ORM'Mapping as ORM;
/**
 * @ORM'Entity
 * @ORM'Table(name="attachments")
 */
class Attachments {
/**
 * @ORM'Column(type="integer")
 * @ORM'Id
 * @ORM'GeneratedValue(strategy="AUTO")
 */
protected $id;
/**
 * @ORM'Column(type="string", length=255)
 * @Assert'NotBlank
 */
public $name;
/**
 * @ORM'Column(type="string", length=255, nullable=true)
 */
public $path;
/**
 * @ORM'ManyToOne(targetEntity="User", inversedBy="attachments")
 * @ORM'JoinColumn(name="user", referencedColumnName="id")
 */
protected $User;

/**
 * @ORM'ManyToOne(targetEntity="Task", inversedBy="attachments")
 * @ORM'JoinColumn(name="task", referencedColumnName="id")
 */
protected $task;
/**
 * @Assert'File(maxSize="6000000")
 */
private $file;
/**
 * Sets file.
 *
 * @param UploadedFile $file
 */
public function setFile(UploadedFile $file = null)
{
    $this->file = $file;
}
/**
 * Get file.
 *
 * @return UploadedFile
 */
public function getFile()
{
    return $this->file;
}
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 up
    // when displaying uploaded doc/image in the view.
    return 'uploads';
}
public function upload()
{
    // the file property can be empty if the field is not required
    if (null === $this->getFile()) {
        return;
    }
    // use the original file name here but you should
    // sanitize it at least to avoid any security issues
    // move takes the target directory and then the
    // target filename to move to
    $this->getFile()->move(
        $this->getUploadRootDir(),
        $this->getFile()->getClientOriginalName()
    );
    // set the path property to the filename where you've saved the file
    $this->path = $this->getFile()->getClientOriginalName();
    // clean up the file property as you won't need it anymore
    $this->file = null;
}


/**
 * Get id
 *
 * @return integer 
 */
public function getId()
{
    return $this->id;
}
/**
 * Set name
 *
 * @param string $name
 * @return Attachments
 */
public function setName($name)
{
    $this->name = $name;
    return $this;
}
/**
 * Get name
 *
 * @return string
 */
public function getName()
{
    return $this->name;
}
/**
 * Set path
 *
 * @param string $path
 * @return Attachments
 */
public function setPath($path)
{
    $this->path = $path;
    return $this;
}
/**
 * Get path
 *
 * @return string 
 */
public function getPath()
{
    return $this->path;
}
/**
 * Set User
 *
 * @param 'Seotool'MainBundle'Entity'User $user
 * @return Attachments
 */
public function setUser('Seotool'MainBundle'Entity'User $user = null)
{
    $this->User = $user;
    return $this;
}
/**
 * Get User
 *
 * @return 'Seotool'MainBundle'Entity'User 
 */
public function getUser()
{
    return $this->User;
}

/**
 * Set Task
 *
 * @param 'Seotool'MainBundle'Entity'Task $task
 * @return Attachments
 */
public function setTask('Seotool'MainBundle'Entity'Task $task = null)
{
    $this->task = $task;
    return $this;
}
/**
 * Get Task
 *
 * @return 'Seotool'MainBundle'Entity'Task
 */
public function getTask()
{
    return $this->task;
}
public function addTask(Task $task)
{
    if (!$this->task->contains($task)) {
        $this->task->add($task);
    }
}
}

这是我的TaskType.php表单类型类:

<?php
namespace Seotool'MainBundle'Form'Type;
use Doctrine'ORM'EntityRepository;
use Symfony'Component'Form'AbstractType;
use Symfony'Component'Form'FormBuilderInterface;
use Symfony'Component'OptionsResolver'OptionsResolverInterface;
class TaskType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
         ....
    $builder->add('attachments', 'collection', array(
        'type' => new AttachmentsType(),
        'allow_add' => true,
        'allow_delete' => true,
        'delete_empty' => true,
        'by_reference' => false,
    ));

这是我的AttachmentsType.php表单类型类:

<?php
namespace Seotool'MainBundle'Form'Type;
use Doctrine'ORM'EntityRepository;
use Symfony'Component'Form'AbstractType;
use Symfony'Component'Form'FormBuilderInterface;
use Symfony'Component'OptionsResolver'OptionsResolverInterface;
class AttachmentsType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
    $builder->add('name', 'text', array(
        'label' => 'Dateiname',
        'required' => false,
    ));
    $builder->add('file', 'file', array(
        'label' => false,
        'required' => false,
        "attr" => array(
            "multiple" => "multiple",
        )
    ));
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
    $resolver
            ->setDefaults(array(
                'data_class' => 'Seotool'MainBundle'Entity'Attachments'
            ));
}
public function getName()
{
    return 'attachments';
}
}

您的问题是在添加附件时使用了错误的调用。

附件和任务之间的关联是manyToOne,意思是attachments needed to be added to a task而不是a task needs to be set on an attachment

要解决您的问题,您只需更改的添加附件呼叫

public function addAttachment('Seotool'MainBundle'Entity'Attachments $attachments)
{
    $attachments->addTask($this);
    // this should be set not add
    $this->attachments->add($attachments);
}

public function addAttachment('Seotool'MainBundle'Entity'Attachments $attachment)
{
    $attachment->setTask($this);
    $this->attachments->add($attachment);
}