開発:ブロック

移動先: 案内, 検索

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

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

Moodle 1.9


このドキュメントでは、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 (正確にこのファイル名にしてください)。差し当たり、以下をコピーしてファイルに貼り付けた後、保存してください:

<table cellpadding="9" cellspacing="0">
  <tr valign="top">
    <td align="right">
       <?php print_string('configcontent', 'block_simplehtml'); ?>:
    </td>
    <td>
       <?php print_textarea(true, 10, 50, 0, 0, 'text', $this->config->text); ?>
    </td>
  </tr>
  <tr>
    <td colspan="2" align="center">
      <input type="submit" value="<?php print_string('savechanges') ?>" />
    </td>
  </tr>
</table>
 
<?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に追加してみましょう。さあ、始めましょう:

<tr valign="top">
  <td align="right"><p>
    <?php print_string('configtitle', 'block_simplehtml'); ?>:</p>
  </td>
  <td>
    <input type="text" name="title" size="30" value="<?php echo $this->config->title; ?>" />
  </td>
</tr>

私たちは、編集したファイルを保存して、コースに移動して、ブロックのタイトルを編集して、そして ... 何も起きません! インスタンス設定は、正しく保存され、(念のため再度編集して) すべて問題ありませんが、何も表示されません。単に「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という名称のファイルを作成して、下記内容をコピー&ペーストしましょう:

<div style="text-align: center;">
 <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'); ?>
 <p>
 <input type="submit" value="<?php print_string('savechanges'); ?>" />
 </p>
</div>

私たちのブロック名に忠実なように、十分にシンプルです。これは、「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でも動作するようにするには、こられの名前付けを含めたアップグレードが必要となります。詳細は、(付録Bをご覧くださいをご覧ください。

目の保養 (Eye Candy)

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

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

function hide_header() {
  return true;
}

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

私たちが実施したい、もう一つの調整は、私たちのブロックに画面上での表示幅を教えることです。Moodleは、これを2つのプロセスで処理します: まず最初に、それぞれのブロックに推奨幅を問い合わせて、最大値を望ましい値として記憶します。それから、表示されるページが、この値を使用できるようにするか、こちらが最もあり得るのですが、推奨幅がない場合、特定の範囲の値を取得します。これは、表示幅の設定が最善努力型 (best-effort) の合意であることを意味します。あなたのブロックは、特定の表示幅を「リクエスト」することができます。Moodleは、「リクエスト」された表示幅を提供できるよう「試みます」が、結果に関して、一切保障はありません。具体的な例として、すべての標準的なMoodleコースフォーマットでは、リクエストされた表示幅を、180から210ピクセルの間で提供します。

私たちの推奨幅をブロックに教えるには、さらに1つのメソッドをブロッククラスに追加する必要があります:

function preferred_width() {
  // The preferred value is in pixels
  return 200;
}

これにより、私たちのブロック (およびページの同じ側に表示される、すべてのブロック) は、標準よりも少しだけ幅広くなります。

最後に、私たちのブロック表示に使用される、実HTMLのプロパティに影響を及ぼすことができます。それぞれのブロックは、すべて<table>エレメント内に含まれ、その中で、すべてのHTMLが表示されます。そのコンテナに特定の値を持ったHTML属性を追加するよう、私たちは、Moodleに指示することができます。これは、a) 終了結果に直接影響を及ぼす (例えば、bgcolor="black" を割り当てます)、または、b) CSSを使って、終了結果をカスタマイズする自由を私たちに与える CSS (実際のところ、これは下記のようにデフォルトで実施されます)、いずれかの方法を取ることができます。

私たちの場合、この機能のデフォルトの動作は、ブロックのコンテナに属性「sideblock block_simplehtml」(接頭辞 "block_" の次に私たちの小文字ブロック名が続きます) を持ったHTMLクラスを割り当てることです。そして、このブロックの視覚的スタイルを変更するため、そのクラスを使用して、私たちのテーマ内にCSSセレクタを作成することができます (例えば、".sideblock.block_simplehtml { border: 1px black solid}")。

デフォルトの動作を変更するには、私たちは、属性名および値の連想配列を返すメソッドを定義する必要があります。例えば、このバージョンでは、

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

Javaスクリプトを使用したマウスオーバーイベントが、HTML内で「onmouseover="alert(...)"」と記述するのと同じように、私たちのブロックに追加されます。ここで留意すべき点は、私たちがクラス属性をセットする部分を複製することです (私たちは、この属性を保持したいと思います。また、デフォルトの動作をオーバーライドするため、必要であればエミュレートすることが、私たちの責任です)。

そして、最後にエレガントな手法は、ハードコードされた値「block_simplehtml」にクラスを設定せず、私たちのブロック名に動的に合致させるため、代わりに name()メソッドを使用することです。

認証ユーザのみ

ある状況において、ブロックが非常に有用であることを想像することは、難しいことではありません。しかし、他のユーザにとって意味あるブロックを作成することは、非常に難しいことです。この例として、ソーシャルフォーマットのコースにとって、非常に使いやすい「社会活動」ブロックがあります。しかし、このブロックは、ウィークリーフォーマットに関して、全く有用なことは実現できません。そのようなブロックは、本当に意味がある場合のみ、使用を許可するという考え方があるでしょう。そして、ブロックの使用に意味がない場合、ユーザを混乱させるべきではありません。

Moodleでは、どのコースフォーマットでブロックを表示できるか、宣言することができます。そして、ブロック開発者から設定された、この制限を常に強制することができます。この情報は、ページフォーマットに対応するキーおよび、そのページフォーマットでブロックが表示可能かどうか宣言するブール値 (true/false) の定義を持った連想配列として、Moodleに提供されます。

上の段落では、意図的に用語「コース」の代わりに「ページ」を使っていることに注意してください。この理由は、Moodle 1.5以降、ブロックは、サポートされているどのページにも表示できるからです。そのようなページの最良の例は、コースページですが、私たちは、コースページに限定するわけではありません。例えば、小テスト表示ページ (私たちが小テスト名をクリックした後、表示される最初のページ) でも、ブロックをサポートします。

私たちがページに使用できるフォーマット名は、実際にページを表示するために使用されるスクリプト名に由来します。例えば、コースでは、そのスクリプトは、/course/view.php (これは、ブラウザのアドレス行で判断できます) となります。従って、そのページのフォーマット名は、course-viewとなります。小テストビューページのフォーマット名は、mod-quiz-viewであると簡単に導くことができます。しかし、サムネイルに関するルールには、少しだけ例外があります:

  1. Moodleフロントページのフォーマット名は、site-indexです。
  2. コースのフォーマット名は、実際には、course-viewだけでなく、course-view-weekscourse-view-topics等です。
  3. そのようなページがないとしても、フォーマット名allを包括的なオプションとして使用することができます。

適用可能なフォーマット定義中で、私たちが必要なだけ、フォーマット名を含むことができます。それぞれのフォーマットを許可、不許可にすることができます。また、「このブロックは、このページで許可されますか?」という問題を解決を手助けするため、さらに3つのルールがあります:

  1. フォーマット名の接頭辞は、そのフォーマット名と合致します。例えば、modは、活動モジュールと合致します。course-viewは、コースフォーマットに関わらず、すべてのコースに合致します。そして、最後に、siteは、フロントページと合致します (フルフォーマット名は、site-indexであることを記憶してください)。
  2. 私たちのページに合致するよう、フォーマット名を特化するほど、ブロックが許可される場合の決定に関する優先度が高くなります。例えば、modmod-quizおよびmod-quiz-viewすべて、小テストのビューページに合致します。3つの名称すべてが存在する場合、合致の度合いが高いため、mod-quiz-viewが優先権を得ます。
  3. 文字 * は、言葉のどのような場所にも使うことができます。例えば、mod および mod-* は、同等です。このドキュメント執筆時点では、この「ワイルドカード合致」機能を使用する実際の理由はありませんが、将来的な利用のため存在していると考えてください。
  4. フォーマット名が表示される順番は関係ありません。

上記すべては、状況を複雑にするのに十分です。そのため、いくつかの具体例を見てみましょう。まず第一に、私たちのブロックをサイトフロントページのみに表示するため、下記の関数を使用します:

function applicable_formats() {
  return array('site' => true);
}

allが存在しないため、ブロックは「すべて」のコースフォーマットでは表示されません。しかし、siteにTRUEが設定されているため、サイトフロントページで表示されることが明確に許可されています (接頭辞により、siteは、site-indexに合致することを記憶してください)。

別の例として、ソーシャルフォーマットを除き、すべてのコースフォーマットで、ブロックを表示したい場合、また、コース以外では表示を「許可したくない」場合、私たちは次のように記述します:

function applicable_formats() {
  return array(
           'course-view' => true, 
    'course-view-social' => false);
}

今回、私たちは、すべてのコースでブロックの表示を許可して、ソーシャルフォーマットでの表示を許可しません。最後に最も複雑な例。サイトフロントページ、コース (ソーシャルコースではなく) そしてまた、小テストを除いて、すべての活動モジュールの表示時に、ブロック表示をサポートします。これは、次のようになります:

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

最終結果の決定に「ベストマッチ」ポリシーがあることを私たちが記憶していれば、上記目標達成を理解することは難しくありません。

UPDATING:
前のバージョン1.5では、ブロックはコース内のみで許可されていました (そして、Moodle 1.4では、サイトフロントページのみ)。その当時、有効なコースフォーマットを記述するキーワードは、若干異なっていました。また、さらにオープンアーキテクチャを許可するため、変更する必要がありました。古いブロックを新しい標準に適合させるための修正情報に関して、 Appendix Bをご覧ください。

リストおよびアイコン

このガイドの最後の部分では、私たちは、Moodleブロックの追加的な機能に関して、短く論じてみます。明確に言うと、ユーザに対して、選択可能なリストを表示するブロックを非常に簡単に作成することのできる機能です。このリストでは、1行あたり1アイテム表示されます。また、アイテムの横に任意のイメージ (アイコン) を置くことができます。このような「リストブロック」の例は、このセクションで論じるすべての点を標準的に含む、Moodle「管理」ブロックです。

今までのところ、私たちが見てきたように、ブロックは、 $this->contentに関して、次の2つのプロパティを使います:「text」および「footer」。「text」は、そのままブロックのコンテンツとして、また、「footer」は小さなサイズのフォントで、コンテンツの下に表示されます。リストブロックは、$this->content->footerを全く同じように使用しますが、$this->content->textは、無視します。

代わりにMoodleは、 get_content()がコールされる場合、そのようなブロックに次の2つのプロパティを設定することを要求します: $this->content->items および $this->content->icons です。$this->content->itemsは、表示されることになるリスト内アイテムそれぞれのHTMLを含む数値索引配列である必要があります。通常、これらのタグは、ページのリンクを提供するHTMLアンカータグです。また、$this->content->iconsも$this->content->itemsと明確に同じ数のアイテムを持った数値索引配列である必要があります。これらのアイテムは、「src」「height」「width」および「alt」属性を持った、省略なしのHTML <img>タグである必要があります。もちろん、イメージを小さく、かつ均一なサイズにすることには意味があります。

私たちが標準的なテキストブロックの代わりにリストブロックを置きたいことをMoodleに伝えるには、ブロッククラス定義を少しだけ修正する必要があります。クラスblock_baseを拡張する代わりに、私たちのブロックは、クラスblock_listを拡張します。例えば以下のようになります:

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:


加えて,この変更をするためには,当然のことながら,上で議論した $this->content 変数を get_content() に対して修正して,変更し なくてはなりません.


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;
}

要約すると、私たちがテキストブロックの代わりに、リストブロックを作成したい場合、ブロッククラス定義および get_content()メソッドを変更する必要があります。私たちが前述した必須の init()メソッドを追加することで、私たちの最初のリストブロックをすぐに作成することができます!

トップページに戻る

Moodle 2.0


Moodle 2.0

付録

付録は別々のページに移動されました: