Masonテンプレートでの継承の使用

Masonは、Perlアプリケーションを開発するための非常によく知られた広く普及したフレームワークです。 単純な構文にもかかわらず、十分な機能と高いパフォーマンスを備えています。 mod_perlおよびmemcachedと統合するための組み込みツールがあります。 石工での作業を学ぶことは非常に簡単です-システムは十分に文書化されています。 同時に、誰もがドキュメントを読むわけではない興味深い微妙な点がいくつかあります。 おそらくこれが、私が見たコードが、PHPでの失敗した作業を痛烈に連想させる理由です。 メイソンでより良く書くことは可能ですか? 私の意見では、はい。



免責事項

この記事では、アメリカを発見し、有名な文書の範囲をはるかに超える何かを説明するつもりはありません。 むしろ、それはいくつかのプロジェクトでうまく機能するシンプルだが効果的な実用的なソリューションについての物語になります。 また、「ダミーのための石工」の紹介的なタイプを書きません-すでにフリーメーソンのコンポーネントを見た人はほとんどそれを必要としません、そして、残りは本当のクールな唐辛子のように、それをその場で理解するか、マニュアルを吸う以外に何時間も費やすことができません役に立たない:)用語に関しては、元のドキュメントから逸脱しないように努めます。 たとえば、masonテンプレートコンポーネントを呼び出します。



真空での球形の膝までの創造性

一連の単純なコンテンツページがあるとします。 ページにアクセスすると、現在のユーザーがそのページにアクセスできるかどうかが確認されます。 そうでない場合は、識別のために送信します。 当然、コンテンツはサイトの標準設計に含まれており、作成者はインクルーダーに共通部分を入れ、関数にコードを入れています。 したがって、例のcompany.html



ファイル:

 <%INIT>
私の$ user = GetUserFromCookies();
 $ m&> redirect( '/ login.html')$ user && $ user-> haveAccess($ r-> uri);
 </%INIT>

 <&/Header.inc、title => "サイトについて"&>
 <h1>サイトについて</ h1>
 <p> Runetで最も人気のあるサイトです</ p>
 <&/Footer.inc&>


おなじみのアプローチ? 原則として、上記の例に問題はありません。 すべてのコンポーネントにほぼ同じ包含物をドラッグしてデザインを表示するのが面倒な場合を除き、承認チェックではページからページにコピーする必要があります。 何ができますか? 余分な部分を削除してください:)



継承の理論的基礎

機能#1:親コンポーネント

各石工コンポーネントは、他のコンポーネントから継承できます。 このようなコンポーネントは、 <%FLAGS>



セクションとinherit



という名前のフラグを使用して強制的に強制(またはリセット)するか、自動的に計算できます。 2番目のケースでは、 autohandler



という名前のファイルは、コンポーネントが配置されているフォルダーで検索され、存在しない場合は、上記のフォルダーを使用して、メイソンがルートと見なしているフォルダーで検索が続行されます。 祖先が見つかった場合、メイソンは彼の親も見つけようとします。



継承チェーンが構築されるとすぐに、実行は「最も親」のコンポーネントに転送されます。このコンポーネントは、マジックコール$m->call_next



を使用してアクションを実行し、その子孫に制御を転送できます。 子が処理された後、親コンポーネントの実行が続行されます。



継承チェーンを構築する上記の手順は、ページにアクセスするときにのみ機能します。 他のコンポーネントが含まれている場合、メカニズムはオンになりません。



機能#2:属性とメソッド

属性を使用すると、すべてが単純になります。コンポーネントの<%ATTR>



セクションで、名前付きパラメーターの任意のセットを開始できます。 現在のコンポーネントで直接宣言されていない親コンポーネントの属性がある場合、それらは継承されます。



メソッドの状況はほぼ同じです。各メソッドは<%METHOD>



セクションでラップされ、「コンポーネント内のコンポーネント」を表します。これは、インクルーダーが接続されているのとほぼ同じ方法で呼び出すことができます。 通常のコンポーネントと同様に、メソッドはテンプレートとして(データを出力するために)、関数として(計算結果を取得するために)使用できます。



継承の実用的な基本

それでは、これらの2つの機能を使用してページを改良してみましょう。 キャップとテールは論理的に/autohandler



されます。 唯一の「しかし」-ページのタイトルはヘッダー( title



タグ内)に表示​​されます。 autohandler



からそれらの一番下に到達できれば、ページの属性に安全に入れることができます(そして、先を見て、はい、そう言うことができます)。 これで、権限チェック付きの伝播セクション<%INIT>



のみができました。 すべてのページで認証が必要でない場合はどうなりますか? この問題を解決するための素晴らしい完全にOOPの方法は、ページ自体に検証の管理を任せることです。 authorize



属性を取得し、true値に設定されているすべてのページで承認を確認します(明確にするため、 /profile/login.html



を除くすべてのページを確認する必要があると想定しています)。 私たちの考えの結果:



/オートハンドラー:

 <%INIT>
私の$ component_requested = $ m-> request_comp;  #company.htmlコンポーネント
 if($ component_requested-> attr( 'authorize'))
 {
    私の$ user = GetUserFromCookies();
     $ m&> redirect( '/ login.html')$ user && $ user-> haveAccess($ r-> uri);
 }
 </%INIT>

 <%ATTR>
承認=> 1
 </%ATTR>

 <&/Header.inc、title => $ component_requested-> attr( 'title')&>
 <h1> <%$ component_requested-> attr( 'title')%> </ h1>
 %$ m-> call_next;
 <&/Footer.inc&>


/company.html:

 <%ATTR>
 title =>「サイトについて」
 </%ATTR>

 <p> Runetで最も人気のあるサイトです</ p>


/profile/login.html:

 <%ATTR>
 title => "サイトにログイン"
許可=> 0
 </%ATTR>

 <p>ログインフォームがある可能性があります</ p>


簡単な例では明らかでないいくつかの簡単な結論:

  1. 属性には、現在のメニュー項目に関する情報を保存して強調表示すると便利です
  2. 上記のコードでは、 Header.inc



    はページタイトルを引数として受け入れますが、原則として、まったく同じコードを使用してヘッダー自体からページタイトルを取得することはありません
  3. ページをフォルダに正しく編成すると、追加レベルのautohandler



    をページに作成できます。 これにより、属性をより柔軟に管理できます(たとえば、 authorize



    属性を/free/autohandler



    移動するauthorize



    で、 /free/



    フォルダーのコンテンツ全体へのアクセスを開くことができ/free/autohandler



    )。 ページのコンテンツを変更することもできます(たとえば、ページの本文の下にEULAを含むトップレベルの見出しまたはブロックを追加します)。


タスクを複雑にします

ページごとに異なるブロックがあるとします。 たとえば、サイト全体の右側の列にセクションのニュースが表示されますが、個人データの機密を保持する義務はユーザープロファイルのページに表示されます。 明らかに、継承もここで役立ちますが、今回はメソッドを使用して問題を解決する方がはるかに便利です。 /autohandler



ニュースを表示するためのデフォルトのメソッド/autohandler



記述し(実装を自分で考えてください)、 /profile/autohandler



そのテキスト/profile/autohandler



再定義します:

 <%メソッドrightmenu>
 <p>誰にもデータを提供しません!</ p>
 </%メソッド>


ここで、一部の(すべてではない)ページに、動的に収集されるサブメニューブロックがあり、サイトのさまざまなセクションでサブメニューが異なって形成されているとします。 たとえば、コンテンツが含まれるページでは、CMSデータベースから取得できます。また、「マイプロファイル」セクションでは、手で作成した静的メニューを使用できます。 当然、メニューに関するデータとそのプレゼンテーションを混在させたくないため、 SubMenu.inc



コンポーネントは実際のレンダリングに関与し、メニュー自体を記述する構造がパラメーターとして渡されます。 質問:継承の可能性を使用するために構造を配置する場所は? 回答:コンポーネントメソッドで。 以下は、対応するファイルに追加することが提案されているスニペットです。

/オートハンドラー:

 %my $ component_requested = $ m-> request_comp;
 %if($ component_requested-> method_exists( 'submenu')){
     <&/SubMenu.inc、MenuItems => $ component_requested-> call_method( 'submenu')&>
 %}


/プロファイル/オートハンドラー:

 <%METHODサブメニュー>
     <%INIT>
     return [
         '/profile/password.html' => 'パスワードの変更'、
         '/profile/update.html' => '個人データの更新'、
         '/profile/logout.html' => '終了'
     ];
     </%INIT>
 </%メソッド>


あとがきの代わりに

上記の手法は、いくつかの単純だが非常に有用なタスクを解決します。 autohandler



一般的なコードフラグメントをautohandler



すると、テンプレート内の情報のないコードの量が大幅に削減されます。 属性を使用すると、コードの記述から構成に移行できます。 メソッドは、ページ上の視覚的なブロックを記述するのに理想的であり、コンポーネントにコードを柔軟にリンクする機能を提供します。



この記事にはアイデアのみが示されており、簡単に開発できます。 たとえば、ページを表示する代わりにCSVファイルをレンダリングできるコンポーネントを作成する必要がある場合、どのように問題を解決しますか? 素晴らしいですが、ユーザーの希望に応じてページがサイトの標準デザインでCSVまたはHTMLを生成する場合はどうでしょうか? スキンと異なるページの異なるスキンを接続する機能を備えたアプリケーションを作成するのは弱いですか? ちなみに、タスクは一見したほど簡単ではありません。 ただし、試してください:)



All Articles