wiki.zope.jp
CMFPortalPollTutorial
   
RecentChanges WikiHelp WikiPractice JumpSearch

CMFPortalPollTutorial

(訳注:Zopeの一般的なプロダクトではなくて、CMF上にプロダクトを作る方法についてのチュートリアルです。ステップ・バイ・ステップが分かりやすいです。)

目次

おことわり

このドキュメントは、2001年3月29日のニュースであった、CMFの1.0リリースに基づくもので、著者はこれをいつも更新しようと思っています。

このドキュメントに関する質問は、davew@digicool.comかjack@digicool.comへ送ってください。フィードバックを歓迎します。

Portalプロダクトとは何か?

Portalプロダクトとは、Zopeのアド・オンで、Portalの可能性を拡張するものです。PortalプロダクトはPortalのメンバーに以下のいずれか、あるいはすべての機能を持つオブジェクトを作らせることを可能にするものです。

プロダクトを適切なベースクラスから作ることにより、これらの機能のほとんどの利点を得ることができます。

このチュートリアルでは、Portalプロダクト(PortalPoll?)を作ります。ここでのサンプルは、メンバーがオンライン投票を作ることが可能なプロダクトです。それは頑健な検索能力を提供し、ユーザーはキーワードで質問や答えを検索することができます。このチュートリアルのゴールは、プロダクトがPortalプロダクトであるためには何が必要かを示しており、PortalPollプロダクトが実際に何をするのかについてはフォーカスを置いていません。

すべてのPortalコンテントは特定のメタデータを含みます。Portalでサポートされるプロパティの標準のセットは以下のようなものです。

以下のPortalプロパティもportal_catalogにより使われ、ユーザーが興味のあるオブジェクトを検索するために使われます。

PortalプロダクトはPortalコンテントであるとされるオブジェクトを生成します。メンバーはコンテントを作成し、そのコンテントのオーナーになります。また、コンテントはポータルの訪問者が見ることが出来るでしょう。Portalプロダクトはオブジェクトについてのワークフローに従うことができ、それはpendingやpublic、reviewedあるいはprivateなどのstateを持つことができます。

なぜポータルプロダクトを作りたいか? 

ポータルはサイト構築者が効果的にWebサイトをレイアウトし、検索やメンバーシップ、構造を容易にすることを可能にします。ポータル構造なしに加工品を積み上げることに基づくWebサイトはすぐに管理不能に陥ることでしょう。

ポータルオブジェクトは以下の利益をもたらします。

ポータルでないオブジェクトはCMFによって認識されません。あなたのプロダクトはポータルプロダクトとなることに意味がありますか?ポータルのユーザーがあなたのプロダクトのインスタンスを作成することを自分自身に問うてください。そして、もしyesならば、あなたのプロダクトをポータルプロダクトとすることに意味があります。

インストール

Zopeのインストール

CMFのインストール

ソフトウェアディレクトリに展開する(中略)

Zopeの再起動

ポータルの作成

ポータルプロダクトは何を定義しますか?

ポータルプロダクトは多くの機能を受けることが出来ます。いくつかは特定のベースクラスから引き継がれ、いくつかは特定の属性やメソッドを提供します。

1つあなたがしなくてはならないことがあり、それを行うとCMFはあなたのプロダクトのオブジェクトをコンテントとして認識するのですが、それはそれをポータルに登録することです。理想的には、これはportal_types toolを使ってWebを通して行われます。また、あなたのコンテントに大して取ることのできるアクションを定義するためにportal_types toolを使うこともできます。

ステップはシンプルで、以下に従うだけです。

ステップ・バイ・ステップ

このチュートリアルの過去のバージョンでは、いくらかあいまいさがありました。それらを削除しようとして、ここに上でのサンプルが動くようにステップ・バイ・ステップを作りました。このすばらしい情報を提供してくれたgogoに感謝します。(より一般的な名前を使うように少し直してくれました。)

特別な注意

何か問題が起きたら、以下をチェックしてみてください。

チュートリアル・サマリー

ZClassベースのPortalプロダクトを作るプロセスを見てきました。我々が示していないPortalの機能がたくさんあります。lib/python/Products/CMFCoreで定義されているクラスをみて、これらのクラスについて学んでください。良い情報がたくさんあります。

サンプルコード

以下はコードとPortalPollClassのサンプルを形成するものです。必要ならばカット・アンド・ペーストできます。私は、ClassやProductが作成されたときに生成されるデフォルトのコードは含めていません。変更がなされた個所のみ示しています。

クラスの一部であるEditForm(DTMLメソッド)のコードです。このコードの目的はプロダクトをインスタンス化するために必要な情報をユーザから入力してもらうようにすることです。タイトルと質問と答えを聞きます。:

    <dtml-var standard_html_header>
    <form action="./" method="POST" enctype="multipart/form-data">
    <h1 class="DesktopTitle"> Poll </h1>
    <h2 class="DesktopTitle"> Add Content </h2>
    <table width="100%" cellpadding="5">
      <tr>
        <td><b><i>Title:</i></b></td>
      </tr>
      <tr>
        <td><input name="title" size="50" value=""></td>
      </tr>
      <tr>
        <td><p>Please add a question for the poll.</p></td>
      </tr>
      <tr>
        <td><b><i>Question:</i></b></td>
      </tr>
      <tr>
        <td><input name="Question" size="50" value=""></td>
      </tr>
      <tr>
        <td><b><i>Poll Answers: </i></b><br>(One per line.)<br>
            <textarea name="Choices:lines" cols="30" rows="10"></textarea>
        </td>
      </tr>
    </table>
    <table>
      <tr>
        <td width="150">&nbsp;</td>
        <td><p align="right">
              <input type="submit" value=" Finish " name="EditDone:method">
            </p>
        </td>
      </tr>
    </table>
  </form>
  <dtml-var standard_html_footer>

注意:このフォームに入力されると、EditDone(DTMLメソッド)が呼ばれます。そのコードは以下の通りです。:

    <dtml-call "propertysheets.PortalPollPropertySheet.manage_changeProperties(REQUEST)">
    <dtml-call "manage_changeProperties(REQUEST)">
    <dtml-call indexObject>
    <dtml-call "RESPONSE.redirect(URL2+'/folder_contents')">

最初の呼び出しは我々のインスタンスのプロパティを変更することに注意してください。2回目の呼び出しはオブジェクトのタイトルをセットします。3回目の呼び出しは我々のオブジェクトが参照されるようにカタログをアップデートするために必要です。最後に我々のインスタンスを追加した後、ユーザーにfolder_contentsを返します。

addPortalClassPy Pythonスクリプトのコードです。これはportal_typesツールを使ってプロダクトを追加するときに参照されます。:

    Parameter List: id

    return context.manage_addProduct['PortalPollProduct'
           ].PortalPollClass.createInObjectManager(id,context.REQUEST)

注意:これはプロダクトのインスタンスを作ります。

以下のコードは我々のクラスが提供するメソッドです。:

    Method - SearchableText:

    Parameter List:

    return "%s %s %s %s" % (context.Title, context.Description
                            , context.Question, context.Choices)

    Method - embeddedView:

    <dtml-if "REQUEST.has_key('hasVoted')">
      <dtml-if "REQUEST['hasVoted']=='true'">
        <dtml-var embeddedResultsView>
      <dtml-else>
        <dtml-var embeddedVoteView>
      </dtml-if>
    <dtml-else>
      <dtml-var embeddedVoteView>
    </dtml-if>

    Method - embeddedVoteView:

    <table class="embeddedPoll" cellspacing="0" cellpadding="0" border="0" >
      <tr>
        <td width="100%">
          <form action="&dtml-absolute_url;/processEmbeddedVotes" method="post">
            <h3>
              <div class="PollQuestion">
                <dtml-var "Question">
              </div>
            </h3>
            <dtml-in "Choices">
              <div class="PollChoice">
                <dtml-let respIndex="_['sequence-index']">
                  <input type="radio" name="responses" value="Choice&dtml-respIndex;">
                  <dtml-var "_['sequence-item']">
                </dtml-let>
              </div>
            </dtml-in>
            <center><br>
              <input type="HIDDEN" name="origUrl" value="&dtml-URL0;">
              <input type="SUBMIT" name="" value="Vote" align="center">
            </center>
          </form>
          </font>
        </td>
      </tr>
    </table>

    Method - embeddedResultsView:

    <table class="embeddedPoll" cellspacing="0" cellpadding="0" border="0">
      <tr class="PollQuestion">
        <td align="left" colspan="3">
          <dtml-var Question>
        </td>
      </tr>
      <tr><td colspan="3"> </td></tr>
      <dtml-in "Choices">
        <tr>
          <td class="PollEmbeddedAnswer"><dtml-var "_['sequence-item']"></td>
          <dtml-let votes="_['sequence-item']">
            <dtml-let respStr="'Choice' + _.str(_['sequence-index'])">
              <dtml-let numResps="_[respStr]">
                <td class="PollEmbeddedAnswer">
                  <dtml-var "getVoteStr(numResps)">%
                </td>
                <td class="PollGraph">
                  <IMG SRC="&dtml-absolute_url;/redbar" WIDTH=<dtml-var "getVoteStr(numResps)">% 
                       HEIGHT="10" BORDER="0">
                </td>
              </dtml-let>
            </dtml-let>
          </dtml-let>
        </tr>
      </dtml-in>
    </table>

    Method - getVoteStr:

    Parameter List: votes

    if context.TotalVotes:
        return "%.2f" % (100*votes/context.TotalVotes)
    else:
        return "%s" % (votes)

    Method - processEmbeddedVotes:

    <dtml-if "REQUEST.has_key('responses')">
      <dtml-if "_.hasattr(this(), REQUEST['responses'])">
        <dtml-let vote="REQUEST['responses']">
          <dtml-let curVotes="_[vote]+1">
            <dtml-let totVotes="TotalVotes+1">
              <dtml-call "propertysheets.PortalPollPropertySheet.
                         manage_changeProperties({REQUEST['responses']:curVotes})">
              <dtml-call "propertysheets.PortalPollPropertySheet.
                         manage_changeProperties({'TotalVotes':totVotes})">
            </dtml-let>
          </dtml-let>
        </dtml-let>
      </dtml-if>
    </dtml-if>
    <dtml-var "RESPONSE.redirect(REQUEST['origUrl']+'?hasVoted=true')">

    Method - view:

    <dtml-var standard_html_header>
    <div class="Desktop">
      <div class="PortalPoll">
        <dtml-var content_byline>
        <dtml-var embeddedView>
      </div>
    </div>
    <dtml-var standard_html_footer>

    Method - viewResults:

    <dtml-var standard_html_header>
    <div class="Desktop">
      <div class="PortalPoll">
        <dtml-var content_byline>
        <dtml-var embeddedResultsView>
      </div>
    </div>
    <dtml-var standard_html_footer>

我々のサンプルで定義されているActionsには以下のものがあります。:

    || Name         ||  Action             ||  Permission            ||  Category ||
    || View         ||  view               ||  View                  ||  object   ||
    || View Results ||  viewResults        ||  View                  ||  object   ||
    ||  Metadata    ||  metadata_edit_form ||  Modify portal content ||  object   ||

我々のサンプルで定義されているプロパティは以下のものです。:

    || Name       || Type   || Explanation                           || 
    || Question   || String || The Question for the POLL.            || 
    || Choices    || lines  || A list of the Answers, one per line.  || 
    || TotalVotes || int    || Total count of all votes.             || 
    || Choice0    || int    || Count of times this choice voted for. || 
    || Choice1    || int    || Count of times this choice voted for. || 
    || Choice2    || int    || Count of times this choice voted for. || 
    || Choice3    || int    || Count of times this choice voted for. || 
    || Choice4    || int    || Count of times this choice voted for. || 
    || Choice5    || int    || Count of times this choice voted for. || 
    || Choice6    || int    || Count of times this choice voted for. || 
    || Choice7    || int    || Count of times this choice voted for. || 
    || Choice8    || int    || Count of times this choice voted for. || 
    || Choice9    || int    || Count of times this choice voted for. ||

Last edited Sat, 09 Sep 2006 19:29:44 +0900 Edit this page