Symfony2 + Сопоставление объекта/базы данных Doctrine

Я создаю CMS, в которой все страницы нашего веб-сайта могут быть добавлены/обновлены/удалены/перемещены и т. д. Я создаю отношение oneToMany между страницами и page_versions, поэтому каждый раз, когда страница изменяется в CMS, копия будет сохраняться как page_version, чтобы мы могли вернуться к этой версии, если это необходимо. Кроме того, когда кто-то в данный момент редактирует страницу, она блокируется, поэтому другие пользователи не могут редактировать ее одновременно. Каждая страница также может иметь родительскую страницу, и каждая страница может иметь несколько правил перезаписи, используя другую связь oneToMany с таблицей rewrite_rules. Однако есть несколько полей, в которых я не уверен, в какой таблице они должны находиться и как их можно использовать в качестве объектов при сопоставлении с использованием отношений сущностей Symfony2 и Doctrine. Вот мои таблицы на данный момент:

page table

id
parent_id
locked

page_version table
page_id
title
content
enabled
position

rewrite_rules table
id
page_id
rewrite
canonical

Мои вопросы:

  1. Должно ли поле position находиться в таблице страниц или таблице page_version? Позиция для каждой страницы не будет меняться в зависимости от версии страницы. Это будет изменено только в представлении списка всех страниц. Это связано с тем, что если у вас есть, например, 5 дочерних страниц страницы «О нас», их можно заказать для вывода вывода в интерфейсе.
  2. Должна ли таблица rewrite_rules присоединяться к таблице страниц или таблице page_version? Опять же, это будет связано со страницей, а не с версией. Если кто-то редактирует версию страницы и добавляет правило перезаписи, оно будет применено к странице, а не только к этой версии страницы. То есть, если вы вернетесь к более старой версии, правило перезаписи все равно будет применяться к этой версии.
  3. Чтобы сделать версию страницы активной страницей, должно ли это быть простое поле в таблице страниц или в таблице page_version?

    Спасибо

    ОБНОВЛЕНИЕ

Вот мои классы Page и PageVersion:

class Page
{
    /**
    * @ORM\OneToMany(targetEntity="PageVersion", mappedBy="page")
    */
   private $pageversions;
}
class PageVersion
{
    /**
     * @var page
     *
     * @ORM\ManyToOne(targetEntity="Page", inversedBy="pageversions")
     *
     */
    private $page;

}

person user1961082    schedule 06.02.2013    source источник
comment
Несколько хороших вопросов. Я могу только предложить взглянуть на symfony-cms и посмотреть, каков их основной подход.   -  person Cerad    schedule 06.02.2013
comment
Я пытался посмотреть на их подход, но не могу найти схему их базы данных, есть идеи, где я могу ее найти?   -  person user1961082    schedule 06.02.2013
comment
Вам, вероятно, следует изучить symfony CMF, который использует JCR для постоянства.   -  person Ocramius    schedule 08.02.2013


Ответы (1)


Учтите, что ассоциации версий становятся действительно раздражающими в долгосрочной перспективе. Кроме того, вам, вероятно, следует удалить отношения OneToMany и оставить только их сторону ManyToOne.

Это упрощает управление версиями ваших данных с помощью такого инструмента, как EntityAudit, который, к сожалению, не работал в моем случае. case (не поддерживает наследование).

Итак, мой совет:

  1. если это не относится к версии свойства, то не делайте этого. Управление версиями — сложная проблема, и к тому же дорогая. ЯГНИ.
  2. если вы хотите отслеживать, были ли на странице правила перезаписи или нет в прошлом, вам нужно будет установить версию ассоциации, но, поскольку правило перезаписи не влияет на версию, YAGNI. На мой взгляд, вы можете просто связать страницу с переписыванием (также здесь: по возможности сохраняйте однонаправленную ассоциацию).
  3. Вам, вероятно, понадобится ссылка на «активную» страницу в объекте «страница». Это немного ускоряет запросы, а также упрощает работу с OOP API.
person Ocramius    schedule 08.02.2013
comment
Спасибо @Окрамиус. 1. Что значит удалить OneTOMany, но оставить ManyToOne? 2. Да, я согласен, что нет необходимости переписывать версии или позиционировать. 3. Еще раз согласен спасибо - person user1961082; 09.02.2013
comment
@user1961082 user1961082 вы можете определить однонаправленные ассоциации. По сути, вы избегаете определения стороны с коллекцией, где это возможно. - person Ocramius; 09.02.2013
comment
Спасибо еще раз. Возвращаясь к предложению активной страницы. Будете ли вы иметь active_page_id в объекте Page или иметь активное поле в PageVersion? У нас также будет возможность сохранить версию страницы в качестве черновика, так что это тоже нужно будет учитывать. - person user1961082; 09.02.2013
comment
Кроме того, возвращаясь к удалению oneToMany, что насчет того, когда я хочу перечислить все версии страницы для определенной страницы, чтобы пользователь мог вернуться к одной? - person user1961082; 09.02.2013
comment
Черновики будут просто версиями страницы, которые не были установлены как активные. Пока Page#activePage не изменено, вы можете добавить столько черновиков, сколько захотите. Поле active в поле PageVersion может помочь, если у вас есть страницы, которые опубликованы как hidden или которые вообще должны быть удалены из публикации (также может быть null для Page#activePage). Чтобы перечислить конкретные версии страниц, вы всегда можете использовать DQL. - person Ocramius; 09.02.2013
comment
Спасибо! Проблема, с которой я сталкиваюсь на данный момент, заключается в том, что я перечисляю все страницы в CMS, но показываю заголовок страницы для активной версии для каждой страницы. Я использую запрос (с активным в таблице page_version) SELECT p,pv FROM XYZWebsiteBundle:Page p JOIN p.pageversions pv WHERE pv.active = 1. Я также обновил свой первоначальный вопрос с двумя моими классами. Вы предлагаете удалить свойство oneToMany $pageversions из класса Page? - person user1961082; 09.02.2013
comment
Да, я бы не стал оставлять ссылку на все версии из класса Page (соображения производительности и SOC). Вероятно, вы захотите сохранить только ссылку на активную версию и вызовы прокси-метода из объекта Page в выбранный объект PageVersion. - person Ocramius; 09.02.2013
comment
давайте продолжим обсуждение в чате - person user1961082; 09.02.2013
comment
Итак, если я создам свойство $activeVersion на странице, как вы сказали, это будет отношение ManyToOne, верно? Не будет ли одна активная версия иметь одну страничную версию? - person user1961082; 09.02.2013
comment
Нет, это не OneToOne. Page#activeVersion это @ManyToOne(targetEntity="PageVersion") - person Ocramius; 09.02.2013
comment
Спасибо. Не могли бы вы объяснить, почему это ManyToOne, а не OneToOne? - person user1961082; 09.02.2013
comment
По возможности избегайте @OneToOne: это вызывает странные проблемы с ленивой загрузкой, если вы обращаетесь к стороне отношения, не являющейся владельцем, и применяет уникальные ключи. Используйте @ManyToOne, если это достаточно строго для вашего варианта использования :) - person Ocramius; 09.02.2013
comment
Хорошо спасибо. Теперь у меня все работает, используя OneToMany, как вы предложили. Единственная проблема, с которой я столкнулся, это когда вы создаете страницу и выбираете сохранить версию как черновик, а не сделать ее активной. Затем я не могу использовать свойство $activeVersion для извлечения заголовка страницы, когда я перечисляю все страницы в CMS. Какие-либо предложения? - person user1961082; 09.02.2013
comment
Вы, вероятно, хотите каким-то образом одновременно отображать как черновики, так и активные версии (в бэкэнд-операциях). Во внешнем интерфейсе учитывается только активная версия. - person Ocramius; 10.02.2013
comment
Возможно, добавьте Page#draftVersion так же, как я добавил Page#activeVersion, потому что у вас будет только один черновик, не так ли? Затем я могу проверить, является ли activeVersion нулевым, а затем загрузить draftVersion (только в бэкэнде) - person user1961082; 10.02.2013
comment
В бэкэнде вам все равно нужны последние версии. - person Ocramius; 10.02.2013
comment
Извините, что вы имеете в виду последние версии? - person user1961082; 10.02.2013
comment
последний, как в последнем черновике (самый новый, независимо от того, опубликован он или нет) - person Ocramius; 10.02.2013
comment
Итак, при редактировании страницы в бэкэнде вы загружаете последнюю версию, независимо от того, опубликована она или нет, а затем возможность вернуться к предыдущим версиям? Следовательно, нет необходимости в конкретном идентификаторе черновика? - person user1961082; 10.02.2013
comment
Верно. Это достигается с помощью чего-то вроде stackoverflow.com/questions/2111384/ - person Ocramius; 10.02.2013
comment
Итак, я бы использовал этот запрос, чтобы вывести список всех страниц и получить последнюю страницу, но использовать свойство Page#activeVersion, когда я хочу получить последнюю версию только на внешнем интерфейсе? В настоящее время я перебирал все объекты страницы, а затем вызывал Page->getActiveVersion()->getTitle() для печати заголовка каждой страницы, но, похоже, это запускает дополнительный запрос для каждой строки страницы. - person user1961082; 10.02.2013