PHP Mentors — Practical Symfony #17: hinclude.jsを使ったWebページのパーツ化

1.5M ratings
277k ratings

See, that’s what the app is perfect for.

Sounds perfect Wahhhh, I don’t wanna

Practical Symfony #17: hinclude.jsを使ったWebページのパーツ化

Symfony Advent Calendar JP 2012 - Day 13


Webページの中で複数ページに共通する部分をパーツ化して別々に作成するというのは、Web制作に関わったことのある方ならどなたでも経験のあることで、よりうまい方法を模索し続けているのではないでしょうか。Web制作ツール側、またはWeb開発フレームワーク側でパーツ化のサポートがいろいろなされてきていますが、デザイナーとプログラマーの双方に受け入れられるバランスの良いものは多くないのではないでしょうか。

hinclude.jsは、パーツ化したWebページの埋め込みをクライアントサイドのみで行うライブラリです。幅広いWebブラウザがサポートされています。特徴は次のようになります。

  • 必要なのはクライアントサイドのJavaScriptファイル1つのみ。サーバー側で特殊なフレームワークやサーバーソフトウェアを用意する必要がない。
  • 埋め込み指定はHTMLタグの拡張なので、外部の言語がHTMLに混ざり込むことがない。
  • 埋め込むコンテンツには特殊な記述が不要。
  • パーツごとにクライアントサイドでのキャッシュが可能。

Warning hinclude.jsの埋め込み処理はAjaxで行われるので、埋め込み動作の確認にはWebサーバー環境が必要になります。

HTMLのみでhinclude.jsをテスト

次のような2つのHTMLを用意します。

index.html
<html xmlns:hx="http://purl.org/NET/hinclude">
  <head>
    <meta charset="utf-8">
    <title>hincludeのテスト</title>
    <script src="hinclude.js" type="text/javascript"></script>
  </head>
  <body>
    <h1>hincludeのテスト</h1>
    <hx:include src="menu.html"></hx:include>
    <h2>本文</h2>
    <p>ここが本文です。メニュー部分はhincludeで埋め込んでいます。</p>
  </body>
</html>
menu.html
<h2>メニュー</h2>
<ul>
  <li>Symfony</li>
  <li>Zend Framework</li>
  <li>Aura</li>
</ul>

同じフォルダにhinclude.jsファイルも配置したら、Webサーバー経由でindex.htmlに対応するURLにアクセスしてみます。次のようにmenu.htmlが埋め込まれた状態の画面が表示されます。

image

Symfonyへのインテグレーション

Symfonyでは2.1からhinclude.jsを使ったWebページのパーツレンダリングがフレームワークに統合されています(FrameworkBundleのHttpKernelクラス)。ESI統合と同じように、テンプレートでrender()関数を使います。render()のstandaloneオプションに"js"を指定すると、hinclude.jsを使ったレンダリングコードが出力されるようになります。HTML単体で埋め込みが動作するという前節で紹介したメリットはなくなりますが、非同期処理によるページレンダリングの体感速度の向上は期待できます。

Example/BlogBundle/Resources/views/Default/index.html.twig
{% extends "::base.html.twig" %}

{% block title %}HInclude Test{% endblock %}

{% block body %}
<h1>HInclude Test</h1>
{% render "ExampleBlogBundle:Default:menu" with {"categoryCode": "sf"}, {"standalone": "js"} %}
{% endblock %}

{% block javascripts %}
  <script src="{{ asset("bundles/exampleblog/js/hinclude.js") }}" type="text/javascript"></script>
{% endblock %}

Note メニューパーツに現在アクティブなカテゴリを知らせるためにcategoryCodeパラメータを渡しています。

Note hinclude.jsファイルはバンドルのResources/public/jsディレクトリに配置しています。app/consoleのassets:installコマンドでwebディレクトリへデプロイします。

この場合、埋め込み自体はクライアント側で行われますが、各パーツもSymfonyアプリケーションでレスポンスするよう用意する必要があることに注意してください。つまり、パーツごとにテンプレートファイルだけでなくアクションメソッドも用意する必要があります。上の例では、menuアクションおよびmenu.html.twigファイルを用意します。

Example/BlogBundle/Controller/DefaultController.php
<php?
    /**
     * @Template()
     */
    public function menuAction($categoryCode)
    {
    	return array('categoryCode' => $categoryCode);
    }
Example/BlogBundle/Resources/views/Default/menu.html.twig
<h2>メニュー</h2>
<ul>
  <li{% if categoryCode == "sf" %} style="font-weight: bold;"{% endif %}>Symfony</li>
  <li{% if categoryCode == "zf" %} style="font-weight: bold;"{% endif %}>Zend Framework</li>
  <li{% if categoryCode == "au" %} style="font-weight: bold;"{% endif %}>Aura</li>
</ul>

これで次のような画面が表示されるようになります。

image

まとめ

SymfonyにはWebページのパーツ化の仕組みが複数搭載されており、HIncludeもそのうちのひとつです。このようなサードパーティライブラリのインテグレーションが、フレームワークに網の目のように食い込んで行われるのではなく、FrameworkBundleのわずかな部分のみで実現されていることも注目すべきポイントです。フレームワークは、自分に合わせて便利にしつつも、基盤として安定していなければなりません。Symfonyでは疎結合なコンポーネントとレイヤー化により、これらの目的を両方同時に達成しています。

参考

symfony practical.symfony hinclude

See more posts like this on Tumblr

#symfony #practical.symfony #hinclude