如何在Doctrine2 CTI继承中更改和实体类型

时间:2011-05-09 14:37:42

标签: database doctrine-orm class-table-inheritance

如何(如果可能的话)使用Doctrine2更改实体类型,使用它的类表继承?

假设我有一个Person父类类型和两个继承类型EmployeClient。我的系统允许创建一个Person并指定它的类型 - 这很容易实现 - 但我也希望能够将人员从Employe更改为Client,同时保留Person级别的信息(这是id和其他相关记录。)

使用Doctrine2有一种简单的方法吗?

4 个答案:

答案 0 :(得分:6)

我昨天也在寻找这种行为。

最后,在与freenode上#doctrine的人交谈后,我被告知这是不可能的。

如果你想这样做,那么你必须经历这个:

升级用户

  1. 抓住人员实体。
  2. 更新discrimator列,使其不再是“person”并将其更改为“employee”
  3. 在您的Employee表中为此继承创建相应的行。
  4. 删除继承

    同样,如果你想删除继承,你必须..

    1. 抓住人员实体。
    2. 更新discriminimnator列,使其不再是“员工”并将其更改为“此人”。
    3. 删除Employee表格中的相应行。 (是的,你必须删除它,只是更改discrimator coumn是不够的)。
    4. 这可能会延迟7个月,但对于其他任何想要支持此类功能的内容来说,这至少是正确答案。

答案 1 :(得分: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实体。

答案 2 :(得分: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();

遵循这些原则,只要您在@DiscriminatorMap中声明了参数,Doctrine2就会为您创建一个实例。此外,还将在Person表中的 discrimination 列中输入一个条目,以反映刚刚实例化的实体类的类型。

希望有所帮助。它全部在documentation

答案 3 :(得分:0)

您可以执行以下操作:

此特性可用于您的存储库类:

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]
        );
    }
}

您可能还需要做一些额外的工作,例如清除仅在您的一个子类中存在的字段中的值