本文概述
- 1.使用FileType配置FormType
- 2.创建和配置FileUploader服务
- 3.创建和配置Doctrine Listener
【如何在Symfony 3.3中为单个字段(文档实体)配置文件上传器】我们将在Symfony的官方文章中以” 小册子” 字段和” 产品” 实体的相同示例制作教程。
1.使用FileType配置FormType你需要做的第一件事是使用FileType定义用于上传文件的表单字段:
注意将字段的data_class属性设置为null很重要, 否则你将面临一个异常, 即:
表单的视图数据应该是Symfony \ Component \ HttpFoundation \ File \ File类的实例, 但是是一个(n)字符串。
当你尝试使用表单更新你的实体时。
<
?php// src/AppBundle/Form/ProductType.phpnamespace AppBundle\Form;
use AppBundle\Entity\Product;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\FileType;
class ProductType extends AbstractType{public function buildForm(FormBuilderInterface $builder, array $options){$builder// ...->
add('brochure', FileType::class, array('label' =>
'Brochure (PDF file)', 'data_class' =>
null, 'required' =>
false))// ...;
}public function configureOptions(OptionsResolver $resolver){$resolver->
setDefaults(array('data_class' =>
Product::class, ));
}}
2.创建和配置FileUploader服务配置FileUploader类的第一步是定义一个全局参数, 该参数指定将在何处上传小册子文件。在这种情况下, 我们将在Web中创建两个文件夹, 即上载和内部上载的小册子文件夹, 其中将存储上载的文件。你可以在应用程序的config.yml文件中定义此参数:
# app/config/config.ymlparameters:brochure_files_directory: '%kernel.project_dir%/web/uploads/brochures'
我们将需要Brochure_files_directory参数将其注入到接下来将要创建的FileUploader服务中。使用下面的代码创建类FileUploader:
<
?php// src/AppBundle/Service/FileUploader.phpnamespace AppBundle\Service;
use Symfony\Component\HttpFoundation\File\UploadedFile;
class FileUploader{private $targetDir;
public function __construct($targetDir){$this->
targetDir = $targetDir;
}public function upload(UploadedFile $file){$fileName = md5(uniqid()).'.'.$file->
guessExtension();
$file->
move($this->
getTargetDir(), $fileName);
return $fileName;
}public function getTargetDir(){return $this->
targetDir;
}}
作为一个标准, 我们在捆绑包中创建了Service文件夹, 因此名称间隔不仅易于理解, 而且对我们的应用程序而言是易于理解的。无需修改代码, 因为它实现了一个非常基本的文件上传器, 该文件上传器将Providen文件移动到所需路径中, 并在一行代码中生成一个随机名称。该文件存在后, 你需要在Symfony项目的services.yml文件中注册它:
# app/config/services.ymlservices:AppBundle\Service\FileUploader:arguments:$targetDir: '%brochure_files_directory%'
请注意, 我们将创建的参数Brochure_files_directory复制为$ targetDir参数的值。侦听器将使用此FileUploader类轻松地操作文件。
3.创建和配置Doctrine Listener如官方教程中所述, 为了防止控制器中有多余的代码来处理文件上传, 你可以创建Doctrine侦听器以在持久保存实体时自动上传文件。在此示例中, 我们在AppBundle中创建了EventListener文件夹, 该文件夹将放置我们的上载侦听器类。侦听器的代码遵循以下逻辑:
注意必须根据你的实体的字段来修改此代码。这意味着你可以自己更改宣传册的获取者和安装者。
<
?php// src/AppBundle/EventListener/BrochureUploadListener.phpnamespace AppBundle\EventListener;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\Event\PreUpdateEventArgs;
// Include Product class and our file uploaderuse AppBundle\Entity\Product;
use AppBundle\Service\FileUploader;
class BrochureUploadListener{private $uploader;
private $fileName;
public function __construct(FileUploader $uploader){$this->
uploader = $uploader;
}public function prePersist(LifecycleEventArgs $args){$entity = $args->
getEntity();
$this->
uploadFile($entity);
}public function preUpdate(PreUpdateEventArgs $args){// Retrieve Form as Entity$entity = $args->
getEntity();
// This logic only works for Product entitiesif (!$entity instanceof Product) {return;
}// Check which fields were changes$changes = $args->
getEntityChangeSet();
// Declare a variable that will contain the name of the previous file, if exists.$previousFilename = null;
// Verify if the brochure field was changedif(array_key_exists("brochure", $changes)){// Update previous file name$previousFilename = $changes["brochure"][0];
}// If no new brochure file was uploadedif(is_null($entity->
getBrochure())){// Let original filename in the entity$entity->
setBrochure($previousFilename);
// If a new brochure was uploaded in the form}else{// If some previous file existif(!is_null($previousFilename)){$pathPreviousFile = $this->
uploader->
getTargetDir(). "/". $previousFilename;
// Remove itif(file_exists($pathPreviousFile)){unlink($pathPreviousFile);
}}// Upload new file$this->
uploadFile($entity);
}}private function uploadFile($entity){// upload only works for Product entitiesif (!$entity instanceof Product) {return;
}$file = $entity->
getBrochure();
// only upload new filesif ($file instanceof UploadedFile) {$fileName = $this->
uploader->
upload($file);
$entity->
setBrochure($fileName);
}}}
当用户为产品创建新的注册(访问表单以创建新产品)时, 该表单允许他在小册子字段中上传文件。如果是Providen, 则将使用随机文件名(名称存储在小册子字段中的数据库中的名称)自动保存在/ uploads / brochures目录中, 如果没有上载任何文件, 则该字段为null。当用户编辑产品时, 如果某人已经上传了小册子文件, 并且用户在不上传新文件的情况下更新了产品, 则旧文件将被保留并且什么也不会发生, 但是如果用户上传新文件, 则旧的将被删除, 新的将被存储(也更新手册字段)。
最后, 你需要在项目的services.yml文件中注册该理论侦听器:
# app/config/services.ymlservices: AppBundle\EventListener\BrochureUploadListener:tags:- { name: doctrine.event_listener, event: prePersist }- { name: doctrine.event_listener, event: preUpdate }
保存更改, 清除缓存并测试你的表单。
编码愉快!
推荐阅读
- 当活动不在前面时,在Android中暂停CountDownTimer
- 如何在Symfony 3中使用纯PHP编译SASS(scss)
- 如何使用MySQL Workbench将MS SQL Server数据库(从SQL Server Management Studio)迁移到MySQL
- 如何在Winforms中为单个键注册单个或多个全局热键
- 什么是PHP Year 2038(Y2K38)错误以及如何解决它
- 如何从PHP中的2个值计算百分比变化(增加和减少)
- 在Symfony 3中将Bootstrap 4分页控制布局与KnpPaginatorBundle一起使用
- 如何在Symfony 3中使用PHP将PDF转换为图像
- 如何使用BeSimpleI18nRoutingBundle在Symfony 3中处理路由国际化