Orchard CMS можно назвать документоориентированной CMS: в Orchard есть понятие Content Item, что практически эквивалентно понятию Document в Umbraco.
Content Item — это единица контента. Например, запись в блоге, страница, статья. Соответственно, каждый Content Item является экземпляром какого-нибудь Content Type'а.
Content Type — определение типа Content Item'а, это аналог Document Template в Umbraco. Для управления Content Item'ами в Orchard CMS по-умолчанию есть один единственный грид:
Этот грид снабжён фильтром по Content Type, но каждый раз выставлять фильтр неудобно. Можно наделать себе в браузере закладок на страницы с фильтрами, но проще установить модуль Vandelay Industries. В этом модуле есть фича Vandelay Content Admin Menu, которая добавляет ссылки на cписки конкретных Сontent Item'ов.
На этом примере хорошо видно, что по-умолчанию Orchard CMS имеет довольно неудобную админку, и до приемлемого состояния её приходится доводить сторонними модулями.
Content Type может содержать Field'ы и Content Part'ы. Field — это минимальная часть контента. Content Part может содержать Field'ы и предоставлять свои собственные данные. Например, Content Part может получать посты из Twitter'a или из базы данных.
В Orchard CMS между Content Type'ами нет наследования, но отсутствие наследования можно легко обойти использованием Part'ов.
Например, мы хотим, чтобы News, BlogPost и Article имели короткое описание, которое бы выводилось красным цветом. Для этого нам нужно создать свой RedDescriptionPart и добавить его в желаемые Content Type'ы. Ещё нам понадобится один шаблон для отображения Part'a. Таким образом мы сможем управлять отображением Content Part'a нескольких Content Type'ов.
Важное отличие между Filed'ами и Part'ами в том, что Part'ы можно многократно использовать в разных Content Type'ах.
Допустим, у нас есть Content Part, который содержит один единственный Boolean Field "Approved" (одобрено). Этот Content Part добавлен в несколько Content Type'ов. В принципе, мы могли бы добавить этот Field прямо к Content Type'у и получили бы тот же результат. Но вот нам приходит требование добавить имя одобрившего. В случае с Content Part'ом мы просто добавляем ещё один Field в Part, а вот в случае с разрозненными Field'ами нам прийдётся много помучаться, чтобы найти все типы с полем Approved.
В базе все Field'ы ContentItem'a хранятся в таблице в сериализованном виде в таблице
Orchard_Framework_ContentItemVersionRecord
.
Если у вас тип имеет пару Text'ов и булево полe, то, при необходимости получить только
булево поле, Orchard вытащит ещё и данные из Text'ов.
Например, у меня есть тип News со своими Field'ами, и к типу News добавлен NewsPart у которого есть свои филды. В итоге XML будет выглядеть так:
<Data>
<News>
<TextFiled>News text here</TextFiled>
<BoolField>True</BoolField>
</News>
<NewsPart>
<NewsPartTextField>News part text here</NewsPartTextField>
<NewsPartBoolField>True</NewsPartBoolField>
</NewsPart>
</Data>
В Orchard CMS есть BodyPart с одним единственным текстовым полем,
только данные из этого поля попадают в таблицу Common_BodyPartRecord
.
Здесь надо заметить, что Orchard CMS при загрузке данных для Content Item'а использует Lazy Load и не будет загружать Part'ы, которые вы не собираетесь использовать.
В Orchard CMS нельзя добавить один и тот же Part в Content Type дважды. Потому не получится использовать один BodyPart для текста статьи, а другой BodyPart для краткого описания статьи.
Field — это не обязательно одна строчка или число. Вот, например, YouTubeField.
В базе ContentItem типа Video, содержащий только одно это поле будет выглядеть так:
<Data>
<Video>
<YoutubeFiled Identifier="oHg5SJYRHA0" Width="640" Height="390" />
</Video>
</Data>
Отношения между объектами
Content Picker Field
В Orchard 1.5 появился Content Picker Field, который позволяет выбрать один или несколько ContentItem'ов. Этим решается задача связки Content Item'ов, однако фича довольно сырая. В Orchard 1.5.1 она глючит и позволяет добавлять элементы только по одному, те для добавления 10 элементов пикер прийдётся открывать 10 раз. Возможно, в Orchard 1.5.2 это поправят.
Сторонняя реализация похожей функциональности, говорят, есть в модуле Science Project: Mechanics, но этот модуль не совместим с Orchard 1.5.
Query и Projection
В Orchard CMS есть возможность организовать выборки Content Item'ов, эта функция называется Query.
Здесь можете посмотреть пример использования:
Как вы могли увидеть, в Query можно делать сортировку и фильтрацию по Field'ам. Для этого
Orchard не десериализует XML, а пользуется таблицами вроде
Orchard_Projections_StringFieldIndexRecord
.
Query приучает не использовать Field'ы с одинаковой функциональностью для разных Content Type'ов. Вот, что получается в Edit Query, если в Content Type'ы Article, News, BlogPost добавлено по филду Teaser:
В этом примере правильно было бы создать один Content Part с Field'ом Teaser и добавить его в Article, News, BlogPost.
Ваши собственные Content Part'ы тоже могут добавить условия в Query, но для этого вам прийдётся реализовать свой
IFilterProvider
, а если нужна сортировка, то и ISortCriterionProvider
.
Taxonomies
Для категоризации контента есть модуль Taxonomies, видео про этот модуль можно посмотреть здесь.
Этот модуль может заменить механизм тегов, который поставляется вместе с Orchard.
Сразу скажу, что с помощью этого модуля можно организовать связь вроде "Страна → Статья". Но Taxonomy не может иметь дерево из Term'ов разного типа, так что создать иерархию "Страна", "Город" и уже к ним привязывать статью, у вас не выйдет, прийдётся писать свой модуль код.
Container и Containable
Есть возможность создавать списки из Content Item'ов, как написано в статье Creating lists. Но из-за того, что Part одного типа можно добавить в Content Type только один раз, нельзя добавить ContainablePart дважды. Потому невозможно создать список любимых статей и список всех статей, так чтобы эти два списка имели общие элементы: статья будет либо в одном, либо в другом списке. Из-за этого ограничения нельзя создать Content Type, который будет содержать в себе два списка.
Модуль List является deprecated, но он делает управление Container Part'ом очень удобным. Добавление и удаление нескольких элементов становится намного удобнее, чем в случае Content Picker Field'a, описанного выше.
Навигация (Menu)
Навигация позволяет вам создавать списки из Content Item'ов, но, в отличии от Container и Containable, один Content Item может быть одновременно в нескольких списках.
В Orchard 1.5 появился приемлемый модуль навигации.
В Orchard 1.4 стандартный модуль навигации был довольно убогий: позволял создавать только одну неиерархическую менюшку. Потому был популярен модуль Advanced menu, который тоже содержал довольно неприятные баги, но их было довольно просто пофиксить самому.
Самописные отношения и списки
В Orchard CMS создавать свои собственные ContentPart'ы и реализовывать связи между ними довольно просто и быстро, если знать как это делать. Потому если вам нужна нетривиальная связь, то смело открывайте Visual Studio и создавайте свои собственные ContentPart'ы, реализующие сущности и списки.
Я применяю такую стратегию: делаю простые сущности вроде ArticlePart и CategoryPart. CategoryPart не имеет никаких полей, а ArticlePart имеет только ссылку на CategoryPart. Затем реализую два Content Type'a: Category и Article, и уже к этим типам добавляю Part'ы вроде TitlePart, BodyPart и Field'ы вроде Favorite. Это даёт возможность легко использовать Query, например, чтобы выбирать любимые статьи.