デバッグコンソールの例でのMagentoの拡張機能の段階的な作成

こんにちは。

プラットフォームが非常に人気があり、同時に単純ではないという事実にもかかわらず、HabrがMagentoに関する記事に甘やかされていないことは注目に値します。 この記事では、ダウンロード可能な実際の拡張機能を作成する方法を示します。 これはこんにちはの世界ではなく、Commercebugの無料の代替手段をコミュニティに提供したいという願望です(Magentoで働いていたなら、おそらく聞いたことがあるでしょう)。



それで、すぐに使える拡張機能はどうあるべきでしょうか? これは、現在使用されているブロック、テンプレート、ハンドル、およびその他の有用な情報に関するデータを含むページ上のセクションである必要があります。 折りたたみ式の「コンソール」の形でこれを行うのが最も便利であるように思えました-Half-Lifeのような多くのゲームで見慣れているものです。 当然、コマンドラインは必要ないため、コマンドラインはありません。



まず最初に行う必要があるのは、ファイル構造の作成です。 私は実際の拡張機能について説明しているため、この記事では名前空間とクラスの実際の名前を使用する許可を求めています。

名前空間(名前空間)を定義しましょう-これはクラスの名前の最初の部分であり、拡張機能の開発者によって識別されます。 たとえば、内部で開発されたすべてのMagento内部クラスには、名前空間「Mage」があります。 「リンカー」にします。 app / code / communityにこの名前のディレクトリを作成します。

プラットフォームに3つの標準コードプール(コアプール、コミュニティ、ローカル)があることを思い出させてください。 1つ目は社内で開発されたコードのみ、2つ目はコミュニティが開発しているもの(有料と無料の両方の拡張機能)、3つ目は共有しないこの特定のサイトの変更を含みます。



次に、モジュールの名前(Insider)を使用して内部にディレクトリを作成し、その中に標準のディレクトリ構造を作成します。



Insider

|-- Block

|-- controllers

|-- etc

|-- — config.xml

|-- Helper

|-- — Data.php

|-- Model








Data.phpとconfig.xmlは必須の拡張ファイルです。これらがなければ、コードは起動しません。



config.xmlに次のものを追加します。



<? xml version ="1.0" ? > <!-- , - XML! -->

< config > <!-- root node -->

< modules >

< Linker_Insider > <!-- -->

< version > 0.1.0.0 </ version >

</ Linker_Insider >

</ modules >

</ config >









ここで、私はシステムに、私がそのようなモジュールであり、そのようなバージョンがあることを通知しました。 これまでのところ、重要なことは何もありません。 Data.phpの内容は次のとおりです。



Copy Source | Copy HTML



  1. <?php
  2. クラス Linker_Insider_Helper_Data Mage_Core_Helper_Dataを拡張します{}




これはスタブです。 ヘルパーは使用しませんが、このファイルはシステムに必要です。

クラスの命名規則について少し説明します。基本的にはZendの命名規則と一致します。つまり、クラス名を見ると、正確にどこにあるかがわかります。 実際、「_」を「/」に置き換えると、名前はファイルシステム内の場所に対応します。

次に、一般リストでモジュールを有効にします。 これを行うには、etc / modules / Mage_All.xmlを開き、最後のモジュールの説明と</ config>の間に次の行を追加します。



< Linker_Insider >

< active > true </ active >

< codePool > community </ codePool >

</ Linker_Insider >









したがって、コミュニティコードのプール(app / code / community)にあるLinker_Insiderというモジュールを有効にする(<active> true </ active>)ことを報告しました。

オン、素晴らしい! しかし、サイトでこれを観察することはまだできません。なぜなら、それはまだ何もしないからです。 彼を作りましょう。

これを行うには、テンプレートファイルを作成します。 フロントエンドのテンプレートは、アプリ/デザイン/フロントエンド/ベース/デフォルト/テンプレートに保存されます。 そこで、モジュール(インサイダー)の名前でディレクトリを作成します。その中には、ファイルdiscover.phtmlがあります。 たとえば、「hello」と記述します(ここでは、モジュールが機能するかどうかを確認するだけです)。 次に、システムに挿入先を指示する必要があります-これはマークアップに関するものです。 レイアウトテンプレートはXMLファイルであり、app / design / frontend / base / default / layoutにあります。 次の内容でinsider.xmlというファイルを作成します。



<? xml version ="1.0" ? >

< layout >

< default > <!-- -->

< block type ="core/template" name ="insider" template ="insider/disclose.phtml" />

</ default >

</ layout >









属性「タイプ」は、テンプレート「テンプレート」のレンダリングを制御するブロックを示します。 この場合、クラス名がMage_Core_Block_Templateのブロックになります。 type = "modulename / blockname"は、Namespace_modulename_Block_blocknameを表します。 名前空間はすでにシステムに登録されており、modulenameで始まるブロックを探す場所を知っていると想定されています。 もちろん、Mageは登録されており、独自のブロックを使用する必要がある場合は、構成ファイルに何かを追加する必要がありますが、それについては後で詳しく説明します。

属性 'name'は、他のブロックが<reference>を使用してそれに固執できるようにするために必要です-これも少し明確になります。



insider.xmlのみをピックアップすることはできません。モジュールがマークアップを変更することを明示的に示す必要があります。このために、config.xmlに別のノードを作成します。



< frontend > <!-- , -->

< layout > <!-- - -->

< updates > <!-- , - -->

< insider > <!-- -->

< file > insider.xml </ file > <!-- , -->

</ insider >

</ updates >

</ layout >

</ frontend >









次に、サイトに戻ってF5を押します。「hello」は、フロントエンドページのどこかに表示されます。 表示されませんでしたか? キャッシュを使用していませんか? 管理パネルで無効にできることを思い出させてください:システム->キャッシュ管理。

私はあなたのことは知りませんが、私にとっては、私たちの記録が一番下にかかっているのは好きではありません。 彼女を高く投げましょうか? これを行うには、レイアウト作成メカニズムについて少し話す必要があります.Magentoページを表示する前に、レイアウトフォルダーのすべての.xmlファイル(当然、現在のページの表示に直接影響するファイルのみ)を解析し、それらの1つを収集しますが、大規模です。 属性「before」および「after」を使用して、パーサーに、それぞれのブロックを挿入する前または後を示すことができます。 <reference>ノード内にブロックを配置すると、特定のブロックに「フック」できます-内部に自分を挿入します。 ほとんどすべてのブロックには属性 'name'があります-これは一般的なマークアップでそれを定義する方法であり、「移動」または「一晩で退出」するリクエストでそれを有効にすることができます。

どの場所のどのブロックがそれ自体を定義するかを知るには、他のモジュールのマークアップファイルを調べる必要があります。 たとえば、page.xmlを見ると、ラベル「Page Top」の「after_body_start」という名前のブロックがあります。 これがあなたが必要なもののようです! おそらく私たちは彼にしがみついています。 これを行うには、ブロックの説明を<reference>ノード内のinsider.xmlファイルに配置します。



< reference name ="after_body_start" > <!-- after_body_start, ! -->

< block type ="core/template" name ="insider" template ="insider/disclose.phtml" />

</ reference >









まあ、それは良いです。 しかし、私たちの「ハロー」が私を刺激するのをやめました。 ある種の圧倒的な<div>をテンプレートに追加しましょう。クラスをハングアップし、.cssでスタイルを記述してから、.jsでさらにダイナミクスを追加します。 コードはあなたの好みに任せて、どのように機能させるかだけを説明します。 フォルダーskin / frontend / base / default / css / insider / insider.cssにファイルを作成し、declare.phtmlの表示スタイルに影響するコードを記述します。 このファイルをページに追加するには、マークアップファイル(insider.xml)を編集し、次を<default>ノードに追加する必要があります。



< reference name ="head" > <!-- HTML <head> -->

< action method ="addCss" >< stylesheet > css/insider/insider.css </ stylesheet ></ action >

</ reference >









このアクションは何ですか? <action>ノードを使用すると、ブロックメソッドを呼び出して、マークアップファイルから直接パラメーターを渡すことができます。 これは非常に強力なことです。 page.xmlに戻ると、ヘッド「page / html_head」が「head」という名前で署名されていることがわかります。これは、Mage_Core_Page_Block_Html_Headというクラスです。 その実装を見れば、addCss()メソッドを簡単に見つけることができます。 今、あなたは何が野生の仕掛け-<アクション>を理解していますか?

JavaScriptをやってみましょう。 js / insider / insider.jsファイルを作成し、好みのコードで味付けします。 CSSとほぼ同じ方法で追加する必要があります。「ヘッド」を参照する同じ<reference>ノードに次のエントリを作成します。



< action method ="addJs" >< script > insider/insider.js </ script ></ action >









ここで説明することは何もないと思います-類推により、すべてが明確でなければなりません。



もちろん、これはすべて良いことですが、私たちの拡張はまだ役に立たないものではありません。 これを修正する時が来ました! テンプレートの動作に影響を与え、情報をテンプレートに送信するには、独自のブロックが必要です。 ファイルLinker / Insider / Block / Disclose.phpを作成します。 次の内容を入力します。



Copy Source | Copy HTML<br/> <?php <br/> class Linker_Insider_Block_Disclose extends Mage_Core_Block_Template<br/>{<br/> // Magento __construct() ( "_") <br/> function _construct()<br/> {<br/> // ( Zend Framework) <br/> $request = $this ->getRequest();<br/> // , <br/> $this ->module = $request ->getModuleName();<br/> $this ->controller = $request ->getControllerName();<br/> $this ->action = $request ->getActionName();<br/> }<br/>}<br/> <br/>







この情報をテンプレートに転送できるようにするには、insider.xmlファイルのブロックタイプを変更する必要があります。



< block type ="insider/disclose" name ="insider" template ="insider/disclose.phtml" />









ただし、注意点が1つあります。機能しません。 私たちは独自の名前空間を持っていることを思い出してください。 これを行う必要があります。そうしないと、システムはブロッククラスを見つけることができません。 config.xmlに変更を加えます。



< global > <!-- , -->

< blocks > <!-- -->

< insider > <!-- , Mage::getModel('insider/') -->

< class > Linker_Insider_Block </ class > <!-- Linker_Insider_Block_ -->

</ insider >

</ blocks >

</ global >









実際、テンプレートは、ブロック自体のメソッドを使用してレンダリングされます。つまり、このブロック自体のすべてのフィールドとメソッド(保護されていてもプライベートでも)にアクセスできます。 この方法で変数の内容を表示できます(disclosure.phtmlに書き込みます)。



Copy Source | Copy HTML<br/> <br/>Module: <?php echo $this ->module; ?> <br/>Controller: <?php echo $this ->controller; ?> <br/>Action : <?php echo $this ->action; ?> <br/> <br/>







ここで、突然ブロックを美しく表示し、データを入力したいと考えていたとします。 基本的に、ここにはname = valueスキームがあるので、これを行う最も簡単な方法はフォームを使用することです。 フォーム用の別のファイルがあります。リンカー/インサイダー/ブロック/開示/フォーム/Controller.phpです。 名前はあなたを混乱させないでください-現在のコントローラ/モジュール/アクションに関する情報を含む単なるフォームになります。ファイルの内容は次のとおりです。



Copy Source | Copy HTML<br/> <br/> <?php <br/> class Linker_Insider_Block_Disclose_Form_Controller extends Varien_Data_Form<br/>{<br/> public function __construct()<br/> {<br/> // HTML id <br/> parent::__construct( array ( 'id' => 'insider-form-controller' ));<br/> <br/> // HTML id , ( Varien_Data_Form_Element_*), <br/> // (ZF- ) <br/> $this ->addField( 'module' , 'text' , array ( 'label' => 'Module' ));<br/> $this ->addField( 'controller' , 'text' , array ( 'label' => 'Controller' ));<br/> $this ->addField( 'action' , 'text' , array ( 'label' => 'Action' ));<br/> }<br/>}<br/> <br/>







完了しました。今度はデータを入力します。 MVCの概念によれば、データはモデルから取得する必要があるため、ブロックのコンテンツをモデルに移動する必要があります。 ファイルLinker / Insider / Model / Insider.phpを作成します。



Copy Source | Copy HTML<br/> <br/> <?php <br/> class Linker_Insider_Model_Insider extends Mage_Core_Model_Abstract<br/>{<br/> public function _construct()<br/> {<br/> // , getRequest(), : <br/> $request = Mage::app()->getRequest();<br/> $module = $request ->getModuleName();<br/> $controller = $request ->getControllerName();<br/> $action = $request ->getActionName();<br/> <br/> // setData() protected $_data <br/> // , id , <br/> // , <br/> $this ->setData( 'controller' , array (<br/> 'module' => $module ,<br/> 'controller' => $controller ,<br/> 'action' => $action ,<br/> ));<br/> }<br/>} <br/>







これで、モデルのデータをフォームに入力できます。



Copy Source | Copy HTML<br/>...<br/> $this ->addField( 'action' , 'text' , array ( 'label' => 'Action' ));<br/> $model = Mage::getSingleton( 'insider/insider' );<br/> $this ->addValues( $model ->getData( 'controller' ));<br/> <br/>







しかし、それも同様に機能しません。 システムは、「インサイダー」で始まるブロックを探す場所を知っていますが、そのようなモデルを探す場所を知りません。 彼女にconfig.xmlファイルの<global>ノードで説明します。



<!-- -->

< models >

< insider >

< class > Linker_Insider_Model </ class >

</ insider >

</ models >










これでモデルに目を向けることができますが、今度はフォームを目に見えるようにする必要があります。 これを行うには、次のようにDisclose.phpの内容を変更します。



Copy Source | Copy HTML<br/> <br/> <?php <br/> class Linker_Insider_Block_Disclose extends Mage_Core_Block_Template<br/>{<br/> public $forms = array ();<br/> <br/> protected function _construct()<br/> {<br/> $this ->forms = array (<br/> 'controller' => new Linker_Insider_Block_Disclose_Form_Controller(),<br/> );<br/> }<br/>}<br/> <br/>







そして、テンプレートで、先ほど追加した3行を削除し、よりシンプルなものに置き換えます。



Copy Source | Copy HTML<br/> <br/> <?php echo $this ->forms[ 'controller' ]->toHtml(); ?> <br/>







OK、完了です。 フォームを「コンソール」の外観にするために、独自のレンダラーを作成できます。 これはそれほど難しい作業ではなく、ソースコードからすべてが明確になっているはずなので、ここではこの手順をスキップします。

それでは、もっと深刻なことをしましょう。現在のページの表示に関係するすべてのブロックのリストを取得すると便利です。 次のようにモデルからこれを行うことができます。



Copy Source | Copy HTML<br/> // , <br/> $layout = Mage::app()->getLayout();<br/> foreach ( $layout ->getAllBlocks() as $name => $block ) {<br/> $class = get_class( $block );<br/> // , , Mage_Core_Block_Abstract, <br/> if (method_exists( $block , 'getTemplate' )) {<br/> /* @var $block Mage_Core_Block_Template */ <br/> $template = $block ->getTemplate();<br/> } else {<br/> $template = false ;<br/> }<br/> <br/> $blocks [] = array (<br/> // eg Mage_Catalog_Product_List <br/> 'class' => $class ,<br/> // eg catalog/product_list.phtml <br/> 'template' => $template ,<br/> // eg "head" <br/> 'name' => $name ,<br/> // eg /home/user/magento/app/code/core/Mage/Catalog/Product/List.php <br/> 'blockFile' => mageFindClassFile( $class ),<br/> // eg /home/user/magento/app/design/frontend/base/default/template/catalog/product_list.phtml <br/> 'templateFile' => $template ? $block ->getTemplateFile() : '' ,<br/> );<br/>}<br/> <br/>







フォームを作成し、これらのデータを入力して、テンプレートでレンダリングすることを信頼しています。 まあ、つまり、すべてソースコードで利用可能です。 なぜこの作品はここにあるのですか? あなたがこのアプローチの失敗を見るために。 ブロックのリストでは、自分自身を取得します(OK、悲しみはそれほど大きくありません)が、すべてを取得するわけでもありません(ストップ-ストップ-ストップ、なぜ?)。 少なくとも、ブロックは<body>タグの直後の最初のブロックの1つにレンダリングされるためです。 その結果、モデルは既に存在するブロックに関する情報のみを引き出すことができ、それはすべて無料です。 この障害を克服するには? 最初に頭に浮かぶのは、どのブロックが最後にレンダリングされるかを確認し、その後に「後」を続けることです。 しかし、考えてみると、別のブロックが表示される可能性があるために機能しません-それは後でレンダリングされるか、「後」を使用して私たちにしがみつくでしょう-そして私たちはそれを見ません。 いいえ、ここでは別のレベルが必要です。 要求を処理する過程で、Magentoはかなり多くのイベントを生成します。これらのイベントについては、「ブロック」のように「キャッチ」することもできます。 ページがブラウザに送信される前に文字通り報告されるイベントはどうですか? それは素晴らしいですね! すべてのブロックがレンダリングされ、可能な限りすべてが完了し、実際には、準備が整ったHTMLが完成しています。 関係するすべてのブロックに関する情報を引き出し(現在は完全に完了)、HTMLを最終出力に追加するだけです。 これには何が必要ですか? 最初に、禁止が自動的にレンダリングされます(ブロックのリストでは何らかの形で並んでいますが、そこに立っています-そしてシステムは確実に何らかの段階で適切にレンダリングしようとします)。 最も簡単な方法は、HTMLコードを生成してレンダリングするために呼び出されるメソッドの代わりにスタブを挿入することです。 新しいメソッドでDisclose.phpを更新します。



Copy Source | Copy HTML<br/> <br/> public function renderView()<br/>{<br/> return '' ;<br/>}<br/> <br/>







そして今、私たちは独自に作成し、オンデマンドで呼び出すことができます-まさに必要なときに:



Copy Source | Copy HTML<br/> <br/> public function renderSelf()<br/>{<br/> return parent::renderView();<br/>}<br/> <br/>







さて、話したイベントに応じて、厳密に定義された瞬間に呼び出されるようにします。 イベントには、「controller_front_send_response_before」のような名前が付いています。 彼を「フック」するには、私たち自身のオブザーバーを作成する必要があります。 次の内容のファイルLinker / Insider / Model / Observer.phpを作成します。



Copy Source | Copy HTML<br/> <br/> class Linker_Insider_Model_Observer<br/>{<br/> public function renderSelf(Varien_Event_Observer $observer )<br/> {<br/> // , - - ? <br/> // , ( - fire') <br/> if ( $block = Mage::app()->getLayout()->getBlock( 'insider' )) {<br/> // HTML- <br/> $insiderHtml = $block ->renderSelf();<br/> // front controller, HTML <br/> $front = $observer ->getData( 'front' );<br/> // <br/> $front ->getResponse()->append( 'insider' , $insiderHtml );<br/> }<br/> }<br/>}<br/> <br/>







次に、オブザーバーが応答する必要がある内容を説明する必要があります。 これは、config.xmlの<global>ノードで行われます。



< events > <!-- -->

< controller_front_send_response_before > <!-- - -->

< observers > <!-- ! -->

< insider_renderself > <!-- -->

< class > insider/observer </ class > <!-- ... -->

< method > renderSelf </ method > <!-- -->

</ insider_renderself >

</ observers >

</ controller_front_send_response_before >

</ events >









実際、それが私が話したかったことのすべてでした。 これにより、Magentoの内部作業パターンの一部を理解できるようになります。

self-PRでの非難を避けるため、リンクは提供していません。 拡張機能の有用性を評価したい人は、Magento Connectでそれを見つけることができます。



All Articles