使用DoctrineORM和SonataAdmin上传和保存文档(包括图像)
编辑本页使用DoctrineORM和SonataAdmin上传和保存文档(包括图像)
这是一个使用SonataAdmin和DoctrineORM持久层的文件上传管理方法的完整工作示例。
的必备条件
- 您已经启动并运行了SonataAdmin和DoctrineORM
- 如果你已经有一个实体类,你希望能够连接上传的文档,在这个例子中,类将被调用
图像
. - 你已经设置了一个管理员,在这个例子中它被称为
ImageAdmin
- 您了解web服务器上的文件权限,并可以管理允许web服务器上传和更新相关文件夹中的文件所需的权限
菜谱
首先,我们将介绍您的实体需要包含哪些基本内容才能使用Doctrine进行文档管理。有一本很好的食谱用Doctrine和Symfony上传文件ob娱乐下载在Symfonob娱乐下载y网站上,所以我将在这里展示代码示例,而不深入细节。强烈建议你先读一下那本食谱。
要获得文件上传与SonataAdmin工作,我们需要:
- 添加文件上传字段到我们的ImageAdmin
- 当上传新文件时,“触摸”实体,从而触发其生命周期事件
基本配置-实体
按照Symfony烹饪书的指导方针,我们有一个实体定义,它看起来类似ob娱乐下载于下面的YAML(您也可以使用基于XML或Annotation的定义实现类似的功能)。在本例中,我们使用更新
字段通过基于上传时间戳设置来触发生命周期回调。
- YAML
12 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
# src /资源/ config /理论/ Image.orm.yaml应用实体\ \图片:类型:实体repositoryClass:应用\ \ ImageRepository实体\存储库表:图片id:id:类型:整数发电机:{策略:汽车}字段:文件名:类型:字符串长度:One hundred.#在文件上传时更改,以强制启动preUpdate和postUpdate更新:类型:datetime可以为空:真正的#……lifecycleCallbacks:prePersist:(“lifecycleFileUpload”)preUpdate:(“lifecycleFileUpload”)
然后,在我们的图像
类来管理文件上传:
12 34 56 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
/ / src /实体/ Image.php最后类图像{常量SERVER_PATH_TO_IMAGE_FOLDER =/服务器/路径/ /图片的;/** *处理文件上传的未映射属性*/私人UploadedFile ?$文件=零;公共函数setFile(?UploadedFile$文件= null):无效{$这->文件=$文件;}公共函数getFile(): ?UploadedFile{返回$这->文件;}/** *管理文件复制到服务器上的相关位置*/公共函数上传():无效{//如果不需要该字段,文件属性可以为空如果(零===$这->getFile ()) {返回;}//我们在这里使用原始文件名,但您应该//至少对其进行消毒以避免任何安全问题// move以目标目录和目标文件名作为参数$这->getFile ()->移动(自我::SERVER_PATH_TO_IMAGE_FOLDER,$这->getFile ()->getClientOriginalName ());//设置路径属性为你保存文件的文件名$这->文件名=$这->getFile ()->getClientOriginalName ();//清理文件属性,因为你不再需要它了$这->setFile (零);}/** *生命周期回调将文件上传到服务器。* /公共函数lifecycleFileUpload():无效{$这->上传();}/** *更新哈希值以强制触发preUpdate和postUpdate事件。* /公共函数refreshUpdated():无效{$这->setUpdated (新\ DateTime ());}/ /……类的其余部分位于这里,包括生成的字段//这样的文件名和更新}
当我们将一个文件上传到Image时,该文件本身是暂时的,并没有持久化到数据库中(它不是映射的一部分)。然而,生命周期回调会触发对图片::上传()
它管理上传文件到文件系统的实际复制,并更新文件名
属性的图像,这个filename字段是持久化到数据库。
以上大部分是来自用Doctrine和Symfony上传文件ob娱乐下载食谱条目。强烈推荐大家读一读!
基本配置- Admin类
我们需要在Sonata中做两件事来启用文件上传:
- 添加一个文件上传小部件
- 确保在上传文件时触发Image类的生命周期事件
当你知道该怎么做时,这两种方法都很简单:
12 34 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
/ / src / Admin / ImageAdmin.php使用ob娱乐下载\组件\形式\扩展\核心\类型\文件类型;最后类ImageAdmin扩展AbstractAdmin{受保护的函数configureFormFields(FormMapper$形式):无效{$形式->add (“文件”,文件类型::类,“要求”= >假]);}公共函数prePersist(对象$图像):无效{$这->manageFileUpload ($图像);}公共函数preUpdate(对象$图像):无效{$这->manageFileUpload ($图像);}私人函数manageFileUpload(对象$图像):无效{如果($图像->getFile ()) {$图像->refreshUpdated ();}}/ /……}
我们标记文件
字段不是必需的,因为我们不需要用户上传一个新的图像每次更新的图像。当上传文件时(表单上没有其他变化),Doctrine需要保存的数据没有变化,所以没有preUpdate
事件会发生。要处理这个问题,我们需要钩子到SonataAdmin的preUpdate
事件(在每次提交编辑表单时触发),并使用它来更新持久化的Image字段。这将确保Doctrine的生命周期事件被触发,并且我们的Image按照预期管理文件上传。
这就是它的全部!
但是,此方法不工作时ImageAdmin
已嵌入到使用sonata_type_admin
字段类型。为此,我们需要更多……
高级示例-与嵌入式管理员一起工作
当一个Admin嵌入到另一个Admin时,子Admin的preUpdate ()
方法在提交父对象时不会触发。为了解决这个问题,我们需要在需要时使用父Admin的生命周期事件来触发文件管理。
在这个例子中,我们有一个Page类,它定义了三个一对一的图像关系,从linkedImage1到linkedImage3。PostAdmin类的表单字段配置如下所示:
12 3 4 5 6 7 8 9 10 11 12 13 14 16 17 18 19 20 21
/ / src / Admin / PostAdmin.php使用奏鸣曲\AdminBundle\形式\类型\AdminType;最后类PostAdmin扩展AbstractAdmin{受保护的函数configureFormFields(FormMapper$形式):无效{$形式->add (“linkedImage1”, AdminType::类,“删除”= >假,)->add (“linkedImage2”, AdminType::类,“删除”= >假,)->add (“linkedImage3”, AdminType::类,“删除”= >假,]);}}
这就足够了——我们嵌入了三个字段,然后它们将使用我们的ImageAdmin
类来确定要显示哪些字段。
在我们的PostAdmin
然后我们有下面的代码来管理关系的生命周期:
12 34 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
/ / src / Admin / PostAdmin.php最后类PostAdmin扩展AbstractAdmin{公共函数prePersist(对象$页面):无效{$这->manageEmbeddedImageAdmins ($页面);}公共函数preUpdate(对象$页面):无效{$这->manageEmbeddedImageAdmins ($页面);}私人函数manageEmbeddedImageAdmins(对象$页面):无效{//循环每个字段foreach($这->getFormFieldDescriptions ()作为$字段名= >$fieldDescription) {//检测管理图像的嵌入式管理员如果($fieldDescription->方法()= = =“sonata_type_admin”& & ($associationMapping=$fieldDescription->getAssociationMapping & & ())$associationMapping[“targetEntity”) = = =“App \实体\形象”) {$getter=“得到”.$字段名;$setter=“设置”.$字段名;/**@varImage $ Image */$图像=$页面美元- - - >getter ();如果($图像) {如果($图像->getFile ()) {//更新镜像来触发文件管理$图像->refreshUpdated ();}elseif(!$图像->getFile() && !$图像->getFilename ()) {//阻止Sf/Sonata尝试创建和保存一个空的Image$页面美元- - - >setter (零);} } } } } }
在这里,我们循环遍历我们的PageAdmin的字段,并寻找那些是sonata_type_admin
字段中嵌入了管理映像的管理员。
一旦我们有了这些字段,我们就使用美元的字段名
构建引用我们的访问器和mutator方法的字符串。例如,我们可能会得到getlinkedImage1
在美元getter
.使用这个访问器,我们可以从PageAdmin管理的Page对象中获得实际的Image对象。检查这个对象会显示它是否有一个挂起的文件上传——如果有,我们会触发相同的文件上传refreshUpdated ()
方法。
最后的检查是为了防止出现Symfony试图在表单中没有输入任何内容时创建空白图像的故障。ob娱乐下载我们检测到这种情况并null关系以阻止这种情况发生。
请注意
如果您正在寻找更丰富的媒体管理功能,有一个完整的SonataMediaBundle
这就满足了这种需求。它是在线记录的,由与SonataAdmin相同的团队创建和维护。
要了解如何将图像预览添加到您的ImageAdmin
看看相关的烹饪书条目。