从DB生成Symfony2灯具?

时间:2011-06-11 20:33:46

标签: doctrine-orm fixtures symfony

是否可以从Symfony2 / Doctrine中的现有数据库生成灯具?我怎么能这样做?

示例:

我已经定义了15个实体,我的symfony2应用程序正在运行。现在有些人可以浏览到该应用程序,并且使用它已经插入了大约5000行,直到现在。现在我希望插入的东西作为固定装置,但我不想手工完成。如何从数据库中生成它们?

7 个答案:

答案 0 :(得分:8)

在Doctrine或Symfony2中没有直接的方式,但为它编写代码生成器(在sf2内部或外部)将是微不足道的。只需拉动每个属性并生成一行代码来设置每个属性,然后将其放入fixture装入方法中。例如:

<?php
$i = 0;
$entities = $em->getRepository('MyApp:Entity')->findAll();
foreach($entities as $entity)
{
   $code .= "$entity_{$i} = new MyApp\Entity();\n";
   $code .= "$entity_{$i}->setMyProperty('" . addslashes($entity->getMyProperty()); . "'); \n");
   $code .= "$manager->persist($entity_{$i}); \n $manager->flush();";
   ++$i;
}
// store code somewhere with file_put_contents

答案 1 :(得分:4)

据我了解你的问题,你有两个数据库:第一个已经在生产中并填充了5000行,第二个是你想用于新测试和开发的新数据库。是对的吗 ?

如果是,我建议你在测试环境中创建两个实体管理器:第一个将是'默认',它将在你的项目中使用(你的控制器等)。第二个将用于连接到您的生产数据库。您将在此处找到如何处理多个实体管理器:http://symfony.com/doc/current/cookbook/doctrine/multiple_entity_managers.html

然后,您应该创建一个可以访问容器的Fixture类。这里有一个“如何”:http://symfony.com/doc/current/bundles/DoctrineFixturesBundle/index.html#using-the-container-in-the-fixtures

使用容器,您将可以访问两个实体管理器。这就是'魔术':你必须从生产数据库中检索对象,并将它们保存在第二个实体管理器中,然后将它们插入到测试数据库中。

我将注意力集中在两点:

  • 如果对象之间存在关系,则必须注意这些依赖关系:所有者方,反方,......
  • 如果您有5000行,请注意脚本将使用的内存。另一种解决方案可能是使用本机sql从生产数据库中检索所有行并将它们插入测试数据库中。或者SQL脚本......

我没有任何代码可以向您推荐,但我希望这个想法可以帮到您。

答案 2 :(得分:3)

我假设你想要使用fixtures(而不仅仅是将生产或临时数据库转储到开发数据库中),因为a)你的架构发生了变化,如果更新你的代码,转储将无法工作,或者b)你没有想要转储空洞数据库,但只想扩展一些自定义夹具。我能想到的一个例子是:您的登台数据库中有206个国家,用户将城市添加到这些国家/地区;为了使灯具保持较小,您的开发数据库中只有5个国家/地区,但是您希望将用户添加到登台数据库中这5个国家/地区的城市添加到开发数据库

我能想到的唯一解决方案是使用上面提到的DoctrineFixturesBundle和多个实体管理器。

首先,您应该在config.yml

中配置两个数据库连接和两个实体管理器
doctrine:
    dbal:
        default_connection: default
        connections:
            default:
                driver:   %database_driver%
                host:     %database_host%
                port:     %database_port%
                dbname:   %database_name%
                user:     %database_user%
                password: %database_password%
                charset:  UTF8
            staging:
                ...

    orm:
        auto_generate_proxy_classes: %kernel.debug%
        default_entity_manager:   default
        entity_managers:
            default:
                connection:       default
                mappings:
                    AcmeDemoBundle: ~
            staging:
                connection:       staging
                mappings:
                    AcmeDemoBundle: ~

正如您所看到的,两个实体管理器都映射了AcmeDemoBundle(在此捆绑包中,我将放置代码来加载灯具)。如果第二个数据库不在您的开发计算机上,您可以将SQL从其他计算机转储到开发计算机。这应该是可能的,因为我们讨论的是500行而不是数百万行。

接下来你要做的是实现一个fixture装入器,它使用服务容器来检索第二个实体管理器,并使用Doctrine查询第二个数据库中的数据并将其保存到开发数据库中(default实体经理):

<?php

namespace Acme\DemoBundle\DataFixtures\ORM;

use Doctrine\Common\DataFixtures\FixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Acme\DemoBundle\Entity\City;
use Acme\DemoBundle\Entity\Country;

class LoadData implements FixtureInterface, ContainerAwareInterface
{
    private $container;
    private $stagingManager;

    public function setContainer(ContainerInterface $container = null)
    {
        $this->container = $container;
        $this->stagingManager = $this->container->get('doctrine')->getManager('staging');
    }

    public function load(ObjectManager $manager)
    {
        $this->loadCountry($manager, 'Austria');
        $this->loadCountry($manager, 'Germany');
        $this->loadCountry($manager, 'France');
        $this->loadCountry($manager, 'Spain');
        $this->loadCountry($manager, 'Great Britain');
        $manager->flush();
    }

    protected function loadCountry(ObjectManager $manager, $countryName)
    {
        $country = new Country($countryName);
        $cities = $this->stagingManager->createQueryBuilder()
            ->select('c')
            ->from('AcmeDemoBundle:City', 'c')
            ->leftJoin('c.country', 'co')
            ->where('co.name = :country')
            ->setParameter('country', $countryName)
            ->getQuery()
            ->getResult();
        foreach ($cities as $city) {
            $city->setCountry($country);
            $manager->persist($city);
        }
        $manager->persist($country);
    }
}

我在loadCountry方法中所做的是我从staging实体管理器加载对象,添加对夹具国家(当前灯具中已存在的那个)的引用并保持不变它使用default实体管理器(您的开发数据库)。

<强>来源:

答案 3 :(得分:1)

您可以使用https://github.com/Webonaute/DoctrineFixturesGeneratorBundle 它增加了使用

等命令为单个实体生成灯具的功能
$ php bin/console doctrine:generate:fixture --entity=Blog:BlogPost --ids="12 534 124" --name="bug43" --order="1"

或者您可以创建完整快照

php app/console doctrine:generate:fixture --snapshot --overwrite

答案 4 :(得分:0)

Doctrine Fixtures很有用,因为它们允许您创建对象并将它们插入到数据库中。当您需要创建关联或者说使用其中一个密码编码器对密码进行编码时,这尤其有用。如果您已经拥有数据库中的数据,那么您实际上不需要将它们从该格式中取出并将其转换为PHP代码,只是让PHP代码将相同的数据插回到数据库中。您可能只是执行SQL转储,然后以这种方式再次将它们重新插入到数据库中。

如果您正在启动项目但希望使用用户输入来创建它,那么使用fixture会更有意义。如果您的配置文件中有默认用户,则可以读取该文件并插入该对象。

答案 5 :(得分:0)

AliceBundle可以帮助您这样做。实际上,它允许使用YAML(或PHP数组)文件加载灯具。

例如,您可以使用以下内容定义灯具:

Nelmio\Entity\Group:
    group1:
        name: Admins
        owner: '@user1->id'

或者在PHP数组中使用相同的结构。它比生成有效的PHP代码更容易。

它还支持引用:

Nelmio\Entity\User:
    # ...

Nelmio\Entity\Group:
    group1:
        name: Admins
        owner: '@user1'

答案 6 :(得分:-2)

在doctrine_fixture cookbook中,您可以在上一个示例中看到如何获取实体中的服务容器。

使用此服务容器,您可以检索doctrine服务,然后检索实体管理器。使用实体管理器,您将能够从您所需的数据库中获取所有数据。

希望这会对你有帮助!