12

クラステーブル継承を使用して、Doctrine2でエンティティタイプを(可能であれば)どのように変更しますか?

Person親クラスタイプと2つの継承タイプEmployeとがありますClientPerson私のシステムでは、Personを作成し、そのタイプを指定できます(実装はかなり簡単です)が、レベル情報(IDおよびその他の関連情報)を維持しながら、PersonをEmployeからClientに変更できるようにしたいと思います。記録)。

Doctrine2でこれを行う簡単な方法はありますか?

4

4 に答える 4

7

私は昨日もこの行動を探していました。

結局、freenodeの#doctrineの人たちと話をしたところ、それは不可能だと言われました。

これを実行したい場合は、これを実行する必要があります。

ユーザーのアップグレード

  1. Personエンティティを取得します。
  2. Discrimator列を更新して、「person」ではなくなり、「employee」に変更します。
  3. Employeeこの継承に対応する行をテーブルに作成します。

継承の削除

同様に、継承を削除したい場合は、削除する必要があります。

  1. Personエンティティを取得します。
  2. Discrimnator列を更新して、「従業員」ではなくなり、「人」に変更します。
  3. テーブルの対応する行を削除しますEmployee。(はい、削除する必要があります。ディスクリミエーターの数を変更するだけでは不十分です)。

これは7か月遅れる可能性がありますが、このような機能をサポートしようとしている他の人にとっては、少なくとも正しい答えです。

于 2011-09-02T11:54:05.707 に答える
4

PHPはオブジェクトキャストをサポートしていないため、Doctrineはそれをサポートしていません。この問題を回避するために、この静的メソッドを親クラスに記述します。

public static function castToMe($obj) {

    $class = get_called_class();
    $newObj = New $class();

    foreach (get_class_vars(get_class($newObj)) as $property => $value) {
        if (method_exists($obj, 'get' . ucfirst($property)) && method_exists($newObj, 'set' . ucfirst($property))) {
            $newObj->{'set' . ucfirst($property)}($obj->{'get' . ucfirst($property)}());
        }
    }

    return $newObj;
}

このメソッドをPersonクラスで作成し、それを使用してEmployeからClientに、またはその逆にキャストできます。

$employe = New Employe();
$client = Client::castToMe($employe);

これで、必要に応じて、$employeエンティティを削除できます。

于 2013-09-04T12:23:50.790 に答える
1

Doctrine2では、親エンティティクラスがある場合、次のようにPerson設定します。

/**
 * @Entity
 * @InheritanceType("JOINED")
 * @DiscriminatorColumn(name="discr", type="string")
 * @DiscriminatorMap({"person" = "Person", "employee" = "Employee", , "client" = "Client"})
 */
class Person
{
    // ...
}

および次のようなサブクラスClient

/** @Entity */
class Client extends Person
{
    // ...
}

次のようにインスタンス化する場合Person

$person = new Person();

Doctrine2は、@DiscriminatorMapステートメント(上記)に対応するマッピングをチェックPersonし、見つかった場合は、上記で設定されたテーブル列に文字列値を作成します@DiscriminatorColumn

したがって、次のようなインスタンスを作成することにした場合Client

$client = new Client();

これらの原則に従って、Doctrine2は、でパラメーターを宣言している限り、インスタンスを作成します@DiscriminatorMap。また、インスタンス化されたばかりのエンティティクラスのタイプを反映するために、Personテーブルのdiscr列にエントリが作成されます。

お役に立てば幸いです。それはすべてドキュメントにあります

于 2011-05-09T20:37:51.450 に答える
1

ただし、次のようなことができます。

このトレイトは、リポジトリクラスで使用できます。

namespace App\Doctrine\Repository;

trait DiscriminatorTrait
{
    abstract public function getClassMetadata();

    abstract public function getEntityManager();

    private function updateDiscriminatorColumn($id, $class)
    {
        $classMetadata = $this->getClassMetadata();

        if (!in_array($class, $classMetadata->discriminatorMap)) {
            throw new \Exception("invalid discriminator class: " . $class);
        }

        $identifier = $classMetadata->fieldMappings[$classMetadata->identifier[0]]["columnName"];

        $column = $classMetadata->discriminatorColumn["fieldName"];
        $value = array_search($class, $classMetadata->discriminatorMap);

        $connection = $this->getEntityManager()->getConnection();

        $connection->update(
            $classMetadata->table["name"],
            [$column => $value],
            [$identifier => $id]
        );
    }
}

サブクラスの1つにのみ存在するフィールドの値をクリアするなど、追加の作業が必要になる場合があります。

于 2019-02-18T15:26:13.140 に答える