Как изменить и тип сущности в Doctrine2 CTI Inheritance - PullRequest
10 голосов
/ 09 мая 2011

Как (если это вообще возможно) изменить тип сущности с помощью Doctrine2, используя его наследование таблиц классов?

Допустим, у меня есть Person родительский тип класса и два унаследованных типа Employe и Client. Моя система позволяет создать Person и указать его тип - это довольно просто реализовать - но я также хотел бы иметь возможность сменить Person с Employe на Client, сохранив при этом информацию Person -уровня (это id и другие связанные записи).

Есть ли простой способ сделать это с Doctrine2?

Ответы [ 4 ]

6 голосов
/ 02 сентября 2011

Я тоже вчера искал это поведение.

В конце концов, после разговора с людьми в #doctrine на freenode мне сказали, что это невозможно.

Если вы хотите сделать это, то вам нужно пройти через это:

Обновление пользователя

  1. Возьмите сущность человека.
  2. Обновите столбец дискриминатора, чтобы он больше не был «человеком», и измените его на «сотрудник»
  3. Создайте соответствующую строку в своей таблице Employee для этого наследования.

Удаление наследования

Аналогичным образом, если вы хотите удалить наследование, вам необходимо ..

  1. Захватить объект Person.
  2. Обновить столбец дискриминаторачтобы он больше не был «сотрудником» и измените его на «человека».
  3. Удалите соответствующую строку в таблице Employee.(Да, вы должны удалить его, просто изменить дискриминатор недостаточно).

Это может быть на 7 месяцев позже, но это, по крайней мере, правильный ответ для всего, кто хочет поддержать такую ​​функцию.

4 голосов
/ 04 сентября 2013

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

Теперь, если хотите, вы можете удалить объект $ employee.

1 голос
/ 10 мая 2011

В 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 , чтобы отразить тот тип класса сущности, который только что был создан.

Надеюсь, что это поможет.Это все в документации хотя

0 голосов
/ 18 февраля 2019

Вы могли бы сделать что-то вроде этого, хотя:

Эта черта может быть использована в вашем классе репозитория:

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

Возможно, вам придется проделать дополнительную работу, например очистку значений в полях, присутствующих только в одном из ваших подклассов

...