...

среда, 7 августа 2013 г.

Пробуем Orchard CMS для корпоративного сайта

Привет!

У нас есть корпоративный сайт на Liferay, и он требует довольно кропотливой работы на этапе создания layout. Мы решили посмотреть, чем отличается создание кастомного раздела в Liferay от того же процесса в Orchard CMS в рамках такой небольшой задачки как создание корпоративных новостей.



Что у нас из этого вышло:


Настройка Orchard:


Реализация раздела «Новости» состоит из следующих частей:



  1. Тип содержимого.

  2. Настройки типа содержимого.

  3. Само содержимое.

  4. Запрос.

  5. Проекция – то, как всё будет выглядеть на сайте. Кастомизация внешних элементов.


Создание типа «News» и запроса (для показа на главной странице):

1. Создаём ContentType:








2. Добавляем в Новости картинку:



3. Создаём запрос

3.1.



3.2. Теперь надо настроить фильтры для запроса:



3.3. Определим порядок сортировки:



3.4. Т.к. результат запроса надо где-то показывать, создаём Projection:



Теперь на главной странице будет проекция. В dashboard можно создать несколько новостей.


Кастомизация внешнего вида




Создаём тему



Необходимо скачать и включить модуль Code generation: http://docs.orchardproject.net/Documentation/Command-line-scaffolding

Далее открываем папку с установленным Orchard -> bin -> orchard.exe, ждём, пока она инициализируется, пишем: codegen theme <theme-name> /BasedOn:TheThemeMachine /CreateProject:true


Открываем проект с темой:



И не можем создать Razor template… Для того, чтобы мы могли создавать .cshtml файлы из интерфейса студии, необходимо выгрузить проект, открыть файл проекта каким-либо текстовым редактором и изменить ProjectTypeGuids, добавив в него {E53F8FEA-EAE0-44A6-8774-FFD645390401}. У нас результат получился таким: {E53F8FEA-EAE0-44A6-8774-FFD645390401};{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}. Теперь можно сохранить файл проекта и загрузить его в студии.



Все файлы темы, не найденные в текущей, берутся из базовой, если она определена, или из темы «SafeMode». Нам необходимо изменить фавиконку и подключить скрипты, фавиконка подключается только в темплейте «Document.cshtml», скрипты, связанные с темой, принято подключать здесь же.


Теперь мы можем создать Document.cshtml в папке Views.

Внутри этого файла мы добавляем ссылки на скрипты, регистрируем фавиконку, а остальной код взят из аналогичного файла в теме SafeMode

Views\Document.cshtml:



@using Orchard.Mvc.Html;
@using Orchard.UI.Resources;
@{
RegisterLink(new LinkEntry { Type = "image/x-icon", Rel = "shortcut icon", Href = Url.Content("~/Themes/ETRTheme/Content/images/favicon-201209261628.ico") });
Script.Include("html5.js").UseCondition("lt IE 9").AtHead();
Script.Include("jquery.min.js").AtHead();
Script.Include("jquery-ui.min.js").AtHead();
Script.Include("knockout-2.2.1.js").AtHead();
Script.Include("jquery.lightbox.js").AtHead();
Script.Include("jquery.cycle.all.js").AtHead();
Script.Include("date.format.js").AtHead();
Script.Include("script.js").AtHead();


string title = Convert.ToString(Model.Title);
string siteName = Convert.ToString(WorkContext.CurrentSite.SiteName);
}
<!DOCTYPE html>
<html lang="@WorkContext.CurrentCulture" class="static @Html.ClassForPage()">
<head>
<meta charset="utf-8" />
<title>@Html.Title(title, siteName)</title>
@Display(Model.Head)
<script> (function (d) { d.className = "dyn" + d.className.substring(6, d.className.length); })(document.documentElement);</script>
</head>
<body>
@Display(Model.Body)
@Display(Model.Tail)
</body>
</html>


Этот файл отвечает за отрисовку страницы, в строке «@Display(Model.Body)» он вызывает Layout.cshtml.


Layout содержит в себе разметку страницы, подключает css и «показывает» разные зоны.


Изменение шейпов для кастомизации UI



Для того чтобы кастомизировать внешний вид элементов, необходимо создать несколько темплейтов с определёнными названиями (по одному на каждую кастомизацию, Orchard сам подберёт, каким темплейтом какой элемент ему рэндерить).

http://docs.orchardproject.net/Documentation/Accessing-and-rendering-shapes#NamingShapesandTemplates


В нашем случае будут, например, такие темплейты:



  • Content-News.Summary.cshtml – отвечает за отображение сокращённого варианта новости.

  • SliderGrid-ProjectionPage.cshtml – отвечает за отображение projection.




Темплейт для отображения сокращённой новости:

Views\Content-News.Summary.cshtml:

@using Orchard.Utility.Extensions;
@using Orchard.Fields.Fields;
@using Orchard.Core.Common.Models;
@using Orchard.ContentManagement;
@using System.Text.RegularExpressions;
@using Orchard.Tags.Models;
@using System.Text;
@using Orchard.MediaLibrary.Fields;
@using Orchard.ContentManagement

@{
ContentItem contentItem = Model.ContentItem;

var contentTypeClassName = ((string)contentItem.ContentType).HtmlClassify();
var news = ((dynamic)contentItem).News;

IEnumerable<ContentField> fields = news.Fields;

var common = contentItem.As<CommonPart>();
var publishedDate = "";
if (common.PublishedUtc.HasValue)
{
var date = common.PublishedUtc.Value;
publishedDate = date.ToString("d MMMM yyyy");
}

MediaLibraryPickerField newsMainImage = null;
bool newsHasImage = false;
string imageUrl = null;
string imageAlternateText = null;
try
{
newsMainImage = (MediaLibraryPickerField)fields.First(f => f.Name == "NewsMainImage");
imageUrl = newsMainImage.MediaParts.First().MediaUrl;
imageAlternateText = newsMainImage.MediaParts.First().AlternateText;
newsHasImage = true;
}
catch (InvalidOperationException e)
{
newsHasImage = false;
}

var body = contentItem.As<BodyPart>();
var summaryBodyText = body.Text.RemoveTags().Trim().Replace(Environment.NewLine, " ");
summaryBodyText = Regex.Replace(summaryBodyText, @"\s+", " ");
var textLength = newsHasImage ? 400 : 500;
textLength = textLength > summaryBodyText.Length ? summaryBodyText.Length : textLength;
summaryBodyText = summaryBodyText.Substring(0, textLength);

var tags = contentItem.As<TagsPart>().CurrentTags;
var tagsHtml = new List<IHtmlString>();
foreach (var t in tags)
{
if (tagsHtml.Any())
{
tagsHtml.Add(new HtmlString(", "));
}
tagsHtml.Add(Html.ActionLink((string)t.TagName, "Search", "Home", new { area = "Orchard.Tags", tagName = (string)t.TagName }, new { }));
}

<div
@if (newsHasImage)
{
<text>class="b-newsroll-item-inner"</text>
}
else
{
<text>class="b-newsroll-item-inner-no-image"</text>
}>
@if (common.PublishedUtc.HasValue)
{
<div class="b-newsroll-date">
@publishedDate
</div>
}
@if (newsHasImage)
{
<div class="b-newsroll-image-wrapper">
<img class="b-newsroll-image" src="@Url.Content(@imageUrl)"
@if (!String.IsNullOrWhiteSpace(imageAlternateText))
{
<text>alt="@imageAlternateText"</text>
}/>
</div>
}
<div class="b-newsroll-content">
<div class="b-newsroll-text">
<p>@Html.Raw(summaryBodyText)</p>
</div>
<span class="b-newsroll-content-crop"></span>
</div>
<div class="b-newsroll-more">
@Html.ItemDisplayLink(T("Read more").ToString(), contentItem)
</div>


@if (tagsHtml.Any())
{
<div class="b-newsroll-tags">
<span>
@T("Tags:")
</span>
@foreach (var htmlString in tagsHtml)
{
@htmlString
}
</div>
}
</div>
}


Создание грида для расположения новостей



Теперь надо сделать нормальный грид для новостей, для этого создаём модуль «SliderGrid»: codegen module SliderGrid и описываем в нём шейпы:

Layouts\SliderGridLayoutForms.cs:



using System;
using Orchard.DisplayManagement;
using Orchard.Forms.Services;
using Orchard.Localization;

namespace SliderGrid.Layouts
{
public class SliderGridLayoutForms : IFormProvider
{
protected dynamic Shape { get; set; }
public Localizer T { get; set; }

public SliderGridLayoutForms(
IShapeFactory shapeFactory)
{
Shape = shapeFactory;
T = NullLocalizer.Instance;
}

public void Describe(DescribeContext context)
{
Func<IShapeFactory, object> form =
shape =>
{
var f = Shape.Form(
Id: "SliderGridLayout",
_HtmlProperties: Shape.Fieldset()
);
return f;
};
context.Form("SliderGridLayout", form);
}
}
}

Layouts\SliderGridLayout.cs:
using System.Collections.Generic;
using System.Linq;
using Orchard.ContentManagement;
using Orchard.DisplayManagement;
using Orchard.Localization;
using Orchard.Projections.Descriptors.Layout;
using Orchard.Projections.Models;
using Orchard.Projections.Services;

namespace SliderGrid.Layouts
{
public class SliderGridLayout : ILayoutProvider
{
public Localizer T { get; set; }
private readonly IContentManager _contentManager;
protected dynamic Shape { get; set; }
public SliderGridLayout(IShapeFactory shapeFactory, IContentManager contentManager)
{
_contentManager = contentManager;
Shape = shapeFactory;
T = NullLocalizer.Instance;
}

public void Describe(DescribeLayoutContext describe)
{
describe.For("Html", T("Html"), T("Html Layouts"))
.Element("SliderGrid", T("SliderGrid"), T("Renders multiPageGrid of elements + slider."),
DisplayLayout,
RenderLayout,
"SliderGridLayout"
);
}

public LocalizedString DisplayLayout(LayoutContext context)
{
return T("Renders multiPageGrid + slider.");
}

public dynamic RenderLayout(LayoutContext context, IEnumerable<LayoutComponentResult> layoutComponentResults)
{
IEnumerable<dynamic> shapes =
context.LayoutRecord.Display == (int)LayoutRecord.Displays.Content
? layoutComponentResults.Select(x => _contentManager.BuildDisplay(x.ContentItem, context.LayoutRecord.DisplayType))
: layoutComponentResults.Select(x => x.Properties);

return Shape.SliderGrid(Items: shapes);
}
}
}


Включаем грид



Подключаем в «модулях» фичу SliderGrid, изменяем layout запроса LastNews на SliderGrid:


Изменяем в проекции запрос на только что исправленный.



Выводы




Для того, чтобы можно было через админку писать новости, нам надо реализовать ContentType, в нашем случае — News. Чтобы показать список новостей на главной странице, нам нужен Projection, а для него — Query. Чтобы мы могли кастомизировать внешний вид элементов, нам надо в текущей теме в папку Views положить шаблоны с определёнными именами, по которым Orchard сможет понять, к какому шейпу этот шаблон применять. Как доставать ContentPart и ContentTypeField из ContentType понятно из примера с короткими новостями.

На основании проведенного эксперимента мы пришли к выводу, что Orchard и Liferay на этапе подготовки инструмента для публикации новостей… примерно одинаковые. И там, и там есть кастомизация тем, изготовление нужных сущностей, возможность кастомизации этих сущностей, но имеется нюанс: на этапе, когда надо сделать блочный вывод (например, список новостей или статей) начинаются проблемы с Liferay – проблема падает на программиста, которому надо вытащить сущности самостоятельно, чтобы их отображать. Здесь требуется довольно высокая квалификация в java и в разработке под Liferay.


В Orchard же есть удобный механизм запроса — Query, — справиться с которым под силу всем.


This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers. Five Filters recommends: 'You Say What You Like, Because They Like What You Say' - http://www.medialens.org/index.php/alerts/alert-archive/alerts-2013/731-you-say-what-you-like-because-they-like-what-you-say.html


Комментариев нет:

Отправить комментарий