我还在学习Symfony2并且不了解如何上传文件。
别担心,我已经检查了the documentation。这真的很好,但我的问题没有在任何教程中解释。
我正在寻找有关如何使用Symfony2上传文件但有所有人需要的所有内容的指导(例如扩展约束,基于id和内容重命名文件,在db中存储路径等。 ..)
我找到了很好的教程,试图混合它们但没有成功。每次出现不同的问题:文件在表单上的每次提交时重新上传(即使文件字段为空),guessExtension也不可能使用,tmp路径存储在数据库而不是正确的路径,文件没有移动,不可能在重命名中使用了id,因为id是自动递增的,因此尚未生成。
所以,我会放一个'标准'实体,比方说:Photo.php
/**
* Photo
*
* @ORM\Table(name="photo")
* @ORM\Entity
* @ORM\HasLifecycleCallbacks
*/
class Photo
{
// Annotation for the id and auto increment etc
private $id;
/**
* @var string
* @Assert\File( maxSize = "3072k", mimeTypesMessage = "Please upload a valid Image")
* @ORM\Column(name="image", type="string", length=245, nullable=false)
*/
private $image
private $title
private $description
// all the function get, set for the 4 previous variables
}
和控制器:
public function addPhotoAction()
{
$add_photo = new Photo;
$formBuilderPhoto = $this->createFormBuilder($add_photo);
$formBuilderPhoto
->add('title','text',array('label' => 'Title of the photo', 'required' => true))
->add('image','file', array('required' => true, 'data_class' => null))
->add('description','textarea',array('label' => 'Description of your photo', 'required' => false))
;
$form_photo = $formBuilderPhoto->getForm();
if ($request->getMethod() == 'POST') {
$form_photo->bind($request);
if ($form_photo->isValid()) {
// ...
}
}
return $this->render('MyBundle:frontend:photo.html.twig',
array('form_photo' => $form_photo->createView())
);
}
您现在知道要添加哪些“重要”功能才能上传照片并重命名吗?
如何检查扩展程序以查看是否可以上传?
使用Symfony2做这样的事情的实际方法是什么?我知道有很多Bundle会为你做所有这些事情,但我想学会这样做并理解这个过程。
使用Symfony2实现文件上传表单和重命名功能的“经典”方法是什么?
答案 0 :(得分:109)
您现在知道要添加哪些“重要”功能才能上传照片并重命名吗?
请参阅official documentation了解如何执行此操作。简单的文件上传有很好的工作示例。另请查看lifecycle callbacks的学说文档。
如何检查扩展程序以查看是否可以上传?
每个浏览器都有一些HTML表单验证。有关accept=""
元素中的HTML input
属性,请参阅this question。同样在Symfony2中,您可以使用此注释specify the MIME-type上传文件:
/**
* @Assert\File(
* maxSize = "1024k",
* mimeTypes = {"application/pdf", "application/x-pdf"},
* mimeTypesMessage = "Please upload a valid PDF"
* )
*/
即使您不想使用任何捆绑包,我也必须向您推荐KnpDoctrineBehavioursBundle,这样可以更轻松地上传文件。
因为您已经阅读了文档,所以我将逐步为您提供代码示例。
首先,你需要一个实体。我们称之为Image
:
/**
* Class Image
*
* @ORM\Entity()
* @ORM\HasLifecycleCallbacks
*/
class Image extends BaseEntity
{
注意@ORM\HasLifecycleCallbacks
注释。 非常重要,您稍后需要它。我们创建了所有基本字段,例如ID
,而不是。我们还需要一个字段来存储文件路径:
/**
* Image path
*
* @var string
*
* @ORM\Column(type="text", length=255, nullable=false)
*/
protected $path;
一个用于图像本身。在这里,我们还定义了图像的验证。在我的示例中,它必须是5M
大且定义为mimeTypes
之一。它应该是不言自明的。否则official docs会一如既往地提供帮助。
/**
* Image file
*
* @var File
*
* @Assert\File(
* maxSize = "5M",
* mimeTypes = {"image/jpeg", "image/gif", "image/png", "image/tiff"},
* maxSizeMessage = "The maxmimum allowed file size is 5MB.",
* mimeTypesMessage = "Only the filetypes image are allowed."
* )
*/
protected $file;
添加所有Getters & Setters
并使用以下命令更新数据库架构:
php app/console doctrine:schema:update --force
接下来我们需要生命周期。它们是Entity
中针对某些事件调用的方法。例如,方法之前的@ORM\PreUpdate()
注释表示在实体更新之前正在调用此方法。
/**
* Called before saving the entity
*
* @ORM\PrePersist()
* @ORM\PreUpdate()
*/
public function preUpload()
{
if (null !== $this->file) {
// do whatever you want to generate a unique name
$filename = sha1(uniqid(mt_rand(), true));
$this->path = $filename.'.'.$this->file->guessExtension();
}
}
在实体存储或更新之前,会调用此方法。您可以将其用于例如生成唯一的文件名。
/**
* Called before entity removal
*
* @ORM\PreRemove()
*/
public function removeUpload()
{
if ($file = $this->getAbsolutePath()) {
unlink($file);
}
}
在删除实体之前调用。这样您就有时间从文件夹中删除图像,或者根据需要记录消息。
/**
* Called after entity persistence
*
* @ORM\PostPersist()
* @ORM\PostUpdate()
*/
public function upload()
{
// The file property can be empty if the field is not required
if (null === $this->file) {
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->file->move(
$this->getUploadRootDir(),
$this->path
);
// Set the path property to the filename where you've saved the file
//$this->path = $this->file->getClientOriginalName();
// Clean up the file property as you won't need it anymore
$this->file = null;
}
这是将文件实际移动到正确目录的重要部分。请注意,我使用了一些其他方法。你们都可以从official docs获得它们。
您需要的下一件事是表格。表单类本身非常简单。只需确保您设置默认data_class
,如下所示:
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(
array(
'data_class' => 'FSchubert\SiyabongaBundle\Entity\Image',
)
);
}
可以使用buildForm()
方法轻松创建文件上传字段:
$builder->add('file', 'file');
Controller
的方法有点长,只是将它们粘贴在这里,恕我直言,这不是回答你问题的一部分。有无数的例子可以为你的目的写一个合适的Controller Action
。
你必须记住更多的事情:
app
个写入权限。虽然看起来很明显,如果你有多台服务器就可以运行应用程序。Image Constraint
。你可以找到它here。但是,由于您在谈论文件上传,我使用的是File Constraint
。DoctrineExtensionsBundle
更改为DoctrineBehaviours
,因为旧版本的开发已停止支持DoctrineBehaviours
捆绑。 答案 1 :(得分:13)
我建议您使用vlabs media bundle。
答案 2 :(得分:6)
VichUploaderBundle也很容易用于上传文件:
答案 3 :(得分:0)
我推荐 VichUploader 捆绑包和此代码,捆绑包植入实体和 FormType。
composer require vich/uploader-bundle
Admission.php
/**
* @ORM\Entity(repositoryClass=AdmissionRepository::class)
* @Vich\Uploadable
*/
class Admission
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=255)
*/
private $cin;
/**
* @Vich\UploadableField(mapping="product_image", fileNameProperty="cin")
* @var File
*/
private $cinFile;
public function getId(): ?int
{
return $this->id;
}
public function getCin(): ?string
{
return $this->cin;
}
public function setCin(string $cin): self
{
$this->cin = $cin;
return $this;
}
}
AdmissionType.php
class AdmissionType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('cinFile', VichFileType::class);
}
vich_uploader.yaml
vich_uploader:
db_driver: orm
mappings:
product_image:
uri_prefix: /uploads
upload_destination: '%kernel.project_dir%/public/uploads'
inject_on_load: false
delete_on_update: true
delete_on_remove: true
namer: vich_uploader.namer_origname