以前で[Sitecore MVC] カスタムモデルを使用する Sitecore MVC で使用する 既定の RenderingModel 以外のカスタムモデルを作成する方法を紹介しましたが、前回はサンプルがあっさり過ぎた気がするので、今回は IRenderingMode を実装するパターンと RenderingModel で実装するパターンでより本格的なカスタムモデルを作成する方法の覚書を記載します。

検証環境

  • Sitecore CMS 7.2 Update 1
  • Visual Studio 2012

1. データテンプレートの作成

まず最初にモデルクラスで使用するためのデータテンプレートを作成してみます。今回は下図のように Product という名前で データテンプレートを作成してみました。Productデータテンプレートは Name, Price, Picture というフィールドを持っています。

2. モデルクラスとMVC ビューページ (レイアウト) の作成

Visual Studio 上のプロジェクトで Product データテンプレート型のアイテムを表す カスタムモデルのクラスを作成します。今回は下記のように IRenderingModel を実装する ProductModel というクラスを作成しました。Initializeメソッドの中でRenderingModel クラスが行っていることとほぼ同じ処理を実装しています。 IRenderingModel をカスタムモデルが実装することで Sitecore は getModel パイプラインで カスタムモデル生成時に自動的に  Initialize メソッドを呼び出します。カスタムモデルクラスの実装者はInitialize メソッドでモデルクラスを初期化するコードを実装できます。今回作成した カスタムモデルクラスでは Name, Price, Picture というプロパティを定義しています。プロパティでは FieldRenderer を使用してマークアップを出力することで ページエディターが編集モードの場合は自動的にみたまま編集(インライン編集) を行えるようにしています。Pictureプロパティではさらに、コードからFieldRenderer のインスタンスにいくつかのパラメーターを渡すサンプルを記載しています。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Collections.Specialized;

namespace v72u1.Web.Fx.Models
{
    using Sitecore;
    using Sitecore.Data.Items;
    using Sitecore.Mvc.Presentation;
    using W = Sitecore.Web.UI.WebControls;
    /// <summary>
    /// IRenderingModel を実装するパターン
    /// </summary>
    public class ProductModel : IRenderingModel
    {
        /// <summary>名前</summary>
        public virtual HtmlString Name
        {
            get
            {
                return new HtmlString(W.FieldRenderer.Render(Item, "Name"));
            }
        }

        public virtual HtmlString Price
        {
            get
            {
                return new HtmlString(W.FieldRenderer.Render(Item, "Price"));
            }
        }
        public virtual HtmlString Picture
        {
            get
            {
                NameValueCollection p = new NameValueCollection();
                p.Add("mw", "100");
                p.Add("mh", "200");
                var r = new W.FieldRenderer();
                r.Item = this.Item;
                r.FieldName = "Picture";
                r.DisableWebEditing = true;
                r.Parameters = StringUtil.NameValuesToString(p, "&");
                return new HtmlString(r.Render());
            }
        }
        /// <summary>データソースアイテム</summary>
        public virtual Item Item { get; private set; }
        /// <summary>コンテキストアイテム</summary>
        public virtual Item PageItem { get; private set; }
        /// <summary>レンダリング情報</summary>
        public virtual Rendering Rendering { get; private set; }
        /// <summary>
        /// 初期化処理.今回はRenderingModelと同じような処理を行っています.
        /// InitializeModel プロセッサから呼び出される
        /// </summary>
        /// <param name="rendering"></param>
        public void Initialize(Rendering rendering)
        {
            this.Rendering = rendering;
            this.PageItem = PageContext.Current.Item;
            this.Item = rendering.Item;
        }
    }
}

カスタムモデルを作成したので、今度はカスタムモデルを使用するレイアウト (MVC 5 ビューページ) を作成します。

今回はMVCで実装したレイアウトでカスタムモデルを使用しますが、ビューレンダリング(MVC 5 部分ページ) でカスタムモデルを使うこともできます。

Viewフォルダー配下の任意のフォルダーを選択して 右クリック -> 追加 -> 新しい項目 をクリックして 新しい項目の追加ダイアログを表示します。下図のように MVC テンプレートから MVC 5 ビューページ (Razor) テンプレートを選択してビューを作成します。今回は View/SC フォルダー配下に TestLayout.cshtml という名前でファイルを作成しました。

ソリューションエクスプローラーを確認すると次のように TestLayout.cshtml が作成されます。

TestLayout.cshtml を次のように編集します。ビューの定義自体はとくに大したことは行っていません。単純に ProductModel のモデルクラスの各プロパティを出力しているだけです。

@using Sitecore.Mvc
@using Sitecore.Mvc.Presentation
@model v72u1.Web.Fx.Models.ProductModel

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>サンプルページ</title>
</head>
<body>
    <div>
        @Model.Picture<br />
        @Model.Name<br />
        @Model.Price
        <br />
    </div>
</body>
</html>

ここまででプログラムの準備ができました。ビルドを行いエラーの発生しないことを確認します。

3.モデルとレイアウト定義アイテムの作成

作成したモデルクラスとビュー (cshtml) をサイトコアで使用するために対応する定義アイテムを作成します。サイトコアエクスプローラー上で /master/sitecore/layout/Models アイテムを右クリック → Add → Model をクリックします。下図の Add New Item ダイアログが表示されるので モデルの名前を入力して OK ボタンをクリックします。今回は ProductModl という名前でモデルの定義アイテムを作成しました。

作成したモデル定義アイテムの  Model Type フィールドに 作成したモデルクラスのシグネチャを記述します(下図参照)。シグネチャとは 完全修飾名付きのクラス名です。うまく動作しない場合は <完全修飾名付きクラス名> , <アセンブリ名> をフィールドに入力してください。フィールドを変更したら忘れずに変更を保存します。

次に 作成した cshtml(MVC 5 ビューページ)  に対応する レイアウト定義アイテムを作成します。サイトコアエクスプローラー上で /master/sitecore/layout/Layouts を右クリック→ Add → New Item.. をクリックします。ダイアログが表示れます。 下図のように Layout テンプレートを使って TestLayout というレイアウトの定義アイテムを作成しました。

引き続き 作成した レイアウト定義アイテムを編集します。 Path フィールドに cshtml までのパスを入力します。 Model フィールドにレイアウトで使用するカスタムモデルのモデル定義アイテムのGUID (サイトコア上でのパスでもOKだと思います。) を設定し変更を保存します。

最後のレイアウト詳細の設定を行います。 Product データテンプレートのスタンダードヴァリューアイテムを作成し、レイアウト詳細の編集を行います。下図のように Layout に 先ほど作成した レイアウトの定義アイテム(本例では TestLayout) を指定します。

準備ができたので、 Home アイテム配下に Product 型のアイテムをいくつか作成したあと ページエディターで作成したコンテンツアイテムのページを表示してみます。

うまくいっていれば下図のように 編集モードの場合はインライン編集が行える状態でマークアップが生成されます。

3. RenderingModelを継承してカスタムモデルを作成する場合

カスタムレンダリングを作成するより簡単な方法は IRenderingModel ではなく既定の RenderingModel を継承する方法になります。上記 ProductModel と同じプロパティを持つ ProductModel2 というクラスを次のように定義できます。コードを見ていただければほとんどコードに違いがないことがわかります。ただし、 Initialize の処理は ベースクラスのInitialize メソッドの実装を利用しています。また、 Picture フィールドもサンプルとして FieldRenderer.Render スタティックメソッドにパラメータを渡して マークアップを生成するようにコードを修正しています。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Collections.Specialized;

namespace v72u1.Web.Fx.Models
{
    using Sitecore;
    using Sitecore.Mvc.Presentation;
    using W = Sitecore.Web.UI.WebControls;

    public class ProductModel2 : RenderingModel
    {
        public string Hello { get; set; }
        /// <summary>名前</summary>
        public virtual HtmlString Name
        {
            get
            {
                return new HtmlString(W.FieldRenderer.Render(Item, "Name"));
            }
        }

        public virtual HtmlString Price
        {
            get
            {
                return new HtmlString(W.FieldRenderer.Render(Item, "Price"));
            }
        }
        public virtual HtmlString Picture
        {
            get
            {
                NameValueCollection p = new NameValueCollection();
                p.Add("mw", "100");
                p.Add("mh", "200");
                p.Add("disable-web-editing", "true"); // Page Editor で編集できないようにする場合
                // FIeldRender.Render スタティックメソッドを使用するパターン
                //return new HtmlString(
                //        W.FieldRenderer.Render(Item, "Picture", "mw=100&mh=200&disable-web-editing=true")
                //       );
                return new HtmlString(
                        W.FieldRenderer.Render(Item, "Picture", StringUtil.NameValuesToString(p, "&"))
                       );
            }
        }
        public override void Initialize(Rendering rendering)
        {
            base.Initialize(rendering);
            // 必要であればカスタム実装
        }

    }
}

クラスを定義したら残りのモデルの定義アイテムを作成したりMVCで実装した レイアウトやビューレンダリングでカスタムモデルを使用する方法は全く同じになります。

4. 作成したカスタムモデルをコントローラーレンダリング内で使用する

本例で作成したカスタムモデルやRenderingModel をコントローラレンダリング(Controllerクラス)のアクションメソッドで使用できます。作成したカスタムモデルをPartialView に渡すこともできます。例えば 次のようにアクションメソッドを実装します。

    public class TestController : Controller
    {
        public ActionResult Hello()
        {
            ProductModel model = new ProductModel();
            model.Initialize(RenderingContext.Current.Rendering);

            return PartialView("Hello", model);
        }
    }

Hello.cshtml パーシャルページ (cshtml) で次のようにモデルクラスを使用します。

@model v72u1.Web.Fx.Models.ProductModel

<div>
    @Model.Picture<br />
    @Model.Name<br />
    @Model.Price
</div>

5.まとめ

説明は以上です。誤りや指摘点があればご連絡ください。カスタムモデルを作成することでRenderingModel を使用する単純なビューレンダリングよりも複雑な処理をモデルクラス内に実装できるようになります。