您如何(如果可能的话)使用 Doctrine2 更改实体类型,使用它的类表继承?
假设我有一个Person
父类类型和两个继承类型Employe
,并且Client
. 我的系统允许创建一个 Person 并指定它的类型——这很容易实现——但我也希望能够将这个人从 Employe 更改为 Client,同时维护Person
- 级别信息(它是 id 和其他相关的记录)。
有没有一种简单的方法可以用 Doctrine2 做到这一点?
您如何(如果可能的话)使用 Doctrine2 更改实体类型,使用它的类表继承?
假设我有一个Person
父类类型和两个继承类型Employe
,并且Client
. 我的系统允许创建一个 Person 并指定它的类型——这很容易实现——但我也希望能够将这个人从 Employe 更改为 Client,同时维护Person
- 级别信息(它是 id 和其他相关的记录)。
有没有一种简单的方法可以用 Doctrine2 做到这一点?
我昨天也在寻找这种行为。
最后,在 freenode 上与#doctrine 中的人交谈后,我被告知这是不可能的。
如果你想这样做,那么你必须经历这个:
Employee
在您的表中为此继承创建相应的行。同样,如果你想删除继承,你必须..
Employee
。(是的,你必须删除它,仅仅改变鉴别器是不够的)。这可能晚了 7 个月,但它至少是任何其他希望支持此类功能的正确答案。
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 实体。
在 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
因此,当您决定拥有 as 的实例时Client
:
$client = new Client();
遵循这些原则,只要您在@DiscriminatorMap
. 还将在Person
表上的discr列中创建一个条目,以反映刚刚实例化的实体类的类型。
希望有帮助。这一切都在文档中
你可以做这样的事情:
此 Trait 可用于您的 Repository 类:
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]
);
}
}
您可能仍然需要进行一些额外的工作,例如清除仅存在于您的一个子类中的字段中的值