limetecbiotechnologies/yaml-fixtures-bundle

用于简化基于 YAML 的 fixtures 加载的 Symfony 包。

v2.0.3 2022-06-13 09:34 UTC

README

此包为您提供了使用基于 YAML 的 fixtures 为 Symfony2 和 Doctrine2 的方法。目前它与 Doctrine ORM 或 Doctrine MongoDB ODM 一起工作。其他后端尚未实现,但可以非常容易地实现。

Travic CI 状态: 构建状态 Scrutinizer CI: Scrutinizer 代码质量

安装

此包依赖于 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.ymlconfig_dev.yml(推荐)中添加以下内容

khepin_yaml_fixtures:
    resources:
        - MyOtherBundle/load_this_first
        - MyBundle
        - MyOtherBundle

在 'resources' 下是一个包含您希望加载 fixtures 的包的列表。fixtures 将按此顺序加载。

MyOtherBundle/load_this_first 语法表示 load_this_first.yml 将在当前包中的其他文件之前加载。这允许为加载 fixture 文件设置任何特定的顺序。

定义您的 fixture 文件

设置

请注意,与 Symfony 1.x 不同,加载 fixtures 的顺序是重要的。有两种方法可以操作此顺序

  • 通过 config.yml:指定哪些包的 fixtures 首先加载
  • 通过文件名:每个包内部按字母顺序加载 fixture 文件

默认情况下,fixture 文件使用包层次结构:MyBundle/DataFixtures/somefixtures.yml

如果您想更改使用的层次结构 fixtures,请在配置中指定它

khepin_yaml_fixtures:
    directory: Resources/fixtures

这将导致您的 fixture 文件使用包层次结构:MyBundle/Resources/fixtures/somefixtures.yml

定义

您只能在每个文件中定义一个类的 fixtures。在顶级配置 fixture 文件,并在 fixtures 键内定义。您可以通过在 fixtures 数组中提供名称来为稍后引用的 fixture 命名。

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"

您可以通过提供名称来使用对先前创建的 fixtures 的引用

model: Name\Space\MyBundle\Entity\Car
fixtures:
    audi_a3:
        owner: michael
        since: "2010-12-12"

对于 MongoDB 的 reference many,在相应的键下包含您的引用列表

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', ...);

关于上下文

有时在设置测试用例时,需要不同的配置。这正是上下文旨在解决的问题。

上下文等同于在固定文件下的tag键中设置的标签。您可以在固定文件上设置任意数量的标签。例如prodtest等...

如果您以这种方式定义固定值,那么从命令行调用

php app/console khepin:yamlfixtures:load prod

将加载您设置的任何固定值文件。

tags: [ ..., prod, ... ]

这样,您可以定义在测试或开发环境中加载的固定值,但在例如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)

如果您需要在您的固定数据上设置ACL条目,这是可能的。ACL是在所有固定数据保存之后创建的,以确保没有可能的冲突。

要为固定数据设置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管理的,因此当您重新创建固定数据时,它们不会被清除。然而,如果有任何冲突,加载ACL将覆盖所有之前的ACL条目。