Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

やはりお前らのMTMLは間違っている!

8,525 views

Published on

MTDDC Meetup Tokyo 2015のセッションスライド

Published in: Technology
  • Be the first to comment

やはりお前らのMTMLは間違っている!

  1. 1. やはりお前らのMTML は間違っている! MTDDC Meetup TOKYO 2015 ! Junnama Noda (Alfasado inc.)
  2. 2. ゴールドスポンサーになりました!
  3. 3. ⾃⼰紹介 ✴ アルファサード株式会社 代表取締役 ✴ PowerCMS 開発者 ✴ ウェブアクセシビリティ エバンジェリスト ✴ Movable Type エバンジェリスト ✴ CPAN Author で MTプラグイン開発者
  4. 4. Movable Type <ul>! <MT:Entries limit="10" include_blogs="all">! <li>! <a href="<MT:EntryPermalink>">! <MT:EntryTitle>! </a>! </li>! </MT:Entries>! </ul>!
  5. 5. WordPress <ul>! <?php! $myposts = get_posts('posts_per_page=10');! foreach($myposts as $post) :! setup_postdata($post);! ?>! <li><a href="<?php the_permalink(); ?>">! <?php the_title(); ?></a></li>! <?php endforeach; ?>! </ul>
  6. 6. <?php か! PHPなのか?
  7. 7. SetVarBlockで変数指定!?
  8. 8. tokuchou_setsubi_01 tokuchou_setsubi_02 tokuchou_setsubi_03 …
  9. 9. (;´Д`)
  10. 10. 気を取り直して参りましょう!
  11. 11. 前提(2つのプラグイン)
  12. 12. https://github.com/alfasado/mt-plugin-get-hash-var
  13. 13. https://github.com/alfasado/mt-plugin-dom-document
  14. 14. なぜ間違ってしまうのか? ✴ 案件規模が⼤きくなり、要件は複雑(怪奇)に ✴ 何でも聞いてきやがって、な営業w ✴ 俺MTタグ得意だぜ、変数分岐お任せあれ ✴ MTタグで頑張ればいけるんじゃね? ✴ 変数に突っ込んでソートして MTLoopで回せば 何とかなるんじゃね?
  15. 15. なぜいけないのか? ✴ 直せない。あいつが書いたの俺、直せない(泣 ✴ わかんね。わかんねぇよ。 ✴ 何で修正箇所と別のところ壊したのさ! ✴ ここ直したら、影響範囲どこまで及ぶのさ、こ、 怖いよ修正すんの。 ✴ 担当者、辞めちゃったんだよね。
  16. 16. (;´Д`)
  17. 17. MTSetVarがすべての始まり
  18. 18. おさらい <mt:SetVarBlock name="site_name">! <mt:WebsiteName>! </mt:SetVarBlock>! ! <mt:WebsiteName setvar="site_name">! ! <mt:SetVar name="site_name2" value="$site_name">! ! <mt:If name="site_name" like="MTDDC">! # do Something.! </mt:If> <= 空⽩・改⾏が含まれるのに注意
  19. 19. 変数とは? https://ja.wikipedia.org/wiki/変数_(プログラミング) プログラミングにおいて、変数(へんすう、variable)とは、プ ログラムのソースコードにおいて、扱われるデータを⼀定期間記 憶し必要なときに利⽤できるようにするために、データに固有の 名前を与えたものである。 ⼀⼈⼀⼈の⼈間が異なる名前によって区別されるように、⼀つ⼀ つの変数も名前によって区別される。これにより、複数のデータ を容易に識別することができる。変数を区別するための名前を特 に識別⼦という。また⼀般に、変数が表しているデータをその変 数の値(あたい)という。
  20. 20. 変数とは、メモリに値を書き込むこと (少々乱暴だが) https://www.youtube.com/watch?v=755AIUT5ZME 参考
  21. 21. 変数とは何か ✴ 名前をつけて、メモリに値を書き込む ✴ 名前で値を取得できる ✴ 処理が終ると変数は消える ✴ MTにおける処理の終わりは、テンプレートがビ ルドされた時 ✴ つまり、テンプレートが読み出されビルドされ るまでが変数の寿命
  22. 22. MTのテンプレート変数は、 グローバル変数である
  23. 23. グローバル変数とは? https://ja.wikipedia.org/wiki/グローバル変数 グローバル変数(⼤域変数、英: global variable)は、コンピュー タプログラミングにおいて全てのスコープからアクセスできる変 数のことである。対する語は、ローカル変数である。(中略) ⼀般にグローバル変数は、その⾮局在的な性質ゆえに、好ましく ない実践だと考えられている。すなわち、グローバル変数は潜在 的にどこかで変更される可能性があり、またプログラムの⼀部は それに依存してしまう恐れがあるからである。 (中略)相互依存が⾼まることは複雑性を増⼤することにつながる。
  24. 24. Perl sub main_hdlr {! my $x = 1;! my $y = 2;! print sub_hdlr( $x, $y );! $x;! }! ! sub sub_hdlr {! my ( $value1, $value2 ) = @_;! my $x = $value1 + $value2;! return $x;! } <= 1 <= 3
  25. 25. Movable Type <mt:Setvar name="x" value="1">! <mt:Setvar name="y" value="1">! <mt:Setvar name="x" value="$y" op="+">! ! <mt:Var name="x">! ! <= 2
  26. 26. Movable Type <mt:Include module="共通変数">! ! <mt:If name="some_condition" eq="1">! # do something.! </mt:If>! some_condition! はここで定義 グローバル変数なのに、わかんない! 書き換えてしまうと、全体に影響
  27. 27. どうすれば良いか? ✴ モジュールのインクルードを使わない(無理だろ) ✴ 常に同じテンプレート内で変数を定義する(現実 的じゃないよね) ✴ コメントを⼊れる(変数を定義している箇所でい いの?) ✴ 絶対使われていない変数に⼀回代⼊してから使 う?(美しくない)
  28. 28. Movable Type <mt:Setvar name="x" value="1">! <mt:Setvar name="y" value="1">! ! <mt:LocalVars>! <mt:Setvar name="x" value="$y" op="+">! <mt:Var name="x">! </mt:LocalVars>! ! <mt:Var name="x">! ! <= 2 <= 1 変数を局所化する
  29. 29. Movable Type <mt:Include module="共通変数">! ! <mt:If name="some_condition" eq="1"! note="会員属性が通常会員の時">! # do something.! </mt:If>! コメントは利⽤箇所でこそ重要
  30. 30. Movable Type <mt:SetVar name="特徴" ! value="24時間365⽇の監視付き、低価格の専⽤サーバー">! ! <mt:Var name="特徴"> ⽇本語でOK
  31. 31. 中級編
  32. 32. お題 タイトルとキーワード欄に「東 京」を含み、本⽂に「MTDDC」 を含む記事を最⼤10件出⼒
  33. 33. <mt:Setvar name="show_entries_counter" value="0">! <mt:Entries>! <mt:EntryKeywords setvar="entry_keywords">! <mt:EntryTitle setvar="entry_title">! <mt:EntryBody setvar="entry_body">! <mt:If name="entry_keywords" like="東京">! <mt:If name="entry_title" like="東京">! <mt:If name="entry_body" like="MTDDC">! <mt:If name="show_entries_counter" lt="10">! <mt:Unless name="show_entries_counter">! <ul>! </mt:Unless>! <li><mt:EntryTitle></li>! <mt:Setvar name="show_entries_counter"! op="++" setvar="show_entries_counter">! </mt:If>! </mt:If>! </mt:If>! </mt:If>! <mt:If name="show_entries_counter" eq="10">! </ul>! </mt:If>! </mt:Entries> ロジック=> ロジック=> ビュー=> テンプレート1
  34. 34. <mt:Setvar name="show_entries_counter" value="0">! <mt:Entries>! <mt:EntryKeywords setvar="entry_keywords">! <mt:EntryTitle setvar="entry_title">! <mt:EntryBody setvar="entry_body">! <mt:SetVar name="show_entry" value="0">! <mt:If name="entry_keywords" like="東京">! <mt:If name="entry_title" like="東京">! <mt:If name="entry_body" like="MTDDC">! <mt:If name="show_entries_counter" lt="10">! <mt:SetVar name="show_entry" value="1">! <mt:Setvar name="show_entries_counter" ! op="++" setvar="show_entries_counter">! </mt:If>! </mt:If>! </mt:If>! </mt:If>! <mt:If name="show_entry">! <mt:Unless name="show_entries_counter"><ul></mt:Unless>! <li><mt:EntryTitle></li>! <mt:Setvar name="show_entries_counter"! op="++" setvar="show_entries_counter">! </mt:If>! <mt:If name="show_entries_counter" eq="10">! </ul>! </mt:If>! </mt:Entries> ロジック=> ビュー=> テンプレート2
  35. 35. <mt:Setvar name="show_entries_counter" value="0">! <mt:Entries>! <mt:EntryKeywords setvar="entry_keywords">! <mt:EntryTitle setvar="entry_title">! <mt:EntryBody setvar="entry_body">! <mt:SetVar name="show_entry" value="0">! <mt:If name="entry_keywords" like="東京">! <mt:If name="entry_title" like="東京">! <mt:If name="entry_body" like="MTDDC">! <mt:If name="show_entries_counter" lt="10">! <mt:EntryId setvar="entry_id">! <mt:SetVar name="entry_ids"! function="push" value="$entry_id">! <mt:Setvar name="show_entries_counter" ! op="++" setvar="show_entries_counter">! </mt:If>! </mt:If>! </mt:If>! </mt:If>! </mt:Entries> ロジックのみ=> 前半 テンプレート3
  36. 36. <mt:Entries entry_ids="$entry_ids">! <mt:If name="__first__"><ul class="entries_widget"></mt:If>! <li class="<mt:If name="__odd__">odd! <mt:Else>even</mt:If>">! <a href="<mt:EntryPermalink>">! <mt:EntryTitle escape="html">! </a>! <span class="date"><mt:EntryDate></span>! <p class="description">! <mt:EntryExcerpt remove_html="1">! </p>! </li>! <mt:If name="__last__">! </ul>! </mt:If>! </mt:Entries>! ビューのみ=> 後半 テンプレート3 entry_idsはGetHashVarプラグインが 提供するモディファイア
  37. 37. <mt:Setvar name="show_entries_counter" value="0">! <mt:Entries>! <mt:EntryKeywords setvar="entry_keywords">! <mt:EntryTitle setvar="entry_title">! <mt:EntryBody setvar="entry_body">! <mt:SetVar name="show_entry" value="0">! <mt:If name="entry_keywords" like="東京">! <mt:If name="entry_title" like="東京">! <mt:If name="entry_body" like="MTDDC">! <mt:If name="show_entries_counter" lt="10">! <mt:SetHashVars name="cols">! title=<mt:EntryTitle>! excerpt=<mt:EntryExcerpt>! date=<mt:EntryDate>! permalink=<mt:EntryPermalink>! </mt:SetHashVars>! <mt:SetVar name="entries"! function="push" key="$__counter__" value="$cols">! <mt:Setvar name="show_entries_counter" ! op="++" setvar="show_entries_counter">! </mt:If>! </mt:If>! </mt:If>! </mt:If>! </mt:Entries> ロジックのみ=> テンプレート4 前半 SetHashVarsはGetHashVarプラグインが提供 (setHashVarタグ使えば標準機能だけでも可能) <= 変数にハッシュで格納
  38. 38. <mt:Loop name="entries">! <mt:If name="__first__"><ul class="entries_widget"></mt:If>! <li class="<mt:If name="__odd__">odd! <mt:Else>even</mt:If>">! <a href="<mt:Var name="__value__{permalink}">">! <mt:Var name="__value__{title}" escape="html">! </a>! <span class="date">! <mt:Var name="__value__{date}"></span>! <p class="description">! <mt:Var name="__value__{excerpt}"! remove_html="1">! </p>! </li>! <mt:If name="__last__">! </ul>! </mt:If>! </mt:Loop>! ビューのみ=> テンプレート4 後半 ただし、変数は諸刃の件。ググれないし、定義した⼈にしかわからないから。
  39. 39. name: EntriesLikeFilter! tags:! filters:! Entries:! like_filter:! handler: > ! sub {! my ( $ctx, $args, $cond ) = @_;! for my $key! ( keys %{ $args->{ like_filter } } ) {! $ctx->{ terms }->{ $key } =! { like => '%' .! $args->! { like_filter }->{ $key } .'%' };! }! } テンプレート5 プラグイン(config.yaml)
  40. 40. <mt:SetHashVars name="entries_condition">! title=東京! keywords=東京! text=MTDDC! </mt:SetHashVar>! ! <mt:Entries like_filter="$entries_condition">! <mt:If name="__first__"><ul class="entries_widget"></mt:If>! <li class="<mt:If name="__odd__">odd! <mt:Else>even</mt:If>">! <a href="<mt:EntryPermalink>">! <mt:EntryTitle escape="html">! </a>! <span class="date"><mt:EntryDate></span>! <p class="description">! <mt:EntryExcerpt remove_html="1">! </p>! </li>! <mt:If name="__last__">! </ul>! </mt:If>! </mt:Entries>! テンプレート5 たいへんよくできました!
  41. 41. MTタグって作れるんだぜ?
  42. 42. Model View Controller https://ja.wikipedia.org/wiki/Model_View_Controller MVC(Model View Controller モデル・ビュー・コントローラ) は、ユーザーインタフェースをもつアプリケーションソフトウェ アを実装するためのデザインパターンである。 アプリケーションソフトウェアの内部データを、ユーザーが直接 参照・編集する情報から分離する。そのためにアプリケーション ソフトウェアを以下の3つの部分に分割する。 ✴model: アプリケーションデータ、ビジネスルール、ロジック、関数 ✴view: グラフや図などの任意の情報表現 ✴controller: ⼊⼒を受け取りmodelとviewへの命令に変換する
  43. 43. サーバーサイド エンジニア フロントエンド エンジニア ロジックの実装 MVCのM+C ビューの実装 MVCのV
  44. 44. <mt:MicrosoftProducts sort_by=„released_on"! sort_order="descend" limit="10">! <mt:If name="__first__"><ul></mt:If>! <li><mt:MicrosoftProductName></li>! <mt:If name="__last__"></ul></mt:If>! </mt:MicrosoftProducts> もしMicrosoft様のウェブサイトなら
  45. 45. CakePHPのView <table>! <tr>! <th>Id</th>! <th>Title</th>! <th>Created</th>! </tr>! <!-- Here is where we loop through our $posts array, printing out post info -->! <?php foreach ($posts as $post): ?>! <tr>! <td><?php echo $post['Post']['id']; ?></td>! <td>! <?php echo $html->link($post['Post']['title'], ! array('controller' => 'posts', 'action' => 'view', $post['Post'] ['id'])); ?>! </td>! <td><?php echo $post['Post']['created']; ?></td>! </tr>! <?php endforeach; ?>! </table>!
  46. 46. MTCakeのView <mt:cake:loop model="Post">! <mt:ignore>! or <mt:cake:loop model="Post" stash="posts">! </mt:ignore>! <mt:if name="__first__">! <table>! <tr>! <th>Id</th>! <th>Title</th>! <th>Created</th>! </tr>! </mt:if>! <tr>! <td><mt:var name="id"></td>! <td>! <a href="./view/<mt:var name="id">"><mt:var name="title" escape="html"></a>! </td>! <td><mt:var name="created"></td>! </tr>! <mt:if name="__last__">! </table>! </mt:if>! </mt:cake:loop>!
  47. 47. <?php foreach ($posts as $post): ?>! <tr>! <td><?php echo $post['Post']['id']; ?></td> <mt:cake:loop model="Post">! <tr>! <td><mt:var name="id"></td> モデルを変えれば書き⽅は同じ、同じ振るまい
  48. 48. MTMLへの疑問?
  49. 49. https://github.com/alfasado/mt-plugin-object-loop
  50. 50. 汎⽤的なMTObjectLoop <mt:ObjectLoop model="entry"! include_blogs="all" keyword="Keyword"! sort_order="descend" sort_by="crearted_on">! <mt:If name="__first__"><ul></mt:If>! <li><mt:Var name="text" trim_to="25+..."></li>! <mt:If name="__last__"></ul></mt:If>! </mt:ObjectLoop>! <mt:ObjectLoop model="comment"! include_blogs="all"! sort_order="descend" sort_by="crearted_on">! <mt:If name="__first__"><ul></mt:If>! <li><mt:Var name="text" trim_to="25+..."></li>! <mt:If name="__last__"></ul></mt:If>! </mt:ObjectLoop>!
  51. 51. 汎⽤的なMTObjectLoop ✴ MTObjectLoop = model指定であらゆるモデル のデータを出⼒できる ✴ MTEntryLoop、MTEntryModelという別名を指 定可能 ✴ tag、field:foo対応 ✴ オブジェクトごとの振る舞いはプラグインで拡 張可能
  52. 52. 覚えるのひとつでいいんだぜ!
  53. 53. 上級編 というか、間違った⽅向のテクニック利⽤
  54. 54. お題 特定の条件の時だけ、 mt:Entriesにカスタムフィール ドによるフィルタ指定をしたい
  55. 55. <mt:Entries! <mt:If name="want_filter">field.foo="1"</mt:If>>! ...! </mt:Entries> こう書ければいいんだけどね。
  56. 56. <mt:Unless decode_html="1" mteval="1">! &lt;mt:Entries! <mt:If name="want_filter">! field.foo="1"! </mt:If>&gt;! ...! &lt;/mt:Entries&gt;! </mt:Unless> テンプレート1
  57. 57. <mt:setVarBlock name="search1">/<lz:/g</mt:setVarBlock>! <mt:setVarBlock name="replace1"><</mt:setVarBlock>! <mt:setVarBlock name="replace1" append="1">mt:</mt:setVarBlock>! ! <mt:setVarBlock name="search2">/</lz:/g</mt:setVarBlock>! <mt:setVarBlock name="replace2"><</mt:setVarBlock>! <mt:setVarBlock name="replace2" append="1">/mt:</mt:setVarBlock>! ! <mt:Unless regex_replace="$search1","$replace1"! regex_replace="$search2","$replace2" mteval="1">! ! <lz:Entries <mt:If name="want_filter">field:foo="1"</mt:if>>! <lz:If name="__first__"><ul></lz:If>! <li><lz:EntryTitle></li>! <lz:If name="__last__"></ul></lz:If>! </lz:Entries>! </mt:Unless> テンプレート2
  58. 58. やはりお前らのMTMLは間違っている!
  59. 59. こういうのをTipsとかテクニックとか⾔うな!
  60. 60. どこが間違っているのか ✴ 管理画⾯のテンプレート検索で⽬的の箇所がヒッ トしない ✴ decode_html のパターンでは、HTML(デザイン) の修正時に修正が困難 ✴ やりすぎると⾒通しが悪くなる ✴ replace のパターンでは⽂字列「<lz:」「</lz:」 がブロック内の出⼒結果に含まれていないかど うかを考慮しておく必要がある
  61. 61. <mt:getElementById id="tmpl_entries" setvar="tmpl_entries">! <mt:removeAttribute name="id" node="tmpl_entries">! ! <mt:If name="want_filter">! <mt:setAttribute node="tmpl_entries" attr="field.foo","1">! </mt:If>! ! <mt:Entries id="tmpl_entries">! ...! </mt:Entries>! テンプレート3 たいへんよくできました!
  62. 62. Tips, Q&Aとか
  63. 63. mt:Includeのblog_idに変数を使うのは? <mt:Include module="HTMLヘッダー" blog_id="$blog_id"> こう書きたい理由は? 開発環境と本番環境でblog_idが違う? <mt:If name="config.IsProduction">! <mt:Include module="HTMLヘッダー" blog_id="2">! <mt:Else>! <mt:Include module="HTMLヘッダー" blog_id="$blog_id">! </mt:If>! もしくは <mt:Unless name="config.IsProduction">! <mt:GetElementById id="html_header" setvar="html_header">! <mt:SetAttribute node="html_header" attributes=„blog_id","$blog_id">! </mt:Unless>! <mt:Include module="HTMLヘッダー" blog_id="2" id="html_header">!
  64. 64. コメントはどこに⼊れたらいい? (本⽇2度⽬)コメントは利⽤時点こそ重要 <mt:Include module="共通変数">! ! <mt:If name="some_condition" eq="1"! note="会員属性が通常会員の時">! # do something.! </mt:If>!
  65. 65. コメントはどこに⼊れたらいい? <mt:Ignore>第1条件</mt:Ignore>! <mtSetvar name="ad_attr" function="push" value="area" note="地域">! <mtSetvar name="add_condition" function="push" value="STREQ" note="等しい">! <mtSetvar name="values" function="push" value="江東区" note="江東区">! ! <mt:Ignore>第2条件</mt:Ignore>! <mtSetvar name="ad_attr" function="push" value="station" note="駅">! <mtSetvar name="add_condition" function="push" value="STRINC" note="含む">! <mtSetvar name="values" function="push" value="森下" note="森下">! ! <mt:EstraierSearch ! ad_attr="$ad_attr" add_condition="$add_condition" values="$values">! # do something.! </mt:EstraierSearch> 存在しないモディファイアは無視される
  66. 66. コメントはどこに⼊れたらいい? https://github.com/alfasado/mt-plugin-template-note
  67. 67. MTEntriesとMTPagesを共通化したい <mt:If name="archive_type" eq="Individual">! <mt:Entries>! <mt:SetHashVars name="cols">! title=<mt:EntryTitle>! excerpt=<mt:EntryExcerpt>! date=<mt:EntryDate>! permalink=<mt:EntryPermalink>! </mt:SetHashVars>! <mt:SetVar name="entries"! function="push" key="$__counter__" value="$cols">! </mt:Entries>! <mt:Elseif name="archive_type" eq="Page">! <mt:Pages>! <mt:SetHashVars name="cols">! title=<mt:PageTitle>! excerpt=<mt:PageExcerpt>! date=<mt:PageDate>! permalink=<mt:PagePermalink>! </mt:SetHashVars>! <mt:SetVar name="entries"! function="push" key="$__counter__" value="$cols">! </mt:Pages>! </mt:If>! <mt:Loop name="entries">! # do something.! </mt:Loop>
  68. 68. MTEntriesとMTPagesを共通化したい <mt:If name="archive_type" eq="Individual">! <mt:SetVar name="class_type" value="entry">! <mt:Elseif name="archive_type" eq="Page">! <mt:SetVar name="class_type" value="page">! </mt:If>! ! <mt:Entries class_type="$class_type">! #do something.! </mt:Entries> http://www.movabletype.jp/documentation/appendices/tags/entries.html
  69. 69. 最後に、絶対にやってはいけないこと <mt:Var name="request.foo"> ※Dynamicもしくは cgiアプリで <mt:Var name="request.foo" escape="html"> ?foo=<script>alert()</script>
  70. 70. まとめ ✴ MTのテンプレート変数はグローバル変数であることを 頭に置いておけ。 ✴ ロジックとビューをできるだけ分けろ。 ✴ コメント重要、どこにどう⼊れるかが問題。 ✴ プラグインを怖がるな。作れなくても誰かが作ってく れるかもしれない。 ✴ リクエストはただ。本家でもMTQでもアルファサード でも。リクエストもコミュニティへの貢献。 ✴ ユーザーの⼊⼒値は必ずエスケープせよ。

×