Symfony VichUploaderBundle:无法生成文件名

时间:2016-03-02 14:26:08

标签: php symfony vichuploaderbundle

我正在使用VichUploader在symfony项目中上传文件。在我使用的配置中(从文档中复制):

service: vich_uploader.namer_property
options: { property: 'slug'}

在我的实体中,我使用Gedmo / Sluggable自动生成slu ::

/**
 * @Gedmo\Slug(fields={"title"}, updatable=false)
 * @ORM\Column(type="string", length=100, nullable=false)
 */
protected $slug;

但是当试图保存实体时,我得到以下错误500:

  

无法生成文件名:属性slug为空。

如果我将该属性设置为' title'有用。我是否忘记了配置参数或其他什么来使它与Gedmo slug一起工作?

4 个答案:

答案 0 :(得分:2)

此刻,我遇到了同样的问题,作为一种解决方法,我在实体类中做了些改动:

use Gedmo\Sluggable\Util\Urlizer;

class Event
{
    // ...

    /**
     * @var string
     *
     * @Gedmo\Slug(fields={"name"})
     * @ORM\Column(name="slug", type="string", length=128, unique=true)
     */
    private $slug;

    // ...

    public function getSlug()
    {
        if (!$this->slug) {
            return Urlizer::urlize($this->getName());
        }

        return $this->slug;
    }
}

做到了。

不幸的是,有两个缺点:

  1. 如果您想更新批注中的缓慢行为以包括其他属性,则还必须更新getter。
  2. 此方法缺少对数据库的检查:如果数据库中已经有一个记录,且在getter中具有相同名称urlizer,则无法在文件名中添加增量,则以前保存的文件可能被覆盖!解决方法是,您可以将unique=true添加到易耗属性。

答案 1 :(得分:1)

VichUploader侦听prePersist和preUpdate事件,而Sluggable侦听onFlush事件。因为prePersist和preUpdate是在onFlush之前调用的,所以不可能仅使用配置来做到这一点。

但是,如果文件字段可为空,则可以通过更改控制器代码来解决该问题。当您收到带有文件的提交表单时,请删除文件,保存实体,然后重新添加文件并再次保存实体。在第二次保存时,将已经设置了子文件,因此VichUploader将可以很好地保存文件。

if ($form->isSubmitted() && $form->isValid()) {
    if ($file = $entity->getFile()) {
        $entity->setFile(null);
    }

    $em = $this->getDoctrine()->getManager();
    $em->persist($entity);
    $em->flush();

    if ($file) {
        $document->setFile($file);
        $em->persist($entity);
        $em->flush();
    }

    // ...
}

仅在添加新文件时有效。如果随后更改了子段并重新保存实体而不上传新文件,则文件名不会更新。

答案 2 :(得分:0)

默认情况下,doctrine extensions bundle不会附加任何侦听器: http://symfony.com/doc/current/bundles/StofDoctrineExtensionsBundle/index.html#activate-the-extensions-you-want

您应该将其配置为缓慢工作:

stof_doctrine_extensions:
    orm:
        default:
            sluggable: true

答案 3 :(得分:0)

我在上传文件时遇到了同样的问题,为此我需要使用fileName作为文件名。

我当时使用Gedmo批注来生成该段塞,但这仅在刷新时触发,而vichUploader名称器在持久化时触发。

对我来说,最简单的方法是不使用Gedmo \ Sluggable注释,而是在我的Document对象上创建一个prePersist侦听器,并使用Cocur \ Slugify库。

这是代码。

我的文档实体:

namespace App\Entity;

use Doctrine\ORM\Mapping as ORM;
use Gedmo\Timestampable\Traits\TimestampableEntity;
use Symfony\Component\HttpFoundation\File\File;
use Vich\UploaderBundle\Mapping\Annotation as Vich;

/**
 * @ORM\Entity(repositoryClass="App\Repository\DocumentRepository")
 * @Vich\Uploadable
 * @ORM\EntityListeners({"App\Listeners\DocumentListener"})
 */
class Document
{
    use TimestampableEntity;

    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;


    /**
     * @ORM\Column(type="string", length=100, nullable=false)
     */
    private $fileName;

    /**
     * @Vich\UploadableField(mapping="document", fileNameProperty="fileName")
     * @var File
     */
    private $documentFile;

    /**
     * @ORM\Column(type="string", length=100, unique=true)
     */
    private $slug;

    /**
     */
    public function getDocumentFile(): ?File
    {
        return $this->documentFile;
    }

    /**
     * @param File $documentFile
     * @return Document
     * @throws \Exception
     */
    public function setDocumentFile(File $documentFile = null): Document
    {
        $this->documentFile = $documentFile;
        if($documentFile){
            $this->updatedAt = new \DateTimeImmutable();
        }

        return $this;
    }

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getSlug(): ?string
    {
        return $this->slug;
    }

    public function setSlug(string $slug): self
    {
        $this->slug = $slug;

        return $this;
    }

    /**
     * @return mixed
     */
    public function getFileName()
    {
        return $this->fileName;
    }

    /**
     * @param mixed $fileName
     */
    public function setFileName($fileName): void
    {
        $this->fileName = $fileName;
    }
}

还有听众:

namespace App\Listeners;

use App\Entity\Document;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Cocur\Slugify\Slugify;

class DocumentListener
{
    public function prePersist(Document $document, LifecycleEventArgs $args)
    {
        $slugify = new Slugify();
        if(!empty($document->getDocumentFile())){
            $originalName = pathinfo($document->getDocumentFile()->getClientOriginalName(), PATHINFO_FILENAME);
            $slug = $slugify->slugify($originalName);
            $document->setSlug($slug);
        }
    }
}

到目前为止,我还没有遇到任何问题。

让我知道这是否对您有用