2

我有实体(如下所示)。我想在创建时设置一些默认值。正如您在 中看到的__construct,设置(字符串)很容易$name,但是如何设置$group?(例如我知道数据库中有一个组id=122

/**
 * @ORM\Entity
 */
class Person {
    private $id;

    /** @ORM\Column(type="string") */
    private $name;

    /**
     * @ORM\ManyToOne(targetEntity="Group", inversedBy="persons")
     * @ORM\JoinColumn(referencedColumnName="id")
     */
    private $group;

    public function setGroup(Group $group)
    {
        $this->group = $group;
        $group->addPerson($this);
    }

    // ... setters/getters

    //construct default Person
    public function __construct()
    {
        $this->setName("Mike");
        $this->setGroup($EXISTING_GROUP_FROM_MY_DB); // <<--------------
    }
}
4

2 回答 2

4

我同意moonwave99 认为这是糟糕的设计。在这里,您尝试从不支持容器的地方(即它不知道也不应该知道 Doctrine)访问数据库(通过 Doctrine 服务)。

我最近有一个类似的问题......实际上几乎完全相同的问题。但我不希望这个逻辑出现在控制器内部。所以我写了一个服务来处理用户的创建。我让该服务可以访问它唯一需要的其他服务:Doctrine。

这是一个示例,其中创建了具有所有可用角色的用户:

namespace MyBundle\Entity;

class UserFactory
{
    private $doctrine;

    public function __construct($doctrine)
    {
        $this->doctrine = $doctrine;
    }

    public function generateNewUser($email, $password)
    {
        $user = new User();

        // Since you have access to the Doctrine service, you can use $this->doctrine
        // to do anything you would normally do in your controller with $this->getDoctrine()
        $roles = $this->doctrine->getEntityManager()->getRepository("MyBundle:Role")->findAll();

        foreach ($roles as $role)
        {
            $user->addRole($role);
        }

        return $user;
    }
}

config.yml现在在or中注册该服务services.yml,记住将 Doctrine 服务传递给它:

services:
    mybundle.factory.user:
        class: MyBundle\Entity\UserFactory
        arguments: ['@doctrine']

就是这样......现在,在您的控制器中,您可以通过执行以下操作创建一个新用户:

public function MyController()
{
    $user = $this->get("mybundle.factory.user")->generateNewUser("someone@email.com", "password123");
}
于 2012-12-12T16:23:47.913 回答
2

推荐的方法是要求构造函数参数中的关联实体对象,可选地与工厂(例如实体存储库)结合,以Group在实例化期间提供实体。这可确保实体始终处于有效状态。

src/Entity/Person.php

namespace App\Entity;

/**
 * @ORM\Entity(repositoryClass="App\Repository\PersonRepository")
 */
class Person 
{
   //...

    public function __construct($name, Group $group)
    {
         $this->setName($name);
         $this->setGroup($group);
    }

    //...
}

src/Repsotory/PersonRepository.php

namespace App\Repsotory;

use App\Entity\Group;
use App\Entity\Person;

class PersonRepository
{
    const DEFAULT_GROUP = 122;

    public function create($name, Group $group = null)
    {
        if (null === $group) {
            $group = $this->_em->getReference(Group::class, self::DEFAULT_GROUP);
        }
        $person = new Person($name, $group);
        $this->_em->persist($person);
 
        return $person;
    }
}

这允许您仅依靠 Doctrine ORM 实体管理器来维护默认的组关联。

$person = $em->getRepository(Person::class)->create('Mike');
$group = $person->getGroup();
echo $group->getId(); //outputs: 122
$em->flush();

这种方法可以在 Symfony 中扩展以使用查询服务而不是理论实体存储库,以提供处理实体实例化的中心位置。

在 Symfony 3.4+ 中,您可以使用存储库服务 为存储库提供依赖注入,而不是使用EntityManagerInterface.

src/Service/PersonCreateQuery.php

namespace App\Service;

use App\Entity\Group;
use App\Entity\Person;
use Doctrine\ORM\EntityManagerInterface;

class PersonCreateQuery
{
    private $em;

    public function __construct(EntityManagerInterface $em)
    {
        $this->em = $em;
    }

    public function __invoke($name)
    {
        $group = $this->em->getReference(Group::class, 122);
        $person = new Person($name, $group);
        $this->em->persist($person);

        return $person;
    }
}

现在您可以使用依赖注入来检索查询服务并根据需要使用它,例如使用 Symfony 表单或控制器。

namespace App\Controller;

use App\Service\PersonCreateQuery;

class PersonController
{
    public function createAction(PersonCreateQuery $query)
    {
        $person = $query('Mike');
        $this->getDoctrine()->getManager()->flush();

        //...
    } 
}

注意: 的用法$em->getReference()可以替换为$em->find()。using$em->getReference()将阻止对数据库的查询,但如果引用无效,则会抛出异常,而 using$em->find()将返回null


另一种方法是使用实​​体中的生命周期回调或事件侦听器来执行更复杂的功能。但是,这将导致您的实体被实例化为无效状态,直到它被持久化。

use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\HasLifecycleCallbacks
 */
class Person 
{
     const DEFAULT_GROUP = 122;

     /** @ORM\Column(type="string") */
     private $name = 'Mike';

    /**
     * @ORM\ManyToOne(targetEntity="Group", inversedBy="persons")
     * @ORM\JoinColumn(referencedColumnName="id")
     */
    private $group;

    //....

    public function setGroup(Group $group)
    {
        $this->group = $group;
        $group->addPerson($this);
    }

    /**
     * @param LifecycleEventArgs $event
     * @ORM\PrePersist
     */
    public function onPrePersist(LifecycleEventArgs $event)
    {
       if (!$this->group instanceof Group) {
           /** set default group if not specified */
           $group = $event->getEntityManager()->getReference(Group::class,  self::DEFAULT_GROUP);
           $this->setGroup($group);
       }
    }

}

现在,当您持久化一个 Person 实体时,如果它没有在其他地方显式设置,它将添加该组。

$person = new Person();
$person->setName('Foo Bar');
$em->persist($person); //persist or do nothing if already persisted

$group = $person->getGroup();
echo $group->getId(); //outputs: 122

$groupPerson = $group->getPerson();
echo $groupPerson->getName(); //outputs: Foo Bar
$em->flush(); //save to database

为了理智,这里是教义事件文档的链接:

于 2015-12-14T03:01:51.567 回答