CMS Hub

HubLの変数の値を、他の変数の呼び出しに使う(evalっぽいハック)

いわゆる、eval的な挙動になります。あまり文章で説明してもピンと来づらいと思いますので、実際の使用例を先にご紹介します。始めに断っておくと、あまり推奨できる方法ではありません。

例えば次のような構造のデータからnameの値を抽出する場合、普通は次のようにforループを回します。

 
  1. {% set offices = [
  2. {
  3. name: '東京オフィス'
  4. },
  5. {
  6. name: '札幌オフィス'
  7. }
  8. ] %}
  9.  
  10. {%- for item in offices -%}
  11. {{ item.name }}
  12. {%- endfor -%}
出力結果
 
  1. 東京オフィス
  2. 札幌オフィス

ここまでは何も問題ありません。では、forループ内でオフィス名を出力している「item.name」の「name」をハードコードしないで出力したい場合、どうすればよいでしょうか?

目次

基本となるコード

今回は仮に「name」というkeyが、「name_key」という変数に値として格納されているとしましょう。雰囲気的には次のような感じですが、当然次のコードは動きません。

  
  1. {% set name_key = 'name' %}
  2. {% set offices = [
  3. {
  4. name: '東京オフィス'
  5. },
  6. {
  7. name: '札幌オフィス'
  8. }
  9. ] %}
  10.  
  11. {%- for item in offices -%}
  12. {{ item.name_key }} {# この呼び出し方では当然動かない #}
  13. {%- endfor -%}

これは次のように書くことで、期待通りの出力を得ることが可能です(変数宣言は同じなので省略します)。

  
  1. {%- for item in offices -%}
  2. {% set call_value = '{{ item.' + name_key + ' }}' %} {# 変数の呼び出しを文字列として組み立てる #}
  3. {{ call_value }} {# 文字列として組み立てた変数の呼び出しを展開する #}
  4. {%- endfor -%}

ここまでの解説ではただ単に非現実的で、使いどころのないコードに思えます。この方法が必要になるのは、次のように「プロパティの数が可変なテーブル的構造のデータを、自動でで出力したい」という場合です。

実用例

次のデータを先ほどの方法を使用して、tableタグで出力してみます。

  
  1. {%- for item in offices -%}
  2. {% set offices = {
  3. columns: {
  4. name: '支店名',
  5. address: '住所',
  6. tel: '電話番号'
  7. },
  8. contents: [
  9. {
  10. name: '東京オフィス',
  11. address: '東京都千代田区',
  12. tel: '03-XXXX-XXXX'
  13. },
  14. {
  15. name: '札幌オフィス',
  16. address: '北海道札幌市',
  17. tel: '011-XXX-XXXX'
  18. }
  19. ]
  20. } %}
  21.  
  22. <table>
  23. <tr>
  24. {# 1. 見出しの出力 #}
  25. {%- for val in offices.columns -%}
  26. <th> {{ val }} </th>
  27. {%- endfor -%}
  28. </tr>
  29. {# 2. contentsでループを回す #}
  30. {%- for item in offices.contents -%}
  31. <tr>
  32. {# 3. keyを取得するため、1.と同じようにループを回す #}
  33. {%- for key, val in offices.columns.items() -%}
  34.  
  35. {# 4. 取得したkeyを使用して、contentsのデータを取り出す変数呼び出しを文字列として組み立てる #}
  36. {% set call_value = '{{ item.' + key + ' }}' %}
  37.  
  38. {# 5. 4を展開する #}
  39. <td> {{ call_value }} </td>
  40. {%- endfor -%}
  41. </tr>
  42. {%- endfor -%}
  43. </table>
出力結果
  
  1. <table>
  2. <tr>
  3. <th> 支店名 </th>
  4. <th> 住所 </th>
  5. <th> 電話番号 </th>
  6. </tr>
  7. <tr>
  8. <td> 東京オフィス </td>
  9. <td> 東京都千代田区 </td>
  10. <td> 03-XXXX-XXXX </td>
  11. </tr>
  12. <tr>
  13. <td> 札幌オフィス </td>
  14. <td> 北海道札幌市 </td>
  15. <td> 011-XXX-XXXX </td>
  16. </tr>
  17. </table>

一気に複雑になってしまったので、順を追って解説します。

  1. 見出しの出力

    まずはcolumnsに格納されている各valueを見出しとして出力します。columnsはディクショナリですが、普通にループを回すとvalue値が取得できます。

  2. contentsでループを回す

    次に、contentsの要素ごとにループを回します。これ自体は特に特別なコードではありません。

  3. keyを取得するため、dictループを回す

    contents内の各ディクショナリのvalueにアクセスするため、columnsの各キーを取得する必要があります。for文をこのように記述するとディクショナリのkeyにもアクセスできるようになり、これはHubSpot CMSの公式ドキュメントにも紹介されている方法です。

  4. 取得したkeyを使用して、contentsのデータを取り出す変数呼び出しを文字列として組み立てる

    本記事で紹介するメインのコードです。先ほどの「基本形」セクションのコードと本質的に同じです。

  5. 4を展開する

    こちらも本記事で紹介するメインのコードで、「基本形」セクションのコードと本質的に同じです。

この状態であれば、次のようにコンテンツが増えても、HTMLの出力をしている側のコードは一切修正する必要がありませんので、つまりデータと出力を疎結合に保てている証となります。

  
  1. {% set offices = {
  2. columns: {
  3. name: '支店名',
  4. address: '住所',
  5. tel: '電話番号',
  6. staff_num: 'スタッフ数' {# 追加 #}
  7. },
  8. contents: [
  9. {
  10. name: '東京オフィス',
  11. address: '東京都千代田区',
  12. tel: '03-XXXX-XXXX',
  13. staff_num: '10名' {# 追加 #}
  14. },
  15. {
  16. name: '札幌オフィス',
  17. address: '北海道札幌市',
  18. tel: '011-XXX-XXXX',
  19. staff_num: '3名' {# 追加 #}
  20. }
  21. ]
  22. } %}
  23. {# 出力の方のコードには一切変更なし #}
出力結果
  
  1. <table>
  2. <tr>
  3. <th> 支店名 </th>
  4. <th> 住所 </th>
  5. <th> 電話番号 </th>
  6. <th> スタッフ数 </th>
  7. </tr>
  8. <tr>
  9. <td> 東京オフィス </td>
  10. <td> 東京都千代田区 </td>
  11. <td> 03-XXXX-XXXX </td>
  12. <td> 10名 </td>
  13. </tr>
  14. <tr>
  15. <td> 札幌オフィス </td>
  16. <td> 北海道札幌市 </td>
  17. <td> 011-XXX-XXXX </td>
  18. <td> 3名 </td>
  19. </tr>
  20. </table>

この方法が何より真価を発揮するのは、カスタムモジュール内でHubDBテーブルを選択できるようにしている場合です。これについては基本形のHubDB記事にて、実例を紹介しています。

まとめ

以上、変数の値を他の変数の呼び出しに使う方法をご紹介しました。この方法をとることによってデータと出力の疎結合性を高められるため、コード設計としても出来ることがかなり広がると思います。

しかし公式ドキュメントで紹介されている方法ではなく、ハックの域を出ないものですので、使用の際は万が一のことを考え、影響範囲が広くなりすぎないようにすることをオススメします。

執筆者:Admin

関連記事