khepin / yaml-fixtures-bundle
Symfony 扩展包,用于轻松加载基于 YAML 的数据固定文件。
Requires
Requires (Dev)
- doctrine/mongodb: 1.*
- doctrine/mongodb-odm: 1.*
- doctrine/mongodb-odm-bundle: 3.*
- mockery/mockery: 0.9.*
- phpunit/phpunit: 5.*
README
此扩展包为您提供了使用基于 YAML 的数据固定文件的方式,适用于 Symfony2 和 Doctrine2。它目前与 Doctrine ORM 或 Doctrine MongoDB ODM 一起工作。其他后端尚未实现,但可以很容易地实现。
安装
此扩展包依赖于 DoctrineFixturesBundle。如果您还没有用 Symfony2 配置它,请遵循设置说明。
通过 Composer,添加到 composer.json
"require": {
"khepin/yaml-fixtures-bundle": "~1.0.1"
}
然后在 AppKernel.php
中注册扩展包,最好只在开发环境中注册,因为它在其他地方可能不需要。
public function registerBundles()
{
if (in_array($this->getEnvironment(), array('dev', 'test'))) {
//...
$bundles[] = new Khepin\YamlFixturesBundle\KhepinYamlFixturesBundle();
//...
}
}
配置
在您的 config.yml
或 config_dev.yml
(推荐)中添加以下内容
khepin_yaml_fixtures:
resources:
- MyOtherBundle/load_this_first
- MyBundle
- MyOtherBundle
在 'resources' 下是一个您想要加载固定文件的扩展包列表。固定文件将按此顺序加载。
MyOtherBundle/load_this_first
语法意味着 load_this_first.yml
将在当前包中的其他文件之前加载。这允许为加载固定文件设置任何特定的顺序。
定义您的固定文件
设置
请注意,与 Symfony 1.x 不同,您加载固定文件的顺序很重要。您可以通过以下两种方式来操纵这个顺序
- 通过
config.yml
:指定哪些扩展包的固定文件首先加载 - 通过文件名:固定文件在每个扩展包内部按字母顺序加载
默认情况下,固定文件使用扩展包层次结构:MyBundle/DataFixtures/somefixtures.yml
。
如果您想更改使用的层次结构固定文件,请在配置中指定它
khepin_yaml_fixtures:
directory: Resources/fixtures
这将导致您的固定文件使用扩展包层次结构:MyBundle/Resources/fixtures/somefixtures.yml
。
定义
您只能在文件中定义一个类的固定文件。固定文件在顶级进行配置,并在 fixtures
键内定义。您可以通过在 fixtures
数组中提供名称来为固定文件命名,以便稍后引用。
model: Name\Space\MyBundle\Entity\User
tags: [ test, dev, prod ] # optional parameter
save_in_reverse: false # optional parameter
persistence: orm (default)| mongodb # lets you choose if these fixtures should be saved through the orm or through mongodb.
fixtures:
michael:
name: Michael
phonenumber: 8765658
birthday: "1989-12-12"
您可以通过提供名称来使用对先前创建的固定文件的引用
model: Name\Space\MyBundle\Entity\Car
fixtures:
audi_a3:
owner: michael
since: "2010-12-12"
对于MongoDB的参考多,将您的引用作为列表放在相应的键下
model: Name\Space\Bundle\Document\Car
persistence: mongodb
fixtures:
audi_a3:
owners:
- michael
- paul
- angella
您可以为同一实体定义尽可能多的文件。当与上下文标签(见下文)一起使用时,这会非常有用。
##处理日期和时间
日期需要在引号内设置。日期传递给DateTime,所以任何可以与DateTime一起工作的字符串都可以在这里使用。这包括相对格式,如"-1天"、"下个月"、"1周前"。
model: Name\Space\MyBundle\Entity\Statistics
fixtures:
stat-1:
product: example.org
date: "2010-12-12" #dates NEED to be set inside quotes
Mongo嵌入式文档
在Mongo中可以使用嵌入式文档(目前只实现了embed_one)。只需像这样连续地保持yaml文件
model: Name\Space\Bundle\Document\Article
persistence: mongodb
fixtures:
first_post:
title: Ouelkom to my niew blog!
content: I will update regularly!
author: # This defines an embedded document
name: khepin # this will be set on the embedded document
用法
从命令行
php app/console khepin:yamlfixtures:load <context>
关于上下文的更多内容将在以后介绍,除非你有理由,否则不需要添加上下文。
注意:目前命令行一次只能加载一个上下文。
从其他任何地方
如果您需要从其他地方加载固定数据,比如...您的功能测试,以便为测试设置一个干净的数据库,您可以通过服务容器访问相同的内容,并且具有能够一起加载多个上下文的优势
$container->get('khepin.yaml_loader')->loadFixtures('prod', 'test', ...);
关于上下文
有时在设置测试用例的固定数据时,您需要不同的配置。这就是上下文旨在解决的问题。
上下文等同于在固定文件下设置在标签键中的标签。您可以在固定文件上设置尽可能多的标签。例如prod
、test
等...
如果您以这种方式定义固定数据,那么从命令行调用
php app/console khepin:yamlfixtures:load prod
将加载您设置的任何固定数据文件
tags: [ ..., prod, ... ]
这样,您可以定义在您使用测试或开发环境时加载的固定数据,但在例如生产环境中不加载。
没有任何标签的固定数据文件总是加载!这样,您可以在完全没有标签的文件中设置引导固定数据,然后为每个目的设置特定的固定数据。
那么这个“save_in_reverse”是什么东西?
这个参数通常可以省略。它目前只有在您有一个自引用表时才有用。例如,如果您有像这样的固定数据
fixtures:
last_level:
next_level: none
name: Meet the boss
middle_level:
next_level: last_level
name: complete the quest
start_level:
next_level: middle_level
name: introduction
在这种情况下,我们需要在我们的固定数据中将last_level
放在第一位,因为它是唯一一个没有引用其他任何东西的。我们无法首先创建start_level
,因为它需要middle_level
已经存在等...
问题是,当清除数据库时,ORMPurger()按id顺序逐行遍历。所以如果我们按这个顺序保存它们,last_level
应该是第一个被移除的,这将因为它仍然被middle_level
引用而导致外键问题。
以反向顺序保存将按此顺序创建对象,以便正确设置引用,然后以相反的顺序保存它们,这样在清除数据库时就没有异常。
处理 ORM 一对多或多对多关联
如果您想将已创建的对象数组传递给 *-To-Many 关联,您可以通过首先允许对象的 setter 接受一个简单的 PHP 数组(而不是仅接受 Doctrine\Common\ArrayCollection)来实现,然后按照以下方式定义您的 YAML 文件
fixtures:
car:
name: foo_bar
parts:
- part_one
- part_two
- part_three
当然,这假设 part_one、part_two 和 part_three 是您在先前加载的文件中已定义的对象。
YAML 加载器将创建一个包含三个对象的简单 PHP 数组,并将其传递给您在此文件中定义的模型上的 setParts() 方法。
构造函数
如果您想向构造函数传递参数
fixtures:
car:
__construct:
- Ford
- {type: reference , value: owner_ford}
- {type: datetime, value: "2012-01-01"}
class Car { /** * @param string $name * @param Owner $owner * @param DateTime $purchaseDate */ public function __construct($name, Owner $owner, \DateTime $purchaseDate, ) { ... } }
服务调用
某些实体在持久化之前需要由特殊服务进行管理。例如,FOSUserBundle 就是这样,正确的密码是由 user_manager
设置的,而不是直接在用户类中设置。因此,我们需要请求此服务在我们将域对象设置为正确状态之前将其持久化。服务调用声明如下
model: My\NameSpace\User
service_calls:
service_1:
service: fos_user.user_manager # this is the service id in the container
method: updateUser # the method to be called on the object
fixtures:
dad:
name: Francois
plain_password: thisismypassword
现在,对于每个用户,在它被持久化之前,将发生类似于以下代码的操作
$container->get('fos_user.user_manager')->updateUser($user_francois);
使用 ACL
如果您需要在您的 fixtures 上设置 ACL 条目,这是可能的。ACL 是在所有 fixtures 已保存之后创建的,以确保没有可能的冲突。
要为 fixtures 设置 ACL,您需要使用 ProblematicAclManagerBundle。
并按照以下方式更新您的配置
khepin_yaml_fixtures:
acl_manager: ~
resources:
- MyBundle
- MyOtherBundle
ACL 只能使用 Symfony MaskBuilder 中定义的标准掩码。示例
model: My\NameSpace\Car
tags: [ test ]
fixtures:
dad_car:
name: Mercedes
mom_car:
name: Mini Cooper
acl:
dad_car:
user_dad: MASK_OWNER
user_mom: MASK_MASTER
mom_car:
user_mom: MASK_OWNER
请注意,Symfony 中的 ACL 不是通过 Doctrine 管理的,因此重新创建 fixtures 时不会清除。但是,如果有冲突,加载 ACL 将覆盖所有先前的 ACL 条目。