捆绑包如何提供;“默认数据”;i、 e.Symfony 2中的预填表格?

捆绑包如何提供;“默认数据”;i、 e.Symfony 2中的预填表格?,symfony,doctrine-orm,bundle,Symfony,Doctrine Orm,Bundle,我想我对Symfony和bundle的工作原理有很好的理解 然而,我从未发现如何解决一个简单的问题:制作一个可重用的捆绑包,提供数据,如预先填充(即)世界上所有国家名称、意大利所有省份、英国税率历史等的表格/条令实体 当然,其目的是提供依赖于此数据源的表单、服务和控制器,而无需跨项目复制和粘贴表和实体 你会怎么做 数据装置IMHO不是一个选项,因为一个明显的原因:您将在数据库运行时清除它 从静态数据源(json、YAML)读取并执行插入/更新的自定义命令?第一步是在包中声明一个条令实体。我认为您

我想我对Symfony和bundle的工作原理有很好的理解

然而,我从未发现如何解决一个简单的问题:制作一个可重用的捆绑包,提供数据,如预先填充(即)世界上所有国家名称、意大利所有省份、英国税率历史等的表格/条令实体

当然,其目的是提供依赖于此数据源的表单、服务和控制器,而无需跨项目复制和粘贴表和实体

你会怎么做

数据装置IMHO不是一个选项,因为一个明显的原因:您将在数据库运行时清除它


从静态数据源(json、YAML)读取并执行插入/更新的自定义命令?

第一步是在包中声明一个条令实体。我认为您应该创建DataFixture来将数据填充到db中

你也许应该考虑用种子代替固定装置。

fixture是假的数据,用于测试应用程序

种子是应用程序运行所需的最小数据

从技术上讲,这些都是完全相同的东西,您可以在“DataFixtures/”文件夹下声明它,然后使用“doctrine:fixtures:load”命令导入它们

您可以创建文件夹“Fixtures/”和文件夹“DataFixtures/”下的文件夹“Seeds/”,然后使用命令加载种子

php app/console doctrine:fixtures:load --fixtures=/path/to/seeds/folder --append

评论中建议,创建自定义Symfony2命令强制使用“-append”模式可能更安全,尤其是在生产环境中。如果没有此模式,您的数据库将被清除,您可能会丢失生产数据。

此答案假设您正在使用composer安装捆绑包(并且您确实排除了fixture作为选项)

您可以做的是对所需的数据进行SQL导出,并确保它使用INSERT IGNORE INTO,并获得正确的唯一约束

然后将该文件保存在包中的某个位置,即“数据”或“装置”文件夹中。 因此,该文件的路径如下所示: “供应商/company/epicbundle/data/countries.sql”

然后,您可以在composer.json中添加post insert和post update命令,如下所示:

"post-install-cmd": [
    "php app/console doctrine:query:sql \"$(cat vendor/company/epicbundle/data/countries.sql)\""
]
如果您只希望它在安装时运行,那么您只需要将它添加到那里,如果您有时更新sql文件,那么您还可以将它添加到更新后的cmd中

请注意,此解决方案仅在人们不处理表名的情况下有效,否则查询将失败


如果您想要一个更为保存/稳定的解决方案,您可以在使用实体管理器的Symfony中编写自己的安装后脚本,在那里您可以使用csv文件,并逐行插入/更新它。

基本上,您可以实现的任何东西都肯定依赖于ORM/ODM/任何东西中使用的持久性机制。因此,您将最终实现一个典型的夹具加载机制,至少是部分实现:您将执行保存一些提供的数据的代码;如果是序列化的,则需要执行XML/JSON/YAML解析(但这只是一个技术问题),并将结果持久化到数据库中

因此,坚持教条并不是坏事。它们是可编程和可扩展的(您甚至可以在加载时从web获取数据)

正如@paul andrieux的回答中所述,如果您担心数据丢失(例如,当最终用户的DB已经启动时,您的包的种子被加载),您应该使用
原则:fixtures:load--append
,并让约束完成它们的工作(例如,在国家名称表中,您对国家名称甚至“slug”有唯一的约束)因此,如果捆绑包已更新了国家/地区列表,并且最终用户具有以前的版本,则以静默方式插入重复行将无法插入单个实体

如果您确实担心最终用户的数据,您可以为
原则:fixtures:load
命令编写一个包装器,该命令将始终启用
--append
标志,并将其注册为单独的命令。(您也可以在那里运行所需的迁移)

@lxg的硬编码ID问题也是可以解决的。在适用的情况下尝试使用(例如,
countries
表将有一个
slug
主键,对于Grean britain,主键将是
great britain
)。这样您的搜索将非常简单:
$em->find('\MyBundle\Country',great britain')。如果您不能找到一个自然密钥,那么最终用户可能并不真正需要该实体


UPD。这里有一篇可能很有用的文章:

一般来说,捆绑包嵌入了将通过ORM/ODM使用其内置命令加载的实体(如
原则:schema:update
原则:migration:diff
,…),并提供了使用ODM/ORM加载所需装置的自定义命令

这个命令可以以多种方式读取装置(解析yaml、xml、原始sql、dql等等),这只是一个品味问题。包的音调,解析器。。。为这些任务而存在


在您的文档中,您只需清楚地声明,开发人员必须在捆绑包安装和架构更新后运行此命令。

如果您不喜欢仅因为清除数据库而使用此命令,则可以使用选项
--append
。正如doc所说:在加载数据之前,使用这个标志来追加数据,而不是删除数据(首先删除是默认行为)。这确实是一个好问题,我们的一个大型项目也有同样的问题。(我们只是提供了一个安装脚本,但这真的很难看)。最难看的是,我们需要将ID硬编码到代码中,以引用预填充的实体。非常期待这个问题的答案。@lxg--您熟悉Magento安装/升级脚本吗?它们提供了一个非常通用的解决方案(读作:“意味着重要的工作”)。在Magento安装/升级脚本中,您可以执行原始SQ