2

私はエンティティを持っています(以下のような)。作成中にいくつかのデフォルト値を設定したい。でわかるように、 (文字列)__constructを設定するのは簡単ですが、? を設定するにはどうすればよいですか? (たとえば、データベースにグループがあることを知っています)$name$groupid=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または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/リポジトリ/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 Entity Manager のみに依存して、デフォルトのグループの関連付けを維持できます。

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

このアプローチを Symfony で拡張して、doctrine エンティティ リポジトリの代わりにクエリ サービスを使用し、エンティティのインスタンス化を処理する中央の場所を提供できます。

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ます。


もう 1 つの方法は、エンティティでライフサイクル コールバックを使用するか、イベント リスナーを使用してより複雑な機能を実行することです。ただし、これにより、エンティティが永続化されるまで無効な状態でインスタンス化されます。

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 に答える