Как определить Doctrine mappedSuperclass, используя XML или YAML вместо сопоставления аннотаций

Следующий сценарий исходит из https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/inheritance-mapping.html#mapped-superclasses и был изменен только для включения второго подкласса. Насколько я понимаю, MappedSuperclassBase не может существовать сам по себе, а должен быть расширен одним и только одним подклассом (то есть либо EntitySubClassOne, либо EntitySubClassTwo), и это та же концепция, что и надтип/подтип для SQL. Соглашаться?

Как определяется супер/подтип с использованием YAML или XML вместо сопоставления аннотаций?

<?php
/** @MappedSuperclass */
class MappedSuperclassBase
{
    /** @Column(type = "integer") */
    protected $mapped1;
    /** @Column(type = "string") */
    protected $mapped2;
    /**
     * @OneToOne(targetEntity = "MappedSuperclassRelated1")
     * @JoinColumn(name = "related1_id", referencedColumnName = "id")
     */
    protected $mappedRelated1;

    // ... more fields and methods
}

/** @Entity */
class EntitySubClassOne extends MappedSuperclassBase
{
    /** @Id @Column(type = "integer") */
    private $id;
    /** @Column(type = "string") */
    private $name;

    // ... more fields and methods
}

/** @Entity */
class EntitySubClassTwo extends MappedSuperclassBase
{
    /** @Id @Column(type = "integer") */
    private $id;
    /** @Column(type = "string") */
    private $name;

    // ... more fields and methods
}

По вашей ссылке прокрутите вниз сюда: doctrine-project.org/projects/doctrine-orm/en/2.6/reference/‌​… ;-)

rkeet 05.02.2019 15:54

@rkeet Если я не ошибаюсь, в этом разделе описываются только переопределения ассоциации, а рассматриваемая часть опущена и описана как //other fields mapping.

user1032531 05.02.2019 16:01

Ваш вопрос спрашивает "как сделать с помощью Yaml/XML". Если вы перейдете конкретно по этой ссылке, в примере кода есть вкладки вверху, позволяющие переключать язык. Если вы читаете этот код, вы видите, «как» отображать там запрошенный MappedSuperClass. (YAML: type: mappedSuperclass, XML: <mapped-superclass name = "MyProject\Model\User">)

rkeet 05.02.2019 16:10

@rkeet Но он не показывает эквивалент @OneToOne(targetEntity = "MappedSuperclassRelated1") и @JoinColumn(name = "related1_id", referencedColumnName = "id"), конечно, это не так уж сложно преобразовать. Что еще более важно, это не объясняет, как EntitySubClass знает, что он связан с MappedSuperclassBase, и это та часть, над которой я борюсь. Спасибо

user1032531 05.02.2019 19:58

Если Worker расширяет Person (суперкласс), то у вас есть 1 Entity: Worker. Создание отношения к Worker (т.е. из Paycheck), ссылки только на Worker. Надкласс Person просто создает базовый набор свойств/значений по умолчанию, которые используются в Worker.

rkeet 06.02.2019 09:05

Я думаю, вы можете перепутать MappedSuperClass с классом Discriminator. Первый предоставляет свойства/значения по умолчанию для дочернего класса, но сам по себе никогда не является сущностью. Последний, различаемый Entity, является классом сам по себе.

rkeet 06.02.2019 09:07
Преобразование данных с помощью красноречивых аксессоров и мутаторов в Laravel
Преобразование данных с помощью красноречивых аксессоров и мутаторов в Laravel
Laravel поставляется с мощной функцией под названием "Eloquent Accessors and Mutators".
Отношения "многие ко многим" в Laravel с методами присоединения и отсоединения
Отношения "многие ко многим" в Laravel с методами присоединения и отсоединения
Отношения "многие ко многим" в Laravel могут быть немного сложными, но с помощью Eloquent ORM и его моделей мы можем сделать это с легкостью. В этой...
0
6
1 163
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Судя по нашим комментариям, я вижу ваше замешательство. Поскольку документы обрабатывает и «MappedSuperclass», и «Discriminator» на одной странице, я думаю, вы перепутали их использование в своей голове. Надеюсь, это поможет вам:

  • MappedSuperclass предоставляет свойства/значения по умолчанию повторно используемым способом, но сам по себе он никогда не может быть сущностью. Это сопоставимо с классами PHP abstract (которые не могут быть созданы сами по себе).
  • Дискриминатор дает возможность «расширить» Сущность, сделав ее другой Сущностью. Например, наличие объекта Person дает вам 1 объект. Этот объект может быть расширен, например, Worker и Manager.

Хорошим вариантом использования MappedSuperclass будет AbstractEntity. Каждому объекту нужен идентификатор, уникальный идентификатор. Это также дает вам что-то общее для проверки в Listeners и тому подобное. Итак, приступайте к созданию:

/**
 * @ORM\MappedSuperclass
 */
abstract class AbstractEntity
{
    /**
     * @var int
     * @ORM\Id
     * @ORM\Column(name = "id", type = "integer", options = {"unsigned":true})
     * @ORM\GeneratedValue(strategy = "IDENTITY")
     */
    protected $id;
  
    // getter / setter
}

Посмотрите, как это объявлено abstract и MappedSuperclass?

Это связано с тем, что ни один из них (abstract class и MappedSuperclass) не может быть создан сам по себе. Вы не можете использовать $entity = new AbstractEntity(), потому что это PHP-класс abstract. Также Doctrine не создаст отдельную таблицу для AbstractEntity.

Затем создайте Person:

/**
 * @ORM\Entity
 * @ORM\Table(name = "persons")
 *
 * @InheritanceType("JOINED")
 * @DiscriminatorColumn(name = "discr", type = "string")
 */
class Person extends AbstractEntity
{
    /**
     * @var string
     * @ORM\Column(name = "name", type = "string", length=255, nullable=false)
     */
    protected $name;

    // getter / setter
}

Вышеупомянутая сущность Person настроена для Наследование таблицы классов через тип наследования JOINED. Это означает, что на уровне базы данных таблица persons будет отделена от любых столбцов, добавленных другими объектами, расширяющими Person.

Обратите внимание, что я не объявил DiscriminatorMap. Ниже из документов, выделенных мной жирным шрифтом:

Things to note:

  • The @InheritanceType, @DiscriminatorColumn and @DiscriminatorMap must be specified on the topmost class that is part of the mapped entity hierarchy.
  • The @DiscriminatorMap specifies which values of the discriminator column identify a row as being of which type. In the case above a value of "person" identifies a row as being of type Person and "employee" identifies a row as being of type Employee.
  • The names of the classes in the discriminator map do not need to be fully qualified if the classes are contained in the same namespace as the entity class on which the discriminator map is applied.
  • If no discriminator map is provided, then the map is generated automatically. The automatically generated discriminator map contains the lowercase short name of each class as key.

Теперь давайте создадим Worker:

/**
 * @ORM\Entity
 * @ORM\Table(name = "workers")
 */
class Worker extends Person
{
    /**
     * @var int
     * @ORM\Column(name = "worker_id", type = "integer", length=11, nullable=false)
     */
    protected $workerId;

    // getter / setter
}

Итак, теперь у нас есть:

  • MappedSuperclass: AbstractEntityнет является автономным объектом.
  • Дискриминация: Personявляется автономный объект
  • "нормальный": Worker - расширяетPerson

Что следует отметить:

  • Будет создан экземпляр MappedSuperclass не может. Таким образом: вы не может создаете на него ссылки/отношения. Сопоставимо с PHP abstract class
  • Дискриминированный объект — это объект, который также стоит отдельно и может использоваться как обычный объект. Вы можете создавать отношения с ним и из него без проблем
  • Объект, расширяющий Дискриминированный Объект, является экземпляром обоих. В приведенном выше коде оба варианта верны: $worker instanceof Worker и $worker instanceof Person, потому что Worker расширяет Person. Однако $person instanceof Worker будет false!

$workerId = $person->getWorkerId() // generates "method does not exist" fatal

$workerId = $worker->getWorkerId() // generates integer value


Надеюсь, вам удалось прояснить ситуацию. Если нет, не стесняйтесь спрашивать.

Спасибо rket. В вашем примере вы явно определили class Person extends AbstractEntity. Но если он реализован с использованием XML или YAML, не будет ли он НЕ начинаться с класса PHP, поэтому не сможет определить это отношение таким образом?

user1032531 06.02.2019 12:52

Вы начинаете было бы таким образом, см. предыдущую ссылку здесь: doctrine-project.org/projects/doctrine-orm/en/2.6/reference/‌​… — случай, когда User является MappedSuperclass, который расширяется Admin. Если вы будете следовать этому, вы сможете заставить его работать.

rkeet 06.02.2019 15:40

А, я вижу источник моего замешательства. Я неправильно думал, что MappedSuperclass представляет супертип/подтип SQL (Learndatamodeling.com/blog/supertype-and-subtype). Я понял, что невозможно создать экземпляр MappedSuperclass, но я не осознавал, что с ним не связана таблица!

user1032531 07.02.2019 11:42

Ах, хорошо, один бит, который я не объяснил в ответе ;-) Но опять же, это как abstract class против class ;-) Поскольку первый не может быть создан, как объект, у него нет таблицы. Последний может должен быть создан и должен иметь связанное с ним хранилище данных (таблицу). Затем есть размеченные классы, где «наследование одной таблицы» имеет «корневую» таблицу самого родительского класса, который расширяется, и наследование таблицы классов, где каждая сущность имеет свою собственную таблицу, но присоединена к своему родителю (и, таким образом, это конкретная таблица добавляет только свои добавленные свойства).

rkeet 07.02.2019 12:18

В очередной раз благодарим за помощь. Первый раз каждый раз экспериментировал с ORM, и это было путешествие, но оно начинает собираться. Дискриминированные классы - это то, что я хочу.

user1032531 07.02.2019 13:21

Что касается discriminator column, я еще не разобрался с этой частью. Если у меня есть абстрактная таблица Person и person с первичным ключом id, а также конкретная таблица Teacher и Student с таблицами teacher и student также с первичными ключами id, где Person можно соединить только с одним Teacher или одним Student с использованием одно отношение, поместил бы я @InheritanceType("JOINED"), @DiscriminatorColumn(name = "id", type = "integer") и @DiscriminatorMap({"teacher" = "Teacher", "student" = "Student"} в Person?

user1032531 07.02.2019 13:27

Ах, кажется, я ошибаюсь насчет discriminator column. В настоящее время у меня нет столбца type в person, но я полагаюсь на соединение id. Может быть, я должен добавить один...

user1032531 07.02.2019 13:37
JOINED вызывает таблица на сущность, однако «первая» сущность (например, Person) содержит только столбец name (и первичный ключ ID), вторая таблица (например, Worker) содержит только столбец workerId (и ID иностранный ключ).
rkeet 07.02.2019 13:56
SINGLE_TABLE заставляет все "дочерние" сущности продлевать исходной таблицы. Таким образом, как для человека, так и для работника (а также для босса и родственника) вы получаете в общей сложности 1 (одну) таблицу! -> id, name, workerId, bossId, relativeId — где все дополнительные поля «пустые».
rkeet 07.02.2019 13:57

Что касается @DiscriminiatorMap, просто удалите эту строку (см. жирную цитату в ответе). Оставьте это доктрине. Делайте только @DiscriminatorColumn(name = "discr", type = "string") и DiscriminatorType. (последнее залейте сами, советую JOINED)

rkeet 07.02.2019 13:58

Другие вопросы по теме