「開発:ブロック」の版間の差分

提供:MoodleDocs
移動先:案内検索
346行目: 346行目:
ここでもう一つ: 私たちは、空のタイトルをブロックの[[開発:ブロック/付録A#init.28.29| init()]]メソッドに設定することはできません。すべてのインストール済みブロックで、Moodleが異なるタイトルを使用できるよう、[[開発:ブロック/付録A#init.28.29| init()]]がコールされた後、それぞれのブロックがユニークなタイトルを持つ必要があります。
ここでもう一つ: 私たちは、空のタイトルをブロックの[[開発:ブロック/付録A#init.28.29| init()]]メソッドに設定することはできません。すべてのインストール済みブロックで、Moodleが異なるタイトルを使用できるよう、[[開発:ブロック/付録A#init.28.29| init()]]がコールされた後、それぞれのブロックがユニークなタイトルを持つ必要があります。


Another adjustment we might want to do is instruct our block to take up a certain amount of width on screen. Moodle handles this as a two-part process: first, it queries each block about its preferred width and takes the maximum number as the desired value. Then, the page that's being displayed can choose to use this value or, more probably, bring it within some specific range of values if it isn't already. That means that the width setting is a best-effort settlement; your block can ''request'' a certain width and Moodle will ''try'' to provide it, but there's no guarantee whatsoever about the end result. As a concrete example, all standard Moodle course formats will deliver any requested width between 180 and 210 pixels, inclusive.
私たちが実施したい、もう一つの調整は、私たちのブロックに画面上での表示幅を教えることです。Moodle handles this as a two-part process: first, it queries each block about its preferred width and takes the maximum number as the desired value. Then, the page that's being displayed can choose to use this value or, more probably, bring it within some specific range of values if it isn't already. That means that the width setting is a best-effort settlement; your block can ''request'' a certain width and Moodle will ''try'' to provide it, but there's no guarantee whatsoever about the end result. As a concrete example, all standard Moodle course formats will deliver any requested width between 180 and 210 pixels, inclusive.


To instruct Moodle about our block's preferred width, we add one more method to the block class:
To instruct Moodle about our block's preferred width, we add one more method to the block class:

2009年8月5日 (水) 15:45時点における版

作成中です - Mitsuhiro Yoshida 2009年5月28日 (木) 15:39 (UTC)

ブロックの作成に関するステップバイステップガイド

原作者: Jon Papaioannou (pj@moodle.org)

このドキュメントでは、Moodleで使用する独自のブロックを開発したい開発者のためのガイドを提供します。ブロックサブシステムは、1.5リリースのため書き換えられ、拡張されたので、このドキュメントは、1.5開発バージョンのMoodle (およびすべての新しいバージョン) のみに適用されます。しかし、あなたがMoodle 1.3および1.4のために書かれたブロックを修正したい場合、最新のバージョンに関するドキュメントを有用だと思うでしょう (付録Bをご覧ください)。

このガイドは、任意のHTMLを表示できる、設定可能な多目的ブロックの開発を目標としたインタラクティブコースのために執筆されています。また、Moodleまたは一般的なプログラミングに関する多少の経験のある人を対象として、Moodleのブロックを作成することがいかに簡単であるか示すことを目標とします。しかし、少しのPHPプログラミングの知識を必要とします。

メインガイドでは、ドキュメントに関する純粋な情報に焦点が置かれていないため、経験豊富な開発者および参考文献のみ閲覧したい人は、 付録Aをご覧ください。

基本コンセプト

このガイドを通じて、私たちは、ほとんどのブロックの特徴を自由に実演するため、HTMLブロックをスクラッチから作成してみます。私たちのブロックには、「SimpleHTML」というブロック名をつけます。このブロック名は、私たちのブロックが実際に保存されるサーバの実ディレクトリ名に関して、同じディレクトリ名を強制することはありません。しかし、一貫性を保持するため、「simplehtml」を使用することで、Moodleの開発において、どのような場合でも要求される小文字の名前付けに従います。

「simplehtml」を含んだ名称のファイルまたはディレクトリを参照する場合は、常に私たちが変更する部分は「simplehtml」のみだと記憶に留めることが重要です。残りは、Moodleが正常に動作するため必要な標準化された部分です。

このガイドでファイルパスを参照する場合、常にスラッシュ (/) から始まります。これは、Moodleホームディレクトリを参照します。また、すべてのファイルおよびディレクトリは、Moodleホームディレクトリに対して参照されます。

レディ、セット、ゴー!

最も基本的な場合、Moodleで「ブロック」を定義するためには、1つのソースコードファイルのみ必要です。ディレクトリ「/blocks/simplehtml」を作成して、その中に私たちのコードを保持する「block_simplehtml.php」というファイルを作成します。それから、私たちは、ブロックのコーディングを始めます:

<?php class block_simplehtml extends block_base {

 function init() {
   $this->title   = get_string('simplehtml', 'block_simplehtml');
   $this->version = 2004111200;
 }
 // 次のセクションで、もうひとつの関数が定義されるので、PHPタグおよびクラス定義の丸括弧が閉じられています。

最初の1行は、ブロッククラス定義です。これは、表示されているのと同じ様式で記述する必要があります。もう一度、「simplehtml」の部分のみ変更することができます (また、そうすべきです)。他のすべては標準化されています。

そして、私たちのクラスは、小さなメソッドを与えられます: init()。これは、すべてのブロックに必要なメソッドであり、内部に2つのクラスメンバ変数を設定することが目的です。しかし、これらの変数の本当の意味は何でしょう? 詳細は、下記をご覧ください。

$this->titleは、私たちのブロックヘッダに表示されるタイトルです。私たちは、どのうなタイトルでも設定することができます。この場合、恐らくブロックと共に提供される言語ファイルから実際のタイトルが取得されます。あなたがブロックタイトルに何も「表示したくない」場合、ここに説明的な値を入力してください (しかし、空のストリングにはしないでください)。では、先に進みましょう。タイトルを表示しない方法に関して、後ほどタイトル表示を無効にする方法を参照します。

$this->versionは、私たちのブロックのバージョンです。実際には、あなたのブロックがデータベースの特別テーブルに独自のデータを保持したい場合のみ重要です (例 非常に複雑なブロック)。その場合、バージョンナンバーは、活動で使用されるのと全く同じように使用されます。「古い」バージョンのブロックデータを最新のデータに増分アップグレードするため、バージョンナンバーはアップグレードスクリプトが使用します。ブロックは比較的シンプルで自データを保持しない傾向にありますので、私たちは、この処理に関する概要を後で説明します。

私たちの例では、正に前述の例に該当しますので、 $this->versionYYYYMMDD00をセットして、後は忘れることにします。

アップデート:
バージョン 1.5以前では、それぞれのブロッククラスの基本構造は、若干異なっていました。古いブロックを新しい標準に準拠させるための変更に関して、詳細は 付録Bをご覧ください。

私には雑音 (Static) が聴こえるだけ

ブロックが画面で何かを表示するために、私たちは、さらに1つのメソッドを (右中括弧が閉じる前に) クラスに追加する必要があります。新しいコードは以下のとおりです:

 function get_content() {
   if ($this->content !== NULL) {
     return $this->content;
   }
   $this->content         =  new stdClass;
   $this->content->text   = 'The content of our SimpleHTML block!';
   $this->content->footer = 'Footer here...';

   return $this->content;
 }

} // Here's the closing curly bracket for the class definition

   // and here's the closing PHP tag from the section above.

?>

これよりシンプルになりません、でしょ? 何が起きるか、このメソッドを解剖してみましょう ...

まず第一に、値がNULLではない場合、 $this->contentの現在値を返すチェックがあります。そうでない場合、私たちはこの値を計算し始めます。計算には、潜在的に多大な時間を要して、それぞれのブロックで複数回コールされるため (そのようにMoodleが内部で動かします)、私たちは予防措置として、この時間節約の手段を含むようにします。コンテンツが計算されていない場合 (NULLの場合)、私たちは最初から定義します。そこでは、コード自体が語りますので、それほど語ることはありません。必要であれば、私たちは、HTMLをテキストおよびフッタで使用できるということに留意してください。

この時点で、私たちのブロックは、Moodleに自動的にインストールされ、コースに追加することができます。管理ページに移動して、ブロックのインストール (サイト管理ブロック内の「通知」をクリック) を確認した後、このチュートリアル (ドキュメント) に戻ってください。

設定しよう

私たちのブロックの現在のバージョンでは、それほど多くのことはできません。非常に有用だとは言えない固定メッセージを表示するのみです。私たちが本当にやりたいことは、教師がブロック内に入れるものをカスタマイズできるようにすることです。このブロックとの会話は、「インスタンス設定」と呼ばれます。それでは、私たちのブロックにインスタンス設定を与えてみましょう ... まず第一に、私たちはMoodleに対して、私たちのブロックにインスタンス固有の設定装備を提供したいと伝える必要があります。 これは、私たちのブロッククラスに、もうひとつのメソッドを追加するのと同じくらい簡単です:

function instance_allow_config() {

 return true;

}

すべてのコースにおいて、「編集モードの開始」ボタンをクリックした場合、私たちのブロックのヘッダに「編集 ...」アイコンを表示するには、少しの修正のみで十分です。しかし、あなたがそのアイコンをクリックした場合、ブロック設定が正しく実装されていない旨、警告が表示されてしまいます。挑戦してみましょう、安全です。Moodleの苦情は当然です。私たちは設定を必要だと伝えたのに、「どのような」設定が欲しいのか伝えていませんし、また何を表示したいかも伝えていません。そのためには、さらに1つのファイルを作成する必要があります: /blocks/simplehtml/config_instance.html (ファイル名は、正確にこのファイル名にしてください)。差し当たり、以下をコピーしてファイルに貼り付けた後、保存してください:

      <?php print_string('configcontent', 'block_simplehtml'); ?>:
      <?php print_textarea(true, 10, 50, 0, 0, 'text', $this->config->text); ?>
     <input type="submit" value="<?php print_string('savechanges') ?>" />

<?php use_html_editor(); ?>

上記コードを読む限り、WYSIWYGエディタが有効にされたtextareaで私たちのブロックの必要なコンテンツを記述して、保存ボタンをクリックすることは難しいことではありません。しかし ... $this->config->text とは何でしょう? そうですね ... Moodleでは、ブロック開発者がブロックを簡単に開発できるようにしています。実際には、textareaが「text」と名前付けされていることに気付きましたか? 送信ボタンがクリックされた場合、Moodleはconfig_instance.htmlファイルで探すことのできる、すべてのフィールドを設定データのインスタンスとして保存します。

そして、私たちは$this->config->variablenameとしてデータにアクセスすることができます。ここで「variablename」は、私たちのフィールドに使用する実フィールド名です。この場合、"text"となります。ですから、基本的に上記のフォームでは、現在のブロックコンテンツ (そのまま) と共にテキストエリアをプレ実装して、私たちがコンテンツを変更できるようにします。

あなたは、送信ボタンの存在して、<form>エレメントが存在しないことにも驚いていることでしょう。しかし、私たちは全く心配する必要がないことが真実です。長期間に渡り、Moodleは開発者が簡単に開発できるよう、発展してきました! 私たちに必要なことは、どのようなフォーマットであれ、送信ボタンを含んだ必要な設定オプションを表示することです。Moodleは、残りのすべてを自ら処理します。インスタンス設定変数は、 init()以外、自由にすべてのクラスメソッドからアクセスすることができます。

イベントのデフォルトの動作に満足できない場合、私たちはオーバーライドすることができます。しかし、オーバーライドするためには、私たちのブロックに関して、高度な修正が必要であり、ここでは取り上げられていません。詳細は、 付録Aをご覧ください。 $this->configを通して、このインスタンス設定データを参照できるようになります。最後の工夫は、私たちのブロックに対して、設定データに保存された内容を「表示すること」を実際に伝えることです。伝えるには、/blocks/simplehtml/block_simplehtml.phpの中で、このスニペットを見つけてください:

$this->content = new stdClass;
$this->content->text   = 'The content of our SimpleHTML block!';
$this->content->footer = 'Footer here...';

そして、以下のように変更します:

$this->content = new stdClass;
$this->content->text   = $this->config->text;
$this->content->footer = 'Footer here...';

おや、この時点でフッタは実際に存在していません。役立つことはありませんので、私たちのブロックからフッタを取り除きます。私たちは、上記と同じように簡単にフッタ設定を決定することができます。ですから、私たちの最新のコード、スニペットは以下のようになります:

$this->content = new stdClass;
$this->content->text   = $this->config->text;
$this->content->footer = ;

このディスカッションの後、私たちのブロックはゴールデンタイムに入ります! 本当に、あなたが、SimpleHTMLブロックを設置したコースに移動すると、コンテンツの修正は簡単だということを目の当たりにすることでしょう。

トップページに戻る

スペシャリスト

ブロックコンテンツのインスタンス設定の実装は、私たちの食欲を満たすには十分でした。しかし、誰がそこで止めたいですか? なぜ、ブロックタイトルもカスタマイズしないのですか?

本当に、なぜ。さて、これに到達するための、私たちの最初の試みは、極めて普通です。/blocks/simplehtml/config_instance.htmlに別のフィールドを追加してみましょう。さあ、始めましょう:

<?php print_string('configtitle', 'block_simplehtml'); ?>:

   <input type="text" name="title" size="30" value="<?php echo $this->config->title; ?>" />

私たちは、編集したファイルを保存して、コースに移動して、ブロックのタイトルを編集して、そして ... 何も起きません! インスタンス設定は、正しく保存され、(念のため再度編集して) すべて問題ありませんが、何も表示されません。単に「SimpleHTML」タイトルが表示されるだけです。 少しだけ戻って考えてみれば、これは、とても奇妙だということではりません。私たちが$this->titleで設定したinit() メソッドを覚えていますか? 実際、それから私たちは、その設定値を変更していません。また、$this->titleは、当然$this->config->title (少なくともMoodle) と同じではありません。私たちに必要なことは、$this->titleのインスタンス設定の値を更新することです。しかし、少し前に述べたように、私たちは、init()を除くすべてのメソッドで、 $this->configを使用することができます! では、私たちには何ができるのでしょうか? 私たちの袖から別のエースを取り出してみましょう。そして、この小さなメソッドを私たちのブロッククラスに追加してみましょう: function specialization() { if(!empty($this->config->title)){ $this->title = $this->config->title; }else{ $this->config->title = 'Some title ...'; } if(empty($this->config->text)){ $this->config->text = 'Some text ...'; } } なるほど、私たちが最初からずっとやりたかったことですね! しかし、 specialization() メソッドで何が起こるのでしょう? 「魔法の」メソッドは、実際に極めて素晴らしい特性を持っています。私たちのインスタンス設定がロードされ、利用されるようになるとすぐに (つまり、init()がコールされるとすぐに)、Moodleから自動的にコールされることが「保証」されています。これは、ブロックコンテンツが最初に計算されること、そして本当にブロックに関して、何らかの処理が実行される前を意味します。従って、この場合、「可能な限り速やか」に実行される、すべてのデータ設定に関して specialization() メソッドを提供することは、自然な選択と言えます。

あなたには私が見える、そして、あなたには私が見えなくなる (Now You See Me, Now You Don't)

さて、ブロックで使用することのできる、別の素晴らしいテクニック、そして、かなり頻繁に役立つテクニックに関して、話すのに良い時間になりました。特に、時々私たちのブロックは興味深いものを表示します。しかし、有益ではないものを表示する場合もあります (例えば、「最近の活動」ブロックで実際に表示するものがない場合です)。

しかし、この場合、ブロックは前述の活動の欠如に関して、あなたに明確に伝えることを選んだわけで、これはほぼ間違いなく有用ではあります。そして、表示する必要のないブロックを「非表示にする」ことは、素晴らしいことです。

これは、実際に可能です。その方法は、 get_content() メソッドがコールされた後、ブロックの中身が完全にないようにすることです。具体的に「中身がない」とは、$this->content->textおよび$this->content->footerThisの両方が、それぞれ空のストリング ('') になっていることです。Moodleは、 is_empty() メソッドをコールすることにより、この状態を確認します。そして、ブロックが実際に空の場合、実際に全く何も表示されません。

ブロックタイトルの実際の値、 hide_header() メソッドの存在の有無は、この動作に影響を及ぼしませんので留意してください。コンテンツがない場合、他の内容に関わらず、ブロックは空であると判断します。

私たちは軍団

現在、私たちのブロックはタイトルおよびコンテンツに関して、完全に設定可能な状態です。実際のところ、私たちは非常に殆どのことを実現することができます。1つのコースに同一ブロックを複数追加することができることは大変素晴らしいことです。そして、あなたが推測するように、このようにすることは、私たちのブロックに別の小さなメソッドを追加するくらい非常に簡単です:

function instance_allow_multiple() {

 return true;

}

これにより、すべてのコースにおいて、MoodleはSimpleHTMLブロックのインスタンスをいくらでも設置することができます。私たちのファイルの変更を保存した後、さらなる騒動なしで、即座に複数のブロックをMoodleで追加することができるようになります!

ここで言及すべき、いくつかの興味深い点があります。まず第一にブログ自体で同一ページに複数インスタンスを許可したとしても、管理者には、そのような挙動を許可しないオプションがあります。この設定は、それぞれのブロックから分離され、「サイト管理 > プラグイン > ブロック > ブロックの管理」にて変更することができます。

そして最後に素晴らしい内容です。私たちが instance_allow_multiple() メソッドを定義するとすぐに、すでに定義されている instance_allow_config() メソッドは、廃止されてしまいます。

ブロックに関して、複数インスタンスが許可された場合、「ブロックは設定したいはず」とMoodleは考えます (ブロックが同じ種類の場合、同じページに複数ブロックインスタンスを設置する時のポイントは何でしょう?)。従って、Moodleは自動的に「編集」アイコンを提供します。ですから、私たちは、すべての instance_allow_config() メソッドを実害なしに取り除くことができるのです。ブロックの複数インスタンスが許可されていない場合のみ、私たちは当該メソッドが必要です。

トップページに戻る

グローバリゼーションの効果

それぞれのブロックインスタンスを独自のパーソナルデータで設定することは、十分に素晴らしいのですが、時々管理者は、特定のブロックに関して、同時にすべてのインスタンスを「触る」方法を必要とするものです。私たちのSimpleHTMLの場合、少しの設定をすべてのインスタンスに適用することは道理にかなっていますし、考え付くことが困難であるというわけでもありません。

例えば、私たちは、それぞれのブロックのコンテンツを文字のみに制限したり、純粋なテキストを使用するため、ブロックコンテンツからHTMLをフィルタすると良いでしょう。確かに、そのような機能は私たちのブロックのネーミング「SimpleHTML」に何ももたらしません。しかし、悩んだ管理者たちは、どこかに実際に有益な点を見つけることでしょう。

このような設定は「グローバル設定」と呼ばれ、特定のブロックタイプにのみ提供されます (しかし、ブロックタイプのすべてのインスタンスが影響を受けます)。そのような設定を私たちのブロックに実装することは、インスタンス設定の実装に極めて似ています。では、私たちは2番目の例の実装方法を見てみましょう。ここでは、ブロックコンテンツにHTMLではなく、テキストのみ許可するよう設定します。 まず第一に、これは驚くことなのですが、ブロッククラスに小さなメソッドを追加することで、私たちのブロックにグローバル設定を提供したい旨、Moodleに伝える必要があります::

function has_config() {

 return true;

}

それから、実際に設定画面を表示するため、私たちはHTMLファイルを作成する必要があります。私たちのケースでは、「コンテンツにHTMLを許可しない」チェックボックスおよび「送信」ボタンを表示するのみです。それでは、/blocks/simplehtml/config_global.htmlという名称のファイルを作成して、下記の内容をコピー&ペースとしましょう:

<input type="hidden" name="block_simplehtml_strict" value="0" />
<input type="checkbox" name="block_simplehtml_strict" value="1"
  <?php if(!empty($CFG->block_simplehtml_strict)) 
            echo 'checked="checked"'; ?> />
  <?php print_string('donotallowhtml', 'block_simplehtml'); ?>

<input type="submit" value="<?php print_string('savechanges'); ?>" />

私たちのブロック名に忠実なように、十分にシンプルです。これは、「block_simplehtml_strict」という名称のチェックボックスを表示して、Moodle設定変数に同じ名称の値が設定されて (例 $CFG->block_simplehtml_strict) 空白ではない場合、(空白、ゼロまたはブール値のFALSEではない) チェック済みの (現在のステータスを反映した) チェックボックスを表示します。

なぜ、同じ名称の設定をチェックするのですか? グローバル設定のコードを保存するデフォルトでは、私たちのフォームの中にある、すべての変数を取得して、Moodle設定オプションとして同一名で保存するためです。従って、説明的な名称を使うこと、別の設定の名称と衝突する可能性のない名称を使うことは、優れた実践と言えます。

「block_simplehtml_strict」という名称は、明らかに両者の要件を満たします。

目先の利く読者は、実際には「block_simplehtml_strict」という名称の2つの入力フィールドが、私たちの設定ファイルにあることに気付いたことでしょう。1つは隠しフィールドで、その値は常にゼロ、別のフィールドはチェックボックスで、その値は1です。何が起こるのでしょう? なぜ、両方のフィールドがそこにあるのでしょう?

実際のところ、これは私たちの仕事を可能な限り簡単にするための、小さなトリックです。HTMLフォーマットは、次のように動作します: フォーム内のチェックボックスがチェックされていない場合、フォーム送信時、PHPに渡される変数の中にチェックボックスの名称は全く出現しません。これは事実上、私たちがチェックボックスのチェックを外して送信ボタンをクリックした場合、PHPに変数が全く渡されないことを意味します。従って、その値をPHPが「0」に更新する方法を知らないわけで、私たちが最初に「厳密型 (strict)」を有効にした場合、それが無効にされることはありません。もちろん、無効にされることは私たちが望む挙動でもありません。

しかしながら、フォームから受け取った変数をPHPが処理する場合、フォームで表示される順で変数が処理されます。すでに処理されている変数と同一名の変数を受け取った場合、古い値を新しい値がオーバーライトします。これを利用して、私たちのロジックは、次のようになります: 最初、「block_simplehtml_strict」の値には、無条件にゼロが設定されます。それから、チェックボックスがチェックされた場合、前述のように前の値をオーバーライトして、値には「1」が設定されます。最終結果として、設定値は、私たちの希望通りに設定されます。

私たちのトリックのバグに対応するには、「デフォルトでチェックボックスがチェックされているか?」をテストするため、「if(!empty($CFG->block_simplehtml_strict))」が使用されている点に注目してください。このスクリプトが最初に実行された場合、変数$CFG->block_simplehtml_strictは、全く存在していません。そして、最初にその変数が設定された場合、値は「0」または「1」となり得ます。文字列「1」が評価されないのに対して、「設定なし」文字列「0」は両者とも空として評価されます。変数が全く設定されていないというPHPの警告を避けるため、そして可能性のある値 (0または1) に関して、人間に可読可能な素晴らしい表現を持つため、私たちはこの処理を追加しています。

config_save()

私たちは、HTMLの少しの行の中に相当量のトリックを何とか詰め込みました。私たちが念頭に置いている特定の設定に対して、トリックが十分でない場合のことを考えて、代わりの方法を議論した方がよさそうです。メソッド config_save()でデータが保存されているため、デフォルトの実装は、以下のようになります:

function config_save($data) {

 // Default behavior: save all variables as $CFG properties
 foreach ($data as $name => $value) {
   set_config($name, $value);
 }
 return true;

}

コードから明らかなように、Moodleはこのメソッドで、私たちの設定画面から取得できるすべての変数を連想配列「$data」に渡しています。私たちが「同一名の変数を隠す」というトリックなしで処理を実行したい場合、1つの方法は、このメソッドを下記のメソッドでオーバーライドすることです:

function config_save($data) {

 if(isset($data['block_simplehtml_strict'])) {
   set_config('block_simplehtml_strict', '1');
 }else {
   set_config('block_simplehtml_strict', '0');
 }
 return true;

}

極めて直接的: 変数「block_simplehtml_strict」が私たちに渡された場合、これはユーザがチェックしたことだけ意味するため、同じ名称の設定変数に「1」をセットします。そうでない場合、「0」をセットします。もちろん、私たちがさらに設定オプションを追加する場合、デフォルトでは反応しないため、このバージョンを更新する必要があります。さらに、私たちの必要性に合致しない場合、デフォルトの実装をどのようにオーバーライドできるか知ることは有用です (例えば、私たちが変数をMoodle設定の一部として保存せず、その変数で他の処理を実行したい場合)。

そして、私たちは、ブロックがそのコンテンツにHTMLタグを許可べきかどうか知ることのできるポイントまで到着しました。実際、どのようにすれば、ブロックがその設定を留意するようにできるのでしょうか?

私たちは、次のうち1つを実行することができます: インスタンス設定に保存される前、ブロックがHTMLをクリーニングして、現状のまま表示する (「熱心」なアプローチ) または、データをそのまま保存して、表示される前、毎回クリーニングする (「怠惰」なアプローチ)。「熱心」なアプローチでは、設定保存時、1回のみ処理を必要とします。「怠惰」なアプローチでは、ブロックが表示されるたびに処理が必要となります。ですから、パフォーマンスが悪くなってしまいます。そのため、私たちは「熱心」なアプローチに取り組むべきです。

トップページに戻る

instance_config_save()

私たちは、 config_save()をオーバーライドする直前に実行しますが、ここで必要なことは、インスタンスを処理するメソッド、 instance_config_save()をオーバーライドすることです。デフォルトの実装は、以下のようになります:

function instance_config_save($data) {

 $data = stripslashes_recursive($data);
 $this->config = $data;
 return set_field('block_instance', 
                  'configdata',
                   base64_encode(serialize($data)),
                  'id', 
                  $this->instance->id);

}

最初、(stripslashes_recursive()、base64_encode()、serialize()が影響して?) 脅威に感じるかもしれませんが、どうか絶望しないでださい。私たちは、これらのどれも触る必要はありません。私たちは、いくつかのコードを最初の部分に追加して、加えて実際にデータを保存するため、Moodleにこのデフォルトの実装をコールするよう指示します。具体的に言えば、下記のようなメソッドを私たちのクラスに追加します:

function instance_config_save($data) {

 // Clean the data if we have to
 global $CFG;
 if(!empty($CFG->block_simplehtml_strict)) {
   $data->text = strip_tags($data->text);
 }
 // And now forward to the default implementation defined in the parent class
 return parent::instance_config_save($data);

}

とうとう最後です! 現在、管理者は、私たちの「SimpleHTML」ブロックにどのようなタイプのコンテンツを許可するかどうかに関して、絶対的な生死の権限を持つに至りました! 絶対的な? そうですね ... 厳密に言えば違います。実際のところ、暫くの間、私たちがそのことを考えた場合、ある時点でHTMLが許可されて、HTMLを含んだ状態でブロックが保存されます。そして、その後、管理者が設定を「off」にすることにより、その後に続く、HTMLが含まれたコンテンツの変更のみ抑制します。すでにコンテンツにHTMLを含んだブロックでは、表示を継続します!

一連の考えを巡らせながら、しばらく前に「怠惰」なアプローチを選択したのであれば、この問題を経験しないことに気付くことが次の停止位置です。なぜならば、私たちは、それぞれのブロックコンテンツが表示される直前に「サニタイズ」するからです。

私たちが「熱心」なアプローチでやれる唯一のことは、管理設定が「HTML off」に変更された直後に、SimpleHTMLインスタンスすべてのコンテンツからタグすべてを取り除くことです。しかし、その時でさえ、私たちが取り除いたタグは、「HTML on」にしても戻すことはできません。他方、「怠惰」なアプローチは「熱心」なアプローチよりも遅いですが、多目的に使用できます。私たちは、コンテンツを表示する前、HTMLを取り除くか、保持するか選択することができます。そして、管理者が再度設定をONまたはOFFにしたとしても、HTMLを失うことはありません。開発者の人生が、シンプルで素晴らしいものになったと思いませんか?

エクササイズ

私たちは、チュートリアルのこの部分を、読者の強制的なエクササイズで終幕にしましょう: SimpleHTMLブロックを「正常」に動作させるには、「熱心」なアプローチが、私たちのブロックの既存のインスタンス設定すべてのタグを取り除くことを強化する方法を探す、または、戻って、代わりに「怠惰」なアプローチを実装することです。 (ヒント: get_content()メソッドで実行します。)

更新:

Moodle 1.5以前のバージョンでは、ファイルconfig_global.htmlは、単純にconfig.htmlというファイル名が付けられていました。また、メソッド config_saveおよび config_printは、各々handle_configおよびprint_configと名前付けられていました。ブロックがMoodle 1.5でも動作するようにするには、こられの名前付けを含めたアップグレードが必要となります。詳細は、 Appendix Bをご覧ください。

目の保養 (Eye Candy)

私たちのブロックは、ほとんど完璧に動作するようになりました。それでは、さらに何箇所か便利にできるよう、私たちが使用できるトリックを見てみましょう。

私たちのブロックの視覚的側面を調整できる、いくつかの方法があります。まず第一に、ヘッダ (タイトル) を全く表示しないブロックを作成できると便利でしょう。あなたは、この公開をMoodleに実装されている「コース説明」ブロックで見ることができます。この動作は、あなたの想像どおり、私たちのブロッククラスに、さらに1つのメソッドを追加することで実現できます:

function hide_header() {

 return true;

}

ここでもう一つ: 私たちは、空のタイトルをブロックの init()メソッドに設定することはできません。すべてのインストール済みブロックで、Moodleが異なるタイトルを使用できるよう、 init()がコールされた後、それぞれのブロックがユニークなタイトルを持つ必要があります。

私たちが実施したい、もう一つの調整は、私たちのブロックに画面上での表示幅を教えることです。Moodle handles this as a two-part process: first, it queries each block about its preferred width and takes the maximum number as the desired value. Then, the page that's being displayed can choose to use this value or, more probably, bring it within some specific range of values if it isn't already. That means that the width setting is a best-effort settlement; your block can request a certain width and Moodle will try to provide it, but there's no guarantee whatsoever about the end result. As a concrete example, all standard Moodle course formats will deliver any requested width between 180 and 210 pixels, inclusive.

To instruct Moodle about our block's preferred width, we add one more method to the block class:

function preferred_width() {

 // The preferred value is in pixels
 return 200;

}

This will make our block (and all the other blocks displayed at the same side of the page) a bit wider than standard.

Finally, we can also affect some properties of the actual HTML that will be used to print our block. Each block is fully contained within a <table> element, inside which all the HTML for that block is printed. We can instruct Moodle to add HTML attributes with specific values to that container. This would be done to either a) directly affect the end result (if we say, assign bgcolor="black"), or b) give us freedom to customize the end result using CSS (this is in fact done by default as we 'll see below).

The default behavior of this feature in our case will assign to our block's container the class HTML attribute with the value "sideblock block_simplehtml" (the prefix "block_" followed by the name of our block, lowercased). We can then use that class to make CSS selectors in our theme to alter this block's visual style (for example, ".sideblock.block_simplehtml { border: 1px black solid}").

To change the default behavior, we will need to define a method which returns an associative array of attribute names and values. For example, the version

function html_attributes() {

 return array(
   'class'       => 'sideblock block_'. $this->name(),
   'onmouseover' => "alert('Mouseover on our block!');"
 );

}

will result in a mouseover event being added to our block using JavaScript, just as if we had written the onmouseover="alert(...)" part ourselves in HTML. Note that we actually duplicate the part which sets the class attribute (we want to keep that, and since we override the default behavior it's our responsibility to emulate it if required).

And the final elegant touch is that we don't set the class to the hard-coded value "block_simplehtml" but instead use the name() method to make it dynamically match our block's name.

Authorized Personnel Only

It's not difficult to imagine a block which is very useful in some circumstances but it simply cannot be made meaningful in others. An example of this would be the "Social Activities" block which is indeed useful in a course with the social format, but doesn't do anything useful in a course with the weeks format. There should be some way of allowing the use of such blocks only where they are indeed meaningful, and not letting them confuse users if they are not.

Moodle allows us to declare which course formats each block is allowed to be displayed in, and enforces these restrictions as set by the block developers at all times. The information is given to Moodle as a standard associative array, with each key corresponding to a page format and defining a boolean value (true/false) that declares whether the block should be allowed to appear in that page format.

Notice the deliberate use of the term page instead of course in the above paragraph. This is because in Moodle 1.5 and onwards, blocks can be displayed in any page that supports them. The best example of such pages are the course pages, but we are not restricted to them. For instance, the quiz view page (the first one we see when we click on the name of the quiz) also supports blocks.

The format names we can use for the pages derive from the name of the script which is actually used to display that page. For example, when we are looking at a course, the script is /course/view.php (this is evident from the browser's address line). Thus, the format name of that page is course-view. It follows easily that the format name for a quiz view page is mod-quiz-view. This rule of thumb does have a few exceptions, however:

  1. The format name for the front page of Moodle is site-index.
  2. The format name for courses is actually not just course-view; it is course-view-weeks, course-view-topics, etc.
  3. Even though there is no such page, the format name all can be used as a catch-all option.

We can include as many format names as we want in our definition of the applicable formats. Each format can be allowed or disallowed, and there are also three more rules that help resolve the question "is this block allowed into this page or not?":

  1. Prefixes of a format name will match that format name; for example, mod will match all the activity modules. course-view will match any course, regardless of the course format. And finally, site will also match the front page (remember that its full format name is site-index).
  2. The more specialized a format name that matches our page is, the higher precedence it has when deciding if the block will be allowed. For example, mod, mod-quiz and mod-quiz-view all match the quiz view page. But if all three are present, mod-quiz-view will take precedence over the other two because it is a better match.
  3. The character * can be used in place of any word. For example, mod and mod-* are equivalent. At the time of this document's writing, there is no actual reason to utilize this "wildcard matching" feature, but it exists for future usage.
  4. The order that the format names appear does not make any difference.

All of the above are enough to make the situation sound complex, so let's look at some specific examples. First of all, to have our block appear only in the site front page, we would use:

function applicable_formats() {

 return array('site' => true);

}

Since all is missing, the block is disallowed from appearing in any course format; but then site is set to TRUE, so it's explicitly allowed to appear in the site front page (remember that site matches site-index because it's a prefix).

For another example, if we wanted to allow the block to appear in all course formats except social, and also to not be allowed anywhere but in courses, we would use:

function applicable_formats() {

 return array(
          'course-view' => true, 
   'course-view-social' => false);

}

This time, we first allow the block to appear in all courses and then we explicitly disallow the social format. For our final, most complicated example, suppose that a block can be displayed in the site front page, in courses (but not social courses) and also when we are viewing any activity module, except quiz. This would be:

function applicable_formats() {

 return array(
          'site-index' => true,
         'course-view' => true, 
  'course-view-social' => false,
                 'mod' => true, 
            'mod-quiz' => false
 );

}

It is not difficult to realize that the above accomplishes the objective if we remember that there is a "best match" policy to determine the end result.

UPDATING:
Prior to version 1.5, blocks were only allowed in courses (and in Moodle 1.4, in the site front page). Also, the keywords used to describe the valid course formats at the time were slightly different and had to be changed in order to allow for a more open architecture. Refer to Appendix B for more information on the changes that old blocks have to make to conform to the new standard.

Lists and Icons

In this final part of the guide we will briefly discuss an additional capability of Moodle's block system, namely the ability to very easily create blocks that display a list of choices to the user. This list is displayed with one item per line, and an optional image (icon) next to the item. An example of such a list block is the standard Moodle "admin" block, which illustrates all the points discussed in this section.

As we have seen so far, blocks use two properties of $this->content: "text" and "footer". The text is displayed as-is as the block content, and the footer is displayed below the content in a smaller font size. List blocks use $this->content->footer in the exact same way, but they ignore $this->content->text.

Instead, Moodle expects such blocks to set two other properties when the get_content() method is called: $this->content->items and $this->content->icons. $this->content->items should be a numerically indexed array containing elements that represent the HTML for each item in the list that is going to be displayed. Usually these items will be HTML anchor tags which provide links to some page. $this->content->icons should also be a numerically indexed array, with exactly as many items as $this->content->items has. Each of these items should be a fully qualified HTML <img> tag, with "src", "height", "width" and "alt" attributes. Obviously, it makes sense to keep the images small and of a uniform size.

In order to tell Moodle that we want to have a list block instead of the standard text block, we need to make a small change to our block class declaration. Instead of extending class block_base, our block will extend class block_list. For example:

class block_my_menu extends block_list {
    // The init() method does not need to change at all
}

In addition to making this change, we must of course also modify the get_content() method to construct the $this->content variable as discussed above:

function get_content() {

 if ($this->content !== null) {
   return $this->content;
 }

 $this->content         = new stdClass;
 $this->content->items  = array();
 $this->content->icons  = array();
 $this->content->footer = 'Footer here...';

 $this->content->items[] = '<a href="some_file.php">Menu Option 1</a>';
 $this->content->icons[] = '<img src="images/icons/1.gif" class="icon" alt="" />';

 // Add more list items here

 return $this->content;

}

To summarize, if we want to create a list block instead of a text block, we just need to change the block class declaration and the get_content() method. Adding the mandatory init() method as discussed earlier will then give us our first list block in no time!

トップページに戻る

付録

The appendices have been moved to separate pages: