如何处理文件上传与教义
编辑该页面警告:你浏览的文档欧宝官网下载appob娱乐下载Symfony 2.4,不再维护。
读这个页面的更新版本Symfob娱乐下载ony 6.2(当前的稳定版本)。
如何处理文件上传与教义
处理文件上传与教义实体比其他任何文件上传处理没有什么不同。换句话说,你自由移动文件在你的控制器处理表单提交。如何做到这一点的例子,请参阅文件类型引用页面。
如果您选择,您也可以将文件上载到实体生命周期(即创建、更新和删除)。在这种情况下,作为实体创建、更新和删除从教义,文件上传和删除处理将自动(而不需要做任何事情在你的控制器)。
做这项工作,你需要照顾的细节,将在这个食谱条目。
基本设置
首先,创建一个简单的理论实体类工作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17日18 19 20 21日22日23日24日25日26日27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
/ / src / Acme / / Document.php DemoBundle /实体名称空间Acme\DemoBundle\实体;使用学说\ORM\映射作为ORM;使用ob娱乐下载\组件\验证器\约束作为断言;/ * * *@ORM实体\ * /类文档{/ * * *@ORM\ Id *@ORM\列(type =“整数”)*@ORM\ GeneratedValue(策略=“汽车”)* /公共美元id;/ * * *@ORM\列(类型=“字符串”,长度= 255)*@Assert\ NotBlank * /公共美元的名字;/ * * *@ORM\列(类型=“字符串”,长度= 255,可空= true) * /公共美元路径;公共函数getAbsolutePath(){返回零= = =美元这- >路径?零:美元这- >getUploadRootDir ()。' / '。美元这- >路径;}公共函数getWebPath(){返回零= = =美元这- >路径?零:美元这- >getUploadDir ()。' / '。美元这- >路径;}受保护的函数getUploadRootDir(){/ /上传的绝对目录路径/ /文件应该保存返回__DIR__。“/ . . / . . / . . / . . / web / '。美元这- >getUploadDir ();}受保护的函数getUploadDir(){/ /去掉__DIR__所以它不会搞砸了/ /当显示上传的文档/视图中的形象。返回'上传/文件;}}
的文档
实体有一个名称和它与文件相关联。的路径
属性存储相对文件路径和持久化到数据库中。的getAbsolutePath ()
是一种便利方法,返回文件的绝对路径,而getWebPath ()
是一种便利方法返回web路径,可以用于一个模板链接上传文件。
提示
如果你已经没有这么做,你应该阅读文件类型的文档欧宝官网下载app先理解基本的上传过程是如何工作的。
请注意
如果你使用注释来指定验证规则(如本例所示),确保您已经启用验证的注释(见验证配置)。
以处理实际的文件上传表单,使用一个“虚拟”文件
字段。例如,如果您正在构建表单直接在一个控制器,它看起来像这样:
1 2 3 4 5 6 7 8 9 10 11
公共函数uploadAction(){/ /……美元形式=美元这- >createFormBuilder (美元文档)- >add (“名字”)- >add (“文件”)- >getForm ();/ /……}
接下来,创建该属性上文档
类,并添加一些验证规则:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17日18 19 20 21日22日23日24日25日26日27 28 29 30
使用ob娱乐下载\组件\HttpFoundation\文件\UploadedFile;/ /……类文档{/ * * *@Assert\文件(最大容量= " 6000000 ")* /私人美元文件;/ * * *文件集。* *@paramUploadedFile文件* /美元公共函数setFile(UploadedFile美元文件= null){美元这- >文件=美元文件;}/ * * *得到文件。* *@returnUploadedFile * /公共函数getFile(){返回美元这- >文件;}}
1 2 3 4 5 6
# src / Acme / DemoBundle /资源/ config / validation.ymlAcme \ DemoBundle \实体\文档:属性:文件:- - - - - -文件:最大尺寸:6000000
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/ / src / Acme / / Document.php DemoBundle /实体名称空间Acme\DemoBundle\实体;/ /……使用ob娱乐下载\组件\验证器\约束作为断言;类文档{/ * * *@Assert\文件(最大容量= " 6000000 ")* /私人美元文件;/ /……}
1 2 3 4 5 6 7 8
< !- - - - - -- - - - - -src/Acme/DemoBundle/Resources/config/validation.yml -->< /span><类的名字=“Acme \ DemoBundle \实体\文件”><财产的名字=“文件”><约束的名字=“文件”><选项的名字=“最大容量”>6000000< /选项>< /约束>< /财产>< /类>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/ / src / Acme / / Document.php DemoBundle /实体名称空间Acme\DemoBundle\实体;/ /……使用ob娱乐下载\组件\验证器\映射\ClassMetadata;使用ob娱乐下载\组件\验证器\约束作为断言;类文档{/ /……公共静态函数loadValidatorMetadata(ClassMetadata美元元数据){美元元数据- >addPropertyConstraint (“文件”,新维护\文件(数组(最大容量的= >6000000)));}}
请注意
当你使用文件
约束,Symfony会自ob娱乐下载动猜输入表单字段是文件上传。这就是为什么你不必显式地设置它在创建上面的形式(- >添加(“文件”)
)。
下面的控制器显示了你如何处理整个过程:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17日18 19 20 21日22日23日24日25日26日27 28 29 30
/ /……使用Acme\DemoBundle\实体\文档;使用Sensio赞助\包\FrameworkExtraBundle\配置\模板;使用ob娱乐下载\组件\HttpFoundation\请求;/ /……/ * * *@Template()* /公共函数uploadAction(请求美元请求){美元文档=新文档();美元形式=美元这- >createFormBuilder (美元文档)- >add (“名字”)- >add (“文件”)- >getForm ();美元形式- >handleRequest (美元请求);如果(美元形式- >isValid ()) {美元新兴市场=美元这- >getDoctrine ()- >getManager ();美元新兴市场- >persist (美元文档);美元新兴市场- >冲洗();返回美元这- >重定向(美元这- >generateUrl (…));}返回数组(“形式”= >美元形式- >createView ());}
之前的控制器将自动保存文档
实体与提交的名字,但它将对文件和什么也不做路径
属性将空白。
一个简单的方法来处理文件上传之前将它移动的实体保存然后设置路径
相应的属性。通过调用一个新的开始上传()
方法文档
类,您将创建一个时刻处理文件上传:
1 2 3 4 5 6 7 8 9 10
如果(美元形式- >isValid ()) {美元新兴市场=美元这- >getDoctrine ()- >getManager ();美元文档- >上传();美元新兴市场- >persist (美元文档);美元新兴市场- >冲洗();返回美元这- >重定向(…);}
的上传()
方法将利用UploadedFile对象,该对象后返回文件
字段提交:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21日22日23日
公共函数上传(){/ /文件属性可以是空的,如果字段不是必需的如果(零= = =美元这- >getFile ()) {返回;}/ /在这里但是你应该使用原始文件名称/ /检查它至少避免任何安全问题/ /移动目标目录然后/ /移动到目标文件名美元这- >getFile ()- >移动(美元这- >getUploadRootDir (),美元这- >getFile ()- >getClientOriginalName ());/ /设置路径属性你保存的文件的文件名美元这- >路径=美元这- >getFile ()- >getClientOriginalName ();/ /文件清理你不需要它了美元这- >文件=零;}
使用生命周期回调
谨慎
使用生命周期回调技术有限,有一些缺陷。如果你想删除硬编码__DIR__
内部参考文档::getUploadRootDir ()
方法,最好的方法是开始使用显式的教义的听众。你将能够注入内核参数等kernel.root_dir
能够建立绝对路径。
即使这个实现的作品,它存在的主要缺陷:如果有一个问题,当实体保存吗?文件已经搬到其最终位置即使实体的路径
属性不正确地坚持。
为了避免这些问题,你应该改变实现数据库操作和文件的移动成为原子:如果有一个问题持久化实体或者文件无法移动,<新兴市场>没有什么新兴市场>应该发生的事情。
要做到这一点,你需要把文件正确的教义存在实体的数据库。这可以通过连接到一个实体生命周期回调:
1 2 3 4 5 6 7
/ * * *@ORM* \实体@ORM\ HasLifecycleCallbacks * /类文档{}
接下来,重构文档
类来利用这些回调函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17日18 19 20 21日22日23日24日25日26日27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
使用ob娱乐下载\组件\HttpFoundation\文件\UploadedFile;/ * * *@ORM* \实体@ORM\ HasLifecycleCallbacks * /类文档{私人美元临时;/ * * *文件集。* *@paramUploadedFile文件* /美元公共函数setFile(UploadedFile美元文件= null){美元这- >文件=美元文件;/ /检查是否我们有一个旧图片路径如果(收取(美元这- >路径)){/ /存储旧名称更新后删除美元这- >temp =美元这- >路径;美元这- >路径=零;}其他的{美元这- >路径=“初始”;}}/ * * *@ORM* \ PrePersist ()@ORM\ PreUpdate () * /公共函数preUpload(){如果(零= = !美元这- >getFile ()) {/ /生成一个唯一的名称做任何你想做的美元文件名函数= sha1 (mt_rand (),真正的));美元这- >路径=美元文件名。“。”。美元这- >getFile ()- >guessExtension ();}}/ * * *@ORM* \ PostPersist ()@ORM\ PostUpdate () * /公共函数上传(){如果(零= = =美元这- >getFile ()) {返回;}/ /如果有一个错误当移动文件时,将一个例外/ /自动抛出的移动()。这将适当的预防/ /实体被持久化到数据库错误美元这- >getFile ()- >移动(美元这- >getUploadRootDir (),美元这- >路径);/ /检查是否我们有一个老的形象如果(收取(美元这- >临时)){/ /删除旧的形象分离(美元这- >getUploadRootDir ()。' / '。美元这- >临时);/ /清除临时图片路径美元这- >temp =零;}美元这- >文件=零;}/ * * *@ORM\ PostRemove () * /公共函数removeUpload(){如果(美元文件=美元这- >getAbsolutePath ()) {unlink (美元文件);}}}
谨慎
如果改变你的实体学说事件监听器处理或事件订阅者preUpdate ()
调必须通知学说所做的更改。全部参考preUpdate事件限制,请参阅preUpdate在教义事件文档。欧宝官网下载app
类现在所有你需要:它生成一个独特文件名持久化之前,保存后的文件,删除文件如果实体是删除。
现在的移动文件自动处理的实体,调用$文档- >上传()
应该从控制器中删除:
1 2 3 4 5 6 7 8
如果(美元形式- >isValid ()) {美元新兴市场=美元这- >getDoctrine ()- >getManager ();美元新兴市场- >persist (美元文档);美元新兴市场- >冲洗();返回美元这- >重定向(…);}
请注意
的@ORM \ PrePersist ()
和@ORM \ PostPersist ()
事件触发回调之前和之后的实体被持久化到数据库中。另一方面,@ORM \ PreUpdate ()
和@ORM \ PostUpdate ()
事件回调函数被称为实体时更新。
谨慎
的PreUpdate
和PostUpdate
回调只是触发如果有变化在一个持久化实体的字段。这意味着,在默认情况下,如果你只修改美元的文件
财产,这些事件将不会触发,房地产本身并不直接持续通过教义。一个解决方案是使用一个更新
坚持的原则,并修改时手动更改文件。
使用id
作为文件名
如果你想使用id
实现文件的名称,略有不同,您需要保存下的扩展路径
财产,而不是实际的文件名:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17日18 19 20 21日22日23日24日25日26日27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
使用ob娱乐下载\组件\HttpFoundation\文件\UploadedFile;/ * * *@ORM* \实体@ORM\ HasLifecycleCallbacks * /类文档{私人美元临时;/ * * *文件集。* *@paramUploadedFile文件* /美元公共函数setFile(UploadedFile美元文件= null){美元这- >文件=美元文件;/ /检查是否我们有一个旧图片路径如果(is_file (美元这- >getAbsolutePath ())) {/ /存储旧名称更新后删除美元这- >temp =美元这- >getAbsolutePath ();}其他的{美元这- >路径=“初始”;}}/ * * *@ORM* \ PrePersist ()@ORM\ PreUpdate () * /公共函数preUpload(){如果(零= = !美元这- >getFile ()) {美元这- >路径=美元这- >getFile ()- >guessExtension ();}}/ * * *@ORM* \ PostPersist ()@ORM\ PostUpdate () * /公共函数上传(){如果(零= = =美元这- >getFile ()) {返回;}/ /检查是否我们有一个老的形象如果(收取(美元这- >临时)){/ /删除旧的形象分离(美元这- >临时);/ /清除临时图片路径美元这- >temp =零;}/ /必须抛出异常如果文件不能移动/ /这样的实体不是持久化到数据库中/ / UploadedFile移动()方法美元这- >getFile ()- >移动(美元这- >getUploadRootDir (),美元这- >id。“。”。美元这- >getFile ()- >guessExtension ());美元这- >setFile (零);}/ * * *@ORM\ PreRemove () * /公共函数storeFilenameForRemove(){美元这- >temp =美元这- >getAbsolutePath ();}/ * * *@ORM\ PostRemove () * /公共函数removeUpload(){如果(收取(美元这- >临时)){unlink (美元这- >临时);}}公共函数getAbsolutePath(){返回零= = =美元这- >路径?零:美元这- >getUploadRootDir ()。' / '。美元这- >id。“。”。美元这- >路径;}}
你会注意到在这种情况下,你需要做更多的工作以删除该文件。之前,你必须存储文件路径(因为它取决于id)。然后,一旦完全从数据库中删除对象,您可以安全地删除文件(PostRemove
)。