Magentoのステップバイステップモジュールの作成-初心者向けガイド

Magentoについてはどれくらい書くのではなく、まだたくさんの質問があります;)© jeje




Magentoの電子ストアを勉強しているときに、例を使用してモジュールの作成を説明する多くの記事に出会いましたが、ほとんどすべての記事で「これを実行して実行してください」という手順が説明されています。 その結果、エラーが発生した場合、何が間違っていたかを判断することは非常に難しく、ニーズに合わせてモジュールを作り直すこともより困難です。



この記事では、DS Newsニュースモジュールの例を使用して、各変更の説明とともにモジュールの作成を段階的に示します。DSは名前空間で、Newsはモジュールの名前です。 このモジュール命名スキームは、モジュール名の名前の競合を恐れないために非常に便利です。 構成ファイルで使用される値(ノードの名前とそれらが使用される場所)の説明に特に重点を置いて説明します。 私自身は、新しいモジュールを作成するときにこのマニュアルを絶えず使用しています。 データがどこから来たか、どのクラスを継承する必要があるかなどを覚えておいてください...それは単に物理的に不可能です。 そして、ここではすべてが1つの記事にまとめられています。



システムがすでに機能していることを考慮して、Magentoのインストールと商品の充填については説明しません。 ただし、キャッシュが無効になっていることを確認する必要があります( システム/キャッシュ管理ページの管理パネルでキャッシュを無効にできます)-これは、加えられた変更をすぐに確認するために必要です。



ステップ1.システムにモジュールを登録する
最初のステップでは、何もしませんが、システムで考慮される(管理パネルに表示される)最小限のモジュールを作成します。



  1. ディレクトリ/アプリ/コード/ローカル/ DS /ニュースを作成します
  2. etc / config.xmlファイルを作成します

    <?xml version="1.0" ?> <config> <modules> <DS_News> <version>0.0.1</version> </DS_News> </modules> </config>
          
          





  3. ディレクトリ/ app / etc / modules /に DS_News.xmlファイルを作成します

     <?xml version="1.0" ?> <config> <modules> <DS_News> <active>true</active> <codePool>local</codePool> </DS_News> </modules> </config>
          
          









このディレクトリ構造とファイルの作成の結果、DS_Newsモジュールがシステムに登録されます。 このモジュールは、[ システム ]、[ 構成 ]、[ 詳細]、[詳細]、[モジュール出力の無効化 ]のパスの下にある管理パネルのモジュールのリストで確認できます。



ステップ1では、ディレクトリ/ app / code / local / DS / Newsが作成され 、そこにモジュールのメインコードが格納されます:モデル、コントローラー、ヘルパーなど。ステップ2では、ディレクトリなどが作成され、モジュール構成ファイルが格納されます。メインの構成ファイルconfig.xmlが作成されますが 、ここではモジュールのバージョンのみが示されています。 パラグラフ3では、モジュールはシステムに登録されています。



実際、モジュール登録タスクで最も重要なのはポイント3です。モジュールディレクトリがない場合でも、モジュールは管理パネルに表示されます。 / app / etc / modules /ディレクトリDS_News.xmlファイルもオプションです-システムをロードするとき、このディレクトリからすべてのXMLファイルを解析します。 これは、相互接続された複数のモジュールがインストールされている開発中に便利です。すべてのモジュールを1つのXMLファイルで指定できます。



xmlファイル内のDS_Newsモジュールの名前は、 [名前空間ディレクトリ名] _ [モジュールディレクトリ名]の2つの部分で構成されています。 この命名方法に関連して、ディレクトリ名は文字のみで作成することをお勧めします。また、大文字と小文字の違いを考慮することも重要です。* nixシステムで正常に動作するには、設定ファイルのモジュール名がディレクトリ名と正確に一致する必要があります。



/app/etc/modules/DS_News.xmlファイルは、 activecodePoolの 2つのタグを使用します。 最初のタグはモジュールの有効化/無効化を担当し、2番目はディレクトリ/ app / code /内の場所: コア (システムコア)、 コミュニティ (Magentoコミュニティが開発したモジュール)またはローカル (他の開発者が開発したモジュール)です。







ステップ2.データベースの初期化
ニュースモジュールを機能させるには、ニュースを保存するテーブルを作成する必要があります。 Magentoでは、モジュールのインストール時にテーブルを作成/更新できます。



  1. sql / dsnews_setup / install-0.0.1.phpファイルを作成します

     <?php die('DS News module setup'); $installer = $this; $installer->startSetup(); $installer->run("CREATE TABLE ds_news_entities ( `news_id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT, `title` VARCHAR(255) NOT NULL, `content` TEXT NOT NULL, `created` DATETIME, PRIMARY KEY (`news_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;"); $installer->endSetup();
          
          





  2. etc / config.xml構成ファイルにインストール用のリソースを含むセクションを追加します。

     <?xml version="1.0" ?> <config> <modules> ... </modules> <global> <resources> <dsnews_setup> <setup> <module>DS_News</module> </setup> </dsnews_setup> </resources> </global> </config>
          
          









変更が行われた後、ブラウザでサイトを開くだけです。 DS Newsモジュールのセットアップが表示されたら、すべて問題ありません。 少し後、 install-0.0.1.phpファイルのdieの行をコメントアウトし、ブラウザーウィンドウを更新できます。その後、モジュールがcore_resourceテーブルに登録され、 ds_news_entitiesテーブルがデータベースに作成されます。



碑文が表示されない場合、ほとんどの場合、モジュールはシステムに既にインストールされています。インストールには、SQLマネージャーを使用してデータベースのcore_resourceテーブルからdsnews_setupリソースレコードを削除し、サイトでブラウザーウィンドウを再更新する必要があります:



 DELETE FROM `core_resource` WHERE `code` = 'dsnews_setup';
      
      







config.xmldsnews_setupノード任意です。 主なことは、このノードの名前が、インストールするファイルが置かれるディレクトリの名前と一致することです。 また、このノードの名前は、システム内で一意である必要があります。 この名前は、インストールされているすべてのリソースを格納するcore_resourceテーブルのプライマリキーとして使用されます。



インストールディレクトリ内のファイルの名前は、特定の構造に対応している必要があります。 インストールファイルの場合はinstall- [version]。[Php | sql]で、更新ファイルの場合はupgrade- [version-from]-[version-to]。[Php | sql]です。 Mage_Core_Model_Resource_Setupクラスを調べると、リソースのインストール、ファイルおよびディレクトリの命名のプロセスに関する詳細を確認できます。







ステップ3. config.xmlからテーブル名を取得する
このモジュールでは将来、データベースとの連携がモデルとコレクションを通じて行われるため、テーブルの名前はインストールファイルではなく、構成ファイルに保存する必要があります。 これを行うには、 etc / config.xmlファイルと、 sql / dsnews_setup / install-0.0.1.phpインストールファイルを変更する必要があります。



  1. etc / config.xmlファイルにモデルノードconfig / global / models /を作成します

     <?xml version="1.0" ?> <config> ... <global> <models> <dsnews> <resourceModel>dsnews_resource</resourceModel> </dsnews> <dsnews_resource> <entities> <table_news> <table>ds_news_entities</table> </table_news> </entities> </dsnews_resource> </models> <resources> ... </resources> </global> </config>
          
          





  2. sql / dsnews_setup / install-0.0.1.phpファイルを編集します

     <?php $installer = $this; $tableNews = $installer->getTable('dsnews/table_news'); die($tableNews); $installer->startSetup(); $installer->getConnection()->dropTable($tableNews); $table = $installer->getConnection() ->newTable($tableNews) ->addColumn('news_id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array( 'identity' => true, 'nullable' => false, 'primary' => true, )) ->addColumn('title', Varien_Db_Ddl_Table::TYPE_TEXT, '255', array( 'nullable' => false, )) ->addColumn('content', Varien_Db_Ddl_Table::TYPE_TEXT, null, array( 'nullable' => false, )) ->addColumn('created', Varien_Db_Ddl_Table::TYPE_DATETIME, null, array( 'nullable' => false, )); $installer->getConnection()->createTable($table); $installer->endSetup();
          
          









ブラウザにds_news_entities テーブルの名前が表示されたら、すべてが正しく行われています-dieで行を削除し、ウィンドウを更新してモジュールのインストールを完了できます。 それ以外の場合は、SQLマネージャーを使用してcore_resourceテーブルからモジュールリソースレコードを削除する必要があります。



 DELETE FROM `core_resource` WHERE `code` = 'dsnews_setup';
      
      







このテーブルが前の段階で作成された場合にSQLエラーが発生するのを防ぐために、既存のテーブルを事前に削除するためのコードがインストールファイルに追加されました。 また、同じテーブルを作成するためのコードが抽象に変更されました。テーブルは抽象接続クラスを使用して作成され、MySQL以外のデータベースをさらにサポートできるようになります。



dsnewsモデルノードの名前、 および config / global / models /にあるdsnews_resourceモデルリソースノードの名前は任意です。 唯一の要件は、システムの他のモデル/リソース間のノード名の一意性です。



段落2のインストーラーコード内では、関数の$ installer-> getTable( 'dsnews / table_news')を使用してテーブルの名前が要求されます。この関数は文字列を引数として受け取ります

[モデルノードの名前] / [リソースのエンティティノードの名前] Magentoロジックによると、データベースとの低レベルの対話はリソースモデルを使用して行われるため、モデルノード自体にはテーブルの名前は保存されません。 このため、モデルはresourceModelタグのリソースモデルのノードへのリンクのみを保存します。







ステップ4.フロントエンドを介してモジュールにアクセスする
次に、サイトに「Hello World」という碑文を表示します。



  1. フロントエンドセクションをetc / config.xml構成ファイルに追加します

     <?xml version="1.0" ?> <config> <modules> ... </modules> <frontend> <routers> <dsnews> <use>standard</use> <args> <module>DS_News</module> <frontName>news</frontName> </args> </dsnews> </routers> </frontend> <global> ... </global> </config>
          
          





  2. ファイルコントローラーの作成/ IndexController.php

     <?php class DS_News_IndexController extends Mage_Core_Controller_Front_Action { public function indexAction() { echo '<h1>News</h1>'; } }
          
          









これで、「 http://site.com/news/ 」で「News」という単語が表示されます。



config / frontend / routers /セクションにあるdsnewsノードの名前は任意です。 唯一の要件は、システムの他のルーター間での名前の一意性です。 より重要なのは、 frontNameノードの値です。この値は、要求処理中に目的のモジュールを決定するために使用されます。



パスは、 http:// [site] / [router] / [controller] / [action]のように定義されます。 要求する場合、 [action]または[controller] / [action]のペアを省略できます。その後、欠落しているパラメーターの代わりに、デフォルト値のインデックスが使用されます。 したがって、パスhttp://site.com/news/、http://site.com/news/index/、http://site.com/news/index/indexは同等です-DS Newsモジュール、コントローラーにアクセスしますIndexControllerおよびindexActionアクション。







ステップ5.テンプレートを使用してデータを出力する
情報はコントローラで直接生成できます。または、特別なテンプレートを使用して、プログラムロジックから表示ロジックを分離できます。



  1. テンプレートファイルを作成する/app/design/frontend/[package†/[theme†/template/ds_news/index.phtml

     <h1>Template ds_news/index.phtml</h1>
          
          





  2. ページレイアウト構成ファイルを作成する/app/design/frontend/[packageapter/[theme†/layout/ds_news.xml

     <?xml version="1.0" ?> <layout> <dsnews_index_index> <reference name="content"> <block type="core/template" template="ds_news/index.phtml" /> </reference> </dsnews_index_index> </layout>
          
          





  3. etc / config.xml構成ファイルにレイアウトセクションを追加します

     <?xml version="1.0" ?> <config> <modules> ... </modules> <frontend> <layout> <updates> <dsnews> <file>ds_news.xml</file> </dsnews> </updates> </layout> <routers> ... </routers> </frontend> <global> ... </global> </config>
          
          





  4. コントローラーコントローラーの変更/ IndexController.php

     <?php class DS_News_IndexController extends Mage_Core_Controller_Front_Action { public function indexAction() { $this->loadLayout(); $this->renderLayout(); } }
          
          









これで、パスhttp://site.com/news/に沿って、すべてのブロック(ヘッダー、フッター、サイドバー)でサイトページが開き、サイトのコンテンツに「テンプレートds_news / index.phtml」が表示されます。



すべてのテンプレートはテンプレートディレクトリに保存され、ページレイアウト設定は現在のテーマディレクトリ/ app / design / frontend / [package] / [theme]に保存されます。 Magentoで作業する場合、Magentoのバージョンを更新するときに基本テーマのコンテンツが上書きされる可能性があるため、基本テーマ/アプリ/デザイン/フロントエンド/ベース/および/アプリ/デザイン/フロントエンド/デフォルト/のコンテンツに触れることなく、独自のテーマを作成する必要があります。



コントローラーアクションでページレイアウト$ this-> loadLayout()を初期化すると、ページレイアウトレイアウトが順番に読み込まれ、互いに変更される可能性があります。 デフォルトでは、デフォルトのハンドルが最初にロードされ、最後の1つは[router] _ [controller] _ [action]という名前のハンドルです[router]config / frontend / routers / [router]ノードの名前です。



節2は、コントローラー/アクションのレイアウトハンドルを定義しますdsnews_index_index 、その内部に組み込みのコア/テンプレートタイプのブロックが作成され、節1で作成されたdsnews / index.phtmlテンプレートが作成されます。節3では、 config / frontend / layout / sectionが構成ファイルに追加されますupdatesは、テーマの初期化時に適用される更新ファイルを指定します。



テーマのレイアウトにそれほど多くの変更がなく、モジュールを他のプロジェクトに実装する予定がない場合、 レイアウトハンドルをファイル/app/design/frontend/[packageapter/[theme†/layout/local.xmlに配置できます。

すべての更新後に常にロードされます-このファイルをconfig.xmlモジュール構成ファイルに登録する必要はありません



レイアウトハンドルの正しい名前を決定するのが困難な場合、コントローラーで使用されるハンドルのリストを見ることができます。

 <?php class DS_News_IndexController extends Mage_Core_Controller_Front_Action { public function indexAction() { $this->loadLayout(); $layoutHandles = $this->getLayout()->getUpdate()->getHandles(); echo '<pre>' . print_r($layoutHandles, true) . '</pre>'; } }
      
      





その結果、次のような結論を確認できます。

配列
 (
     [0] =>デフォルト
     [1] => STORE_default
     [2] => THEME_frontend_ [パッケージ] _ [テーマ]
     [3] => dsnews_index_index
     [4] => customer_logged_out
 )








ステップ6.データベースからニュースを直接表示する
この段階で、データベースから直接データを使用して、テンプレートにニュースを表示することができます。 これを行うには、最初にいくつかのテストニュースをデータベースに追加する必要があります。



  1. 表示するテストニュースをデータベースに追加します。

     INSERT INTO `ds_news_entities` VALUES (NULL, 'News 1', 'News 1 Content', '2013-10-16 17:45'), (NULL, 'News 2', 'News 2 Content', '2013-11-07 04:12'), (NULL, 'News 3', 'News 3 Content', '2014-01-12 15:55');
          
          





  2. テンプレートを変更します/app/design/frontend/[package†/[theme†/template/dsnews/index.phtml

     <h1>News</h1> <?php $news = Mage::registry('news'); foreach ($news as $item) { echo '<h2>' . $item['title'] . '</h2>'; }
          
          





  3. コントローラーコントローラーの変更/ IndexController.php

     <?php class DS_News_IndexController extends Mage_Core_Controller_Front_Action { public function indexAction() { $resource = Mage::getSingleton('core/resource'); $read = $resource->getConnection('core_read'); $table = $resource->getTableName('dsnews/table_news'); $select = $read->select() ->from($table, array('news_id', 'title', 'content', 'created')) ->order('created DESC'); $news = $read->fetchAll($select); Mage::register('news', $news); $this->loadLayout(); $this->renderLayout(); } }
          
          









この例は、データベースからのデータの直接リクエストと、 Mage ::レジストリレジストリを使用してコントローラからテンプレートにニュースを転送することを示しています。 レジストリは、コードのどの部分でもグローバルに利用可能であり、まれに、困難な状況で最も最適なソリューションです。



レジストリを使用すること、およびグローバル変数を使用することは、低品質コードの兆候と見なされます。 データベースへの直接アクセスも推奨されません。これは、コードの互換性と移植性の潜在的な問題だからです。 次のセクションで説明するモデルやコレクションなどのオブジェクトを操作するために、システム自体が提供する機能を使用することをお勧めします。







ステップ7.モデルの作成と使用
Magento(および他の多くのOOPシステム)のロジックによれば、データの取得および保存の方法を考慮せずに、オブジェクト/モデルおよびコレクションのレベルでデータ処理を実行する必要があります。 データの取得と保存の操作は、リソースモデルに下位レベルとして残されます-その後、データの保存方法(データベース、ファイルなど)を変更する場合、処理ロジックを変更する必要はありませんが、リソースモデルを変更するだけで、データの受信と保存に従事。 モデルを使用してニュース出力をやり直し、IDによるニュースコンテンツの出力も追加します。



  1. 構成ファイル内のモデルノードにクラスノードを追加します。

     <?xml version="1.0" ?> <config> <modules> ... </modules> <frontend> ... </frontend> <global> <models> <dsnews> <class>DS_News_Model</class> <resourceModel>dsnews_resource</resourceModel> </dsnews> <dsnews_resource> <class>DS_News_Model_Resource</class> <entities> <table_news> <table>ds_news_entities</table> </table_news> </entities> </dsnews_resource> </models> <resources> ... </resources> </global> </config>
          
          





  2. ニュースモデルファイルモデルの作成/ News.php

     <?php class DS_News_Model_News extends Mage_Core_Model_Abstract { public function _construct() { parent::_construct(); $this->_init('dsnews/news'); } }
          
          





  3. ニュースモデルリソースファイルモデルの作成/リソース/News.php

     <?php class DS_News_Model_Resource_News extends Mage_Core_Model_Mysql4_Abstract { public function _construct() { $this->_init('dsnews/table_news', 'news_id'); } }
          
          





  4. コレクションリソースファイルを作成するModel / Resource / News / Collection.php

     <?php class DS_News_Model_Resource_News_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract { public function _construct() { parent::_construct(); $this->_init('dsnews/news'); } }
          
          





  5. コントローラーコントローラーの変更/ IndexController.php

     <?php class DS_News_IndexController extends Mage_Core_Controller_Front_Action { public function indexAction() { $news = Mage::getModel('dsnews/news')->getCollection()->setOrder('created', 'DESC'); $viewUrl = Mage::getUrl('news/index/view'); echo '<h1>News</h1>'; foreach ($news as $item) { echo '<h2><a href="' . $viewUrl . '?id=' . $item->getId() . '">' . $item->getTitle() . '</a></h2>'; } } public function viewAction() { $newsId = Mage::app()->getRequest()->getParam('id', 0); $news = Mage::getModel('dsnews/news')->load($newsId); if ($news->getId() > 0) { echo '<h1>' . $news->getTitle() . '</h1>'; echo '<div class="content">' . $news->getContent() . '</div>'; } else { $this->_forward('noRoute'); } } }
          
          









これで、リンクhttp://site.com/newsをクリックすると、ニュースの内容を含むページが開くリンクをクリックすると、リンクの形でニュースのリストが開きます。



ステップ1では、 クラスノードが構成ファイルに追加され、 DS_News_ModelモデルとDS_News_Model_Resourceリソースの基本的なクラスプレフィックスが登録されます。



コントローラー(アイテム5)のモデルを要求するとき、 Mage :: getModel( 'dsnews / news')getModel関数は、モデルクラス名の形成元である[model] / [class]型の文字列を受け入れます。 [model]は構成ノードの名前です/ global / models / [model]クラスノードの値の取得元-DS_News_Model 、および値[class]がこのクラスプレフィックスに追加されます(各単語[class]の最初の文字は大文字に変換されます)。 たとえば、 DS_News_Model_Newsクラスはdsnews / news から取得され、 DS_News_Model_News_Galleryクラスはdsnews / news_gallery から取得されます。



節2では、基本的なDS_News_Model_Newsニュースモデルが作成され 、そのコンストラクターでリソース$ this-> _ init( 'dsnews / news')が初期化されます:パラメーターとして、関数は文字列[model] / [class]を取ります。 [model]はノードの名前ですconfig / global / models / [model] 、および[class]クラスの名前です。 ただし、モデルとは異なり、リソースクラスをクラスプレフィックスとして初期化するには、 resourceModelノードのモデルによって参照されるリソースconfig / global / models / [resourceModel] / classノードの値を使用します。 その結果、リソース$ this-> _ init( 'dsnews / news')を初期化するときに、 DS_News_Model_Resource_Newsクラスが初期化されます。



ステップ3では、リソースクラスDS_News_Model_Resource_Newsが作成されます。 このクラスでは、テーブル$ this-> _ init( 'dsnews / table_news'、 'news_id')が初期化されます 。最初のパラメーターは目的のテーブルの名前へのパスで、2番目は主キーとして使用されるフィールドです(主キー)テーブル。



節4では、オブジェクトコレクションクラスが初期化され、そのコンストラクターで初期モデルDS_News_Model_Newsが初期化されます。



パラグラフ5では、データベースからのデータの受信に変更があります。 今回は、モデルとコレクションが使用されます。 indexActionアクションでは、すべてのニュースは$ news = Mage :: getModel( 'dsnews / news')-> getCollection()collectionを取得することで要求されます。 コレクションクラスの名前は、モデルDS_News_Model_Resource_News + _Collectionのリソースクラスの名前から計算されます。



viewActionアクションでは、リクエストで受信したIDによってニュースがダウンロードされます。 このIDのニュースが存在する場合、ニュースとコンテンツの名前が表示されます。 それ以外の場合、ページ404が生成されます。







ステップ8.ブロックの作成と使用
Magentoは、データを出力するために特別なブロックを使用します-これらは、コードの特定のセクションをレンダリングするコードオブジェクトです。 ステップ5:データ出力用のテンプレートの使用では、標準のコア/テンプレートブロックが使用されました。 このステップでは、ニュースのリストとコンテンツを表示するために、ニュースモジュール用のブロックが作成されます。



  1. ブロックノード構成/グローバル/ブロックを追加

     <?xml version="1.0" ?> <config> ... <global> <blocks> <dsnews> <class>DS_News_Block</class> </dsnews> </blocks> ... </global> </config>
          
          





  2. ニュースリストブロッククラスBlock / News.phpを作成する

     <?php class DS_News_Block_News extends Mage_Core_Block_Template { public function getNewsCollection() { $newsCollection = Mage::getModel('dsnews/news')->getCollection(); $newsCollection->setOrder('created', 'DESC'); return $newsCollection; } }
          
          





  3. ニュースコンテンツブロッククラスBlock / View.phpを作成する

     <?php class DS_News_Block_View extends Mage_Core_Block_Template { }
          
          





  4. 構成ファイルの更新/app/design/frontend/[package†/[theme†/layout/ds_news.xml

     <layout> <dsnews_index_index> <reference name="content"> <block type="dsnews/news" template="ds_news/index.phtml" /> </reference> </dsnews_index_index> <dsnews_index_view> <reference name="content"> <block type="dsnews/view" name="news.content" template="ds_news/view.phtml" /> </reference> </dsnews_index_view> </layout>
          
          





  5. テンプレートファイルを編集します/app/design/frontend/[package†/[theme†/template/ds_news/index.phtml

     <?php $news = $this->getNewsCollection(); $newsViewUrl = Mage::getUrl('news/index/view'); ?> <h1>News</h1> <?php foreach ($news as $item): ?> <h2> <a href="<?php echo $newsViewUrl; ?>?id=<?php echo $item->getId(); ?>"> <?php echo $item->getTitle(); ?> </a> </h2> <?php endforeach; ?>
          
          





  6. テンプレートファイルを作成します/app/design/frontend/[packageapter/[theme†/template/ds_news/view.phtml

     <h1><?php echo $newsItem->getTitle(); ?></h1> <div class="content"><?php echo $newsItem->getContent(); ?></div>
          
          





  7. コントローラーコントローラーの変更/ IndexController.php

     <?php class DS_News_IndexController extends Mage_Core_Controller_Front_Action { public function indexAction() { $this->loadLayout(); $this->renderLayout(); } public function viewAction() { $newsId = Mage::app()->getRequest()->getParam('id', 0); $news = Mage::getModel('dsnews/news')->load($newsId); if ($news->getId() > 0) { $this->loadLayout(); $this->getLayout()->getBlock('news.content')->assign(array( "newsItem" => $news, )); $this->renderLayout(); } else { $this->_forward('noRoute'); } } }
          
          









ページhttp://site.com/news/を開くと、サイトページのコンテンツとしてニュースリストが表示され、ニュースリンクをクリックすると、ニュースコンテンツのあるページが開きます。



ブロックメカニズムにより、コントローラーに関係なく表示ロジックを使用できます。 パラグラフ3からわかるように、 indexActionアクションはテンプレートのロードと表示のみを処理するようになりました。 ニュースを受信するためのロジックはDS_News_Block_Newsブロックにあり、表示ロジックは/app/design/frontend/[package†/[theme†/template/dsnews/index.phtmlテンプレートにあります。 したがって、たとえば、最近のニュースのリストを他のページのサイドバーに表示する必要がある場合は、コントローラーを使用せずに目的のブロックをページに接続するだけで十分です。



$this , / - .



1 , Magento . , (type) .xml . type [module]/[block] , [module]config/global/blocks/[module] , class ; a [block] — . type=«dsnews/news» DS_News_Block_News .



4 <reference name=«content» . , , . layout handle dsnews_index_view , <block type=«dsnews/view» name=«news.content» template=«ds_news/view.phtml» /> . viewAction assign , . .







ステップ9.モジュールの管理パネルを作成する
, , - . .



  1. controllers/Adminhtml/NewsController.php

     <?php class DS_News_Adminhtml_NewsController extends Mage_Adminhtml_Controller_Action { public function indexAction() { echo '<h1>News Module: Admin section</h1>'; } }
          
          





  2. etc/config.xml

     <?xml version="1.0" ?> <config> ... <admin> <routers> <dsnews_admin> <use>admin</use> <args> <module>DS_News</module> <frontName>dsnews_admin</frontName> </args> </dsnews_admin> </routers> </admin> ... </config>
          
          





  3. , etc/config.xml

     <?xml version="1.0" ?> <config> ... <adminhtml> <menu> <dsnews module="dsnews"> <title>News</title> <sort_order>77</sort_order> <action>dsnews_admin/adminhtml_news</action> </dsnews> </menu> </adminhtml> ... </config>
          
          





  4. - Helper/Data.php

     <?php class DS_News_Helper_Data extends Mage_Core_Helper_Abstract { }
          
          





  5. etc/config.xml

     <?xml version="1.0" ?> <config> ... <global> ... <helpers> <dsnews> <class>DS_News_Helper</class> </dsnews> </helpers> ... </global> ... </config>
          
          









, , News , «News Module: Admin section» .



1 , 2 — config/admin/routers/[router] . , http://site.com/index.php/[frontName]/[controller]/index/ , [frontName]config/admin/routers/[router]/args/[frontName] , [controller] — , DS_News + [controller] + Controller . adminhtml_news DS_News_Adminhtml_NewsController . http://site.com/index.php/dsnews_admin/adminhtml_news/index/ .



, Magento - . , . 3 , .



4 5, , «Warning: include(Mage\DS\News\Helper\Data.php): failed to open stream: No such file or directory...» . Magento , module config/adminhtml/menu/[menu] . config/global/helpers/[helper] , . 4 5 -, .



, — frontName config/admin/routers config/frontend/routers .

( ), , HTTPS .







ステップ10.管理パネルでブロックを使用する
. .



  1. controllers/Adminhtml/NewsController.php

     <?php class DS_News_Adminhtml_NewsController extends Mage_Adminhtml_Controller_Action { public function indexAction() { $this->loadLayout(); $this->_setActiveMenu('dsnews'); $contentBlock = $this->getLayout()->createBlock('dsnews/adminhtml_news'); $this->_addContent($contentBlock); $this->renderLayout(); } }
          
          





  2. Block/Adminhtml/News.php

     <?php class DS_News_Block_Adminhtml_News extends Mage_Adminhtml_Block_Abstract { public function _toHtml() { return '<h1>News Module: Admin section</h1>'; } }
          
          









Magento , frontend ( ), backend () . .xml / ( 5: « »), , - Magento, . HTML « » . , /app/design/adminhtml/default/default/ , , .. .



1 $this->loadLayout() . $this->getLayout() : // . createBlock [module]/[block] , <block type="[module]/[block]" ; .







ステップ11.データグリッドにリストする
, .



  1. Block/Adminhtml/News.php

     <?php class DS_News_Block_Adminhtml_News extends Mage_Adminhtml_Block_Widget_Grid_Container { protected function _construct() { parent::_construct(); $helper = Mage::helper('dsnews'); $this->_blockGroup = 'dsnews'; $this->_controller = 'adminhtml_news'; $this->_headerText = $helper->__('News Management'); $this->_addButtonLabel = $helper->__('Add News'); } }
          
          





  2. Block/Adminhtml/News/Grid.php

     <?php class DS_News_Block_Adminhtml_News_Grid extends Mage_Adminhtml_Block_Widget_Grid { protected function _prepareCollection() { $collection = Mage::getModel('dsnews/news')->getCollection(); $this->setCollection($collection); return parent::_prepareCollection(); } protected function _prepareColumns() { $helper = Mage::helper('dsnews'); $this->addColumn('news_id', array( 'header' => $helper->__('News ID'), 'index' => 'news_id' )); $this->addColumn('title', array( 'header' => $helper->__('Title'), 'index' => 'title', 'type' => 'text', )); $this->addColumn('created', array( 'header' => $helper->__('Created'), 'index' => 'created', 'type' => 'date', )); return parent::_prepareColumns(); } }
          
          









, 1 DS_News_Block_Adminhtml_News : [_blockGroup]/[_controller]_grid , _blockGroupconfig/global/blocks/[_blockGroup] . «dsnews/adminhtml_news_grid» .



_prepareColumns , . addColumn , — , index — , type — . Mage_Adminhtml_Block_Widget_Grid_Column .







手順12.データグリッドでの一括操作




  1. Block/Adminhtml/News/Grid.php _prepareMassaction

     <?php class DS_News_Block_Adminhtml_News_Grid extends Mage_Adminhtml_Block_Widget_Grid { protected function _prepareCollection(){ ... } protected function _prepareColumns(){ ... } protected function _prepareMassaction() { $this->setMassactionIdField('news_id'); $this->getMassactionBlock()->setFormFieldName('news'); $this->getMassactionBlock()->addItem('delete', array( 'label' => $this->__('Delete'), 'url' => $this->getUrl('*/*/massDelete'), )); return $this; } }
          
          





  2. massDeleteAction controllers/Adminhtml/NewsController.php

     <?php class DS_News_Adminhtml_NewsController extends Mage_Adminhtml_Controller_Action { public function indexAction(){ ... } public function massDeleteAction() { $news = $this->getRequest()->getParam('news', null); if (is_array($news) && sizeof($news) > 0) { try { foreach ($news as $id) { Mage::getModel('dsnews/news')->setId($id)->delete(); } $this->_getSession()->addSuccess($this->__('Total of %d news have been deleted', sizeof($news))); } catch (Exception $e) { $this->_getSession()->addError($e->getMessage()); } } else { $this->_getSession()->addError($this->__('Please select news')); } $this->_redirect('*/*'); } }
          
          









. , Actions Delete Submit .



1 _prepareMassaction , id- news_id , , id-. — , , . : . , . Mage_Adminhtml_Block_Catalog_Product_Grid .







ステップ13. CRUD:追加、編集、削除
,



  1. controllers/Adminhtml/NewsController.php

     <?php class DS_News_Adminhtml_NewsController extends Mage_Adminhtml_Controller_Action { public function indexAction() { $this->loadLayout()->_setActiveMenu('dsnews'); $this->_addContent($this->getLayout()->createBlock('dsnews/adminhtml_news')); $this->renderLayout(); } public function newAction() { $this->_forward('edit'); } public function editAction() { $id = (int) $this->getRequest()->getParam('id'); Mage::register('current_news', Mage::getModel('dsnews/news')->load($id)); $this->loadLayout()->_setActiveMenu('dsnews'); $this->_addContent($this->getLayout()->createBlock('dsnews/adminhtml_news_edit')); $this->renderLayout(); } public function saveAction() { if ($data = $this->getRequest()->getPost()) { try { $model = Mage::getModel('dsnews/news'); $model->setData($data)->setId($this->getRequest()->getParam('id')); if(!$model->getCreated()){ $model->setCreated(now()); } $model->save(); Mage::getSingleton('adminhtml/session')->addSuccess($this->__('News was saved successfully')); Mage::getSingleton('adminhtml/session')->setFormData(false); $this->_redirect('*/*/'); } catch (Exception $e) { Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); Mage::getSingleton('adminhtml/session')->setFormData($data); $this->_redirect('*/*/edit', array( 'id' => $this->getRequest()->getParam('id') )); } return; } Mage::getSingleton('adminhtml/session')->addError($this->__('Unable to find item to save')); $this->_redirect('*/*/'); } public function deleteAction() { if ($id = $this->getRequest()->getParam('id')) { try { Mage::getModel('dsnews/news')->setId($id)->delete(); Mage::getSingleton('adminhtml/session')->addSuccess($this->__('News was deleted successfully')); } catch (Exception $e) { Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); $this->_redirect('*/*/edit', array('id' => $id)); } } $this->_redirect('*/*/'); } public function massDeleteAction(){ ... } }
          
          





  2. getRowUrl Block/Adminhtml/News/Grid.php

     <?php class DS_News_Block_Adminhtml_News_Grid extends Mage_Adminhtml_Block_Widget_Grid { protected function _prepareCollection(){ ... } protected function _prepareColumns(){ ... } protected function _prepareMassaction(){ ... } public function getRowUrl($model) { return $this->getUrl('*/*/edit', array( 'id' => $model->getId(), )); } }
          
          





  3. Block/Adminhtml/News/Edit.php

     <?php class DS_News_Block_Adminhtml_News_Edit extends Mage_Adminhtml_Block_Widget_Form_Container { protected function _construct() { $this->_blockGroup = 'dsnews'; $this->_controller = 'adminhtml_news'; } public function getHeaderText() { $helper = Mage::helper('dsnews'); $model = Mage::registry('current_news'); if ($model->getId()) { return $helper->__("Edit News item '%s'", $this->escapeHtml($model->getTitle())); } else { return $helper->__("Add News item"); } } }
          
          





  4. Block/Adminhtml/News/Edit/Form.php

     <?php class DS_News_Block_Adminhtml_News_Edit_Form extends Mage_Adminhtml_Block_Widget_Form { protected function _prepareForm() { $helper = Mage::helper('dsnews'); $model = Mage::registry('current_news'); $form = new Varien_Data_Form(array( 'id' => 'edit_form', 'action' => $this->getUrl('*/*/save', array( 'id' => $this->getRequest()->getParam('id') )), 'method' => 'post', 'enctype' => 'multipart/form-data' )); $this->setForm($form); $fieldset = $form->addFieldset('news_form', array('legend' => $helper->__('News Information'))); $fieldset->addField('title', 'text', array( 'label' => $helper->__('Title'), 'required' => true, 'name' => 'title', )); $fieldset->addField('content', 'editor', array( 'label' => $helper->__('Content'), 'required' => true, 'name' => 'content', )); $fieldset->addField('created', 'date', array( 'format' => Mage::app()->getLocale()->getDateFormat(Mage_Core_Model_Locale::FORMAT_TYPE_SHORT), 'image' => $this->getSkinUrl('images/grid-cal.gif'), 'label' => $helper->__('Created'), 'name' => 'created' )); $form->setUseContainer(true); if($data = Mage::getSingleton('adminhtml/session')->getFormData()){ $form->setValues($data); } else { $form->setValues($model->getData()); } return parent::_prepareForm(); } }
          
          









Data Grid , Add News — .



1 new , edit , save delete , . new edit , new edit . , ( , ), . save

$model->setData($data)->setId(...) — , .. , setData . , .



2 Data Grid — . 3 , , [_blockGroup]/[_controller]_[_mode]_form , dsnews/adminhtml_news_edit_form ( _mode edit ).



. , new Varien_Data_Form id HTML id , .. JavaScript-, . , name .







ステップ14.タブを使用する
, TAB-.



  1. controllers/Adminhtml/NewsController.php

     <?php class DS_News_Adminhtml_NewsController extends Mage_Adminhtml_Controller_Action { public function indexAction(){ ... } public function newAction(){ ... } public function editAction() { $id = (int) $this->getRequest()->getParam('id'); $model = Mage::getModel('dsnews/news'); if($data = Mage::getSingleton('adminhtml/session')->getFormData()){ $model->setData($data)->setId($id); } else { $model->load($id); } Mage::register('current_news', $model); $this->loadLayout()->_setActiveMenu('dsnews'); $this->_addLeft($this->getLayout()->createBlock('dsnews/adminhtml_news_edit_tabs')); $this->_addContent($this->getLayout()->createBlock('dsnews/adminhtml_news_edit')); $this->renderLayout(); } public function saveAction(){ ... } public function deleteAction() { ... } public function massDeleteAction(){ ... } }
          
          





  2. Block/Adminhtml/News/Edit/Tabs.php

     <?php class DS_News_Block_Adminhtml_News_Edit_Tabs extends Mage_Adminhtml_Block_Widget_Tabs { public function __construct() { $helper = Mage::helper('dsnews'); parent::__construct(); $this->setId('news_tabs'); $this->setDestElementId('edit_form'); $this->setTitle($helper->__('News Information')); } protected function _prepareLayout() { $helper = Mage::helper('dsnews'); $this->addTab('general_section', array( 'label' => $helper->__('General Information'), 'title' => $helper->__('General Information'), 'content' => $this->getLayout()->createBlock('dsnews/adminhtml_news_edit_tabs_general')->toHtml(), )); $this->addTab('custom_section', array( 'label' => $helper->__('Custom Fields'), 'title' => $helper->__('Custom Fields'), 'content' => $this->getLayout()->createBlock('dsnews/adminhtml_news_edit_tabs_custom')->toHtml(), )); return parent::_prepareLayout(); } }
          
          





  3. Block/Adminhtml/News/Edit/Form.php

     <?php class DS_News_Block_Adminhtml_News_Edit_Form extends Mage_Adminhtml_Block_Widget_Form { protected function _prepareForm() { $form = new Varien_Data_Form(array( 'id' => 'edit_form', 'action' => $this->getUrl('*/*/save', array( 'id' => $this->getRequest()->getParam('id') )), 'method' => 'post', 'enctype' => 'multipart/form-data' )); $form->setUseContainer(true); $this->setForm($form); return parent::_prepareForm(); } }
          
          





  4. General Block/Adminhtml/News/Edit/Tabs/General.php

     <?php class DS_News_Block_Adminhtml_News_Edit_Tabs_General extends Mage_Adminhtml_Block_Widget_Form { protected function _prepareForm() { $helper = Mage::helper('dsnews'); $model = Mage::registry('current_news'); $form = new Varien_Data_Form(); $fieldset = $form->addFieldset('general_form', array( 'legend' => $helper->__('General Information') )); $fieldset->addField('title', 'text', array( 'label' => $helper->__('Title'), 'required' => true, 'name' => 'title', )); $fieldset->addField('content', 'editor', array( 'label' => $helper->__('Content'), 'required' => true, 'name' => 'content', )); $fieldset->addField('created', 'date', array( 'format' => Mage::app()->getLocale()->getDateFormat(Mage_Core_Model_Locale::FORMAT_TYPE_SHORT), 'image' => $this->getSkinUrl('images/grid-cal.gif'), 'label' => $helper->__('Created'), 'name' => 'created' )); $form->setValues($model->getData()); $this->setForm($form); return parent::_prepareForm(); } }
          
          





  5. Custom

    Block/Adminhtml/News/Edit/Tabs/Custom.php

     <?php class DS_News_Block_Adminhtml_News_Edit_Tabs_Custom extends Mage_Adminhtml_Block_Widget { protected function _toHtml() { return '<h2>Custom Fields</h2>'; } }
          
          









. 2 — , — . , General, .



, , . 2 - , _prepareLayout . . , General $form = new Varien_Data_Form() , , — .







ステップ15.画像アップロードフィールドを追加する
.



  1. General Block/Adminhtml/News/Edit/Tabs/General.php

     <?php class DS_News_Block_Adminhtml_News_Edit_Tabs_General extends Mage_Adminhtml_Block_Widget_Form { protected function _prepareForm() { $helper = Mage::helper('dsnews'); $model = Mage::registry('current_news'); $form = new Varien_Data_Form(); $fieldset = $form->addFieldset('general_form', array('legend' => $helper->__('General Information'))); $fieldset->addField('title', 'text', array( 'label' => $helper->__('Title'), 'required' => true, 'name' => 'title', )); $fieldset->addField('content', 'editor', array( 'label' => $helper->__('Content'), 'required' => true, 'name' => 'content', )); $fieldset->addField('image', 'image', array( 'label' => $helper->__('Image'), 'name' => 'image', )); $fieldset->addField('created', 'date', array( 'format' => Mage::app()->getLocale()->getDateFormat(Mage_Core_Model_Locale::FORMAT_TYPE_SHORT), 'image' => $this->getSkinUrl('images/grid-cal.gif'), 'label' => $helper->__('Created'), 'name' => 'created' )); $formData = array_merge($model->getData(), array('image' => $model->getImageUrl())); $form->setValues($formData); $this->setForm($form); return parent::_prepareForm(); } }
          
          





  2. Helper/Data.php

     <?php class DS_News_Helper_Data extends Mage_Core_Helper_Abstract { public function getImagePath($id = 0) { $path = Mage::getBaseDir('media') . '/ds_news'; if ($id) { return "{$path}/{$id}.jpg"; } else { return $path; } } public function getImageUrl($id = 0) { $url = Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_MEDIA) . 'ds_news/'; if ($id) { return $url . $id . '.jpg'; } else { return $url; } } }
          
          





  3. Model/News.php

     <?php class DS_News_Model_News extends Mage_Core_Model_Abstract { protected function _construct() { parent::_construct(); $this->_init('dsnews/news'); } protected function _afterDelete() { $helper = Mage::helper('dsnews'); @unlink($helper->getImagePath($this->getId())); return parent::_afterDelete(); } public function getImageUrl() { $helper = Mage::helper('dsnews'); if ($this->getId() && file_exists($helper->getImagePath($this->getId()))) { return $helper->getImageUrl($this->getId()); } return null; } }
          
          





  4. controllers/Adminhtml/NewsController.php

     <?php class DS_News_Adminhtml_NewsController extends Mage_Adminhtml_Controller_Action { public function indexAction(){ ... } public function newAction(){ ... } public function editAction(){ ... } public function saveAction() { $id = $this->getRequest()->getParam('id'); if ($data = $this->getRequest()->getPost()) { try { $helper = Mage::helper('dsnews'); $model = Mage::getModel('dsnews/news'); $model->setData($data)->setId($id); if (!$model->getCreated()) { $model->setCreated(now()); } $model->save(); $id = $model->getId(); if (isset($_FILES['image']['name']) && $_FILES['image']['name'] != '') { $uploader = new Varien_File_Uploader('image'); $uploader->setAllowedExtensions(array('jpg', 'jpeg')); $uploader->setAllowRenameFiles(false); $uploader->setFilesDispersion(false); $uploader->save($helper->getImagePath(), $id . '.jpg'); // Upload the image } else { if (isset($data['image']['delete']) && $data['image']['delete'] == 1) { @unlink($helper->getImagePath($id)); } } Mage::getSingleton('adminhtml/session')->addSuccess($this->__('News was saved successfully')); Mage::getSingleton('adminhtml/session')->setFormData(false); $this->_redirect('*/*/'); } catch (Exception $e) { Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); Mage::getSingleton('adminhtml/session')->setFormData($data); $this->_redirect('*/*/edit', array( 'id' => $id )); } return; } Mage::getSingleton('adminhtml/session')->addError($this->__('Unable to find item to save')); $this->_redirect('*/*/'); } public function deleteAction(){ ... } public function massDeleteAction(){ ... } }
          
          









JPG, . /media/ds_news , , . — URL , , — . , — image : $formData = array_merge($model->getData(), array('image' => $model->getImageUrl())) .







ステップ16.管理パネルでJavaScript / CSSファイルを接続する




  1. /skin/adminhtml/default/default/ds_news/adminhtml/scripts.js

     console.log('DS News admin');
          
          





  2. /skin/adminhtml/default/default/ds_news/adminhtml/styles.css

     #general_form label { color: #FF0000; font-weight: bold; }
          
          





  3. controllers/Adminhtml/NewsController.php

     <?php class DS_News_Adminhtml_NewsController extends Mage_Adminhtml_Controller_Action { public function indexAction(){ ... } public function newAction(){ ... } public function editAction() { $id = (int) $this->getRequest()->getParam('id'); $model = Mage::getModel('dsnews/news'); if ($data = Mage::getSingleton('adminhtml/session')->getFormData()) { $model->setData($data)->setId($id); } else { $model->load($id); } Mage::register('current_news', $model); $this->loadLayout()->_setActiveMenu('dsnews'); $this->getLayout()->getBlock('head')->addItem('skin_js', 'ds_news/adminhtml/scripts.js'); $this->getLayout()->getBlock('head')->addItem('skin_css', 'ds_news/adminhtml/styles.css'); $this->_addLeft($this->getLayout()->createBlock('dsnews/adminhtml_news_edit_tabs')); $this->_addContent($this->getLayout()->createBlock('dsnews/adminhtml_news_edit')); $this->renderLayout(); } public function saveAction(){ ... } public function deleteAction(){ ... } public function massDeleteAction(){ ... } }
          
          









DS News admin , .



, , , : JS, . — /skin/adminhtml/default/default/ /js/ — . , , /js/ , — .



, /js/ /js/

 $this->getLayout()->getBlock('head')->addItem('skin_js', 'ds_news/adminhtml/scripts.js'); $this->getLayout()->getBlock('head')->addItem('skin_css', 'ds_news/adminhtml/styles.css');
      
      





 $this->getLayout()->getBlock('head')->addJs('ds_news/adminhtml/scripts.js'); $this->getLayout()->getBlock('head')->addItem('js_css', 'ds_news/adminhtml/styles.css');
      
      











ステップ17.モジュールの更新:ニュースのカテゴリーの追加
— : . , .



  1. sql/dsnews_setup/upgrade-0.0.1-0.0.2.php

     <?php echo '<h1>Upgrade DS News to version 0.0.2</h1>'; exit; $installer = $this; $tableCategories = $installer->getTable('dsnews/table_categories'); $tableNews = $installer->getTable('dsnews/table_news'); $installer->startSetup(); $installer->getConnection()->dropTable($tableCategories); $table = $installer->getConnection() ->newTable($tableCategories) ->addColumn('category_id', Varien_Db_Ddl_Table::TYPE_INTEGER, null, array( 'identity' => true, 'nullable' => false, 'primary' => true, )) ->addColumn('title', Varien_Db_Ddl_Table::TYPE_TEXT, '255', array( 'nullable' => false, )); $installer->getConnection()->createTable($table); $installer->getConnection()->addColumn($tableNews, 'category_id', array( 'comment' => 'News Category', 'default' => '0', 'nullable' => false, 'type' => Varien_Db_Ddl_Table::TYPE_INTEGER, )); $installer->endSetup();
          
          





  2. etc/config.xml

     <?xml version="1.0" ?> <config> <modules> <DS_News> <version>0.0.2</version> </DS_News> </modules> ... <global> ... <models> <dsnews> <class>DS_News_Model</class> <resourceModel>dsnews_resource</resourceModel> </dsnews> <dsnews_resource> <class>DS_News_Model_Resource</class> <entities> <table_categories> <table>ds_news_categories</table> </table_categories> <table_news> <table>ds_news_entities</table> </table_news> </entities> </dsnews_resource> </models> ... </global> </config>
          
          





  3. Model/Category.php

     <?php class DS_News_Model_Category extends Mage_Core_Model_Abstract { protected function _construct() { parent::_construct(); $this->_init('dsnews/category'); } protected function _afterDelete() { $newsCollection = Mage::getModel('dsnews/news')->getCollection() ->addFieldToFilter('category_id', $this->getId()); foreach($newsCollection as $news){ $news->setCategoryId(0)->save(); } return parent::_afterDelete(); } }
          
          





  4. Block/Adminhtml/News/Edit/Tabs/General.php

     <?php class DS_News_Block_Adminhtml_News_Edit_Tabs_General extends Mage_Adminhtml_Block_Widget_Form { protected function _prepareForm() { ... $fieldset->addField('category_id', 'select', array( 'label' => $helper->__('Category'), 'name' => 'category_id', 'values' => $helper->getCategoriesOptions(), )); ... } }
          
          





  5. Helper/Data.php ,

     <?php class DS_News_Helper_Data extends Mage_Core_Helper_Abstract { public function getImagePath($id = 0){ ... } public function getImageUrl($id = 0){ ... } public function getCategoriesList() { $categories = Mage::getModel('dsnews/category')->getCollection()->load(); $output = array(); foreach($categories as $category){ $output[$category->getId()] = $category->getTitle(); } return $output; } public function getCategoriesOptions() { $categories = Mage::getModel('dsnews/category')->getCollection()->load(); $options = array(); $options[] = array( 'label' => '', 'value' => '' ); foreach ($categories as $category) { $options[] = array( 'label' => $category->getTitle(), 'value' => $category->getId(), ); } return $options; } }
          
          





  6. Block/News/Grid.php

     <?php class DS_News_Block_Adminhtml_News_Grid extends Mage_Adminhtml_Block_Widget_Grid { protected function _prepareCollection(){ ... } protected function _prepareColumns() { $helper = Mage::helper('dsnews'); $this->addColumn('news_id', array( 'header' => $helper->__('News ID'), 'index' => 'news_id', 'width' => '100px', )); $this->addColumn('title', array( 'header' => $helper->__('Title'), 'index' => 'title', 'type' => 'text', )); $this->addColumn('category', array( 'header' => $helper->__('Category'), 'index' => 'category_id', 'options' => $helper->getCategoriesList(), 'type' => 'options', 'width' => '150px', )); $this->addColumn('created', array( 'header' => $helper->__('Created'), 'index' => 'created', 'type' => 'date', )); return parent::_prepareColumns(); } protected function _prepareMassaction(){ ... } public function getRowUrl($model){ ... } }
          
          





  7. etc/config.xml

     <?xml version="1.0" ?> <config> ... <adminhtml> <menu> <dsnews module="dsnews"> <title>News</title> <sort_order>77</sort_order> <children> <dsnews_news translate="title" module="dsnews"> <title>News</title> <sort_order>10</sort_order> <action>dsnews_admin/adminhtml_news</action> </dsnews_news> <dsnews_category translate="title" module="dsnews"> <title>Categories</title> <sort_order>20</sort_order> <action>dsnews_admin/adminhtml_category</action> </dsnews_category> </children> </dsnews> </menu> </adminhtml> ... </config>
          
          









«Upgrade DS News to version 0.0.2», — . core_resourcedsnews_setup 0.0.1 . , , comment , .



, , . , . , , . / — Magento ( /var/cache ), .. Magento !







ステップ18.タブでのデータグリッドの表示
,



  1. Model/Category.php

     <?php class DS_News_Model_Category extends Mage_Core_Model_Abstract { protected function _construct(){ ... } protected function _afterDelete() { foreach($this->getNewsCollection() as $news){ $news->setCategoryId(0)->save(); } return parent::_afterDelete(); } public function getNewsCollection() { $collection = Mage::getModel('dsnews/news')->getCollection(); $collection->addFieldToFilter('category_id', $this->getId()); return $collection; } }
          
          





  2. Block/Adminhtml/Category/Edit/Tabs/News.php

     <?php class DS_News_Block_Adminhtml_Category_Edit_Tabs_News extends Mage_Adminhtml_Block_Widget_Grid { public function __construct() { parent::__construct(); $this->setId('categoryNewsGrid'); $this->setUseAjax(true); } protected function _prepareCollection() { $collection = Mage::registry('current_category')->getNewsCollection(); $this->setCollection($collection); return parent::_prepareCollection(); } protected function _prepareColumns() { $helper = Mage::helper('dsnews'); $this->addColumn('ajax_grid_news_id', array( 'header' => $helper->__('News ID'), 'index' => 'news_id', 'width' => '100px', )); $this->addColumn('ajax_grid_title', array( 'header' => $helper->__('Title'), 'index' => 'title', 'type' => 'text', )); $this->addColumn('ajax_grid_created', array( 'header' => $helper->__('Created'), 'index' => 'created', 'type' => 'date', )); return parent::_prepareColumns(); } public function getGridUrl() { return $this->getUrl('*/*/news', array('_current' => true)); } }
          
          





  3. Block/Adminhtml/Category/Edit/Tabs.php

     <?php class DS_News_Block_Adminhtml_Category_Edit_Tabs extends Mage_Adminhtml_Block_Widget_Tabs { public function __construct(){ ... } protected function _prepareLayout() { $helper = Mage::helper('dsnews'); $this->addTab('general_section', array( 'label' => $helper->__('General Information'), 'title' => $helper->__('General Information'), 'content' => $this->getLayout()->createBlock('dsnews/adminhtml_category_edit_tabs_general')->toHtml(), )); $this->addTab('news_section', array( 'class' => 'ajax', 'label' => $helper->__('News'), 'title' => $helper->__('News'), 'url' => $this->getUrl('*/*/news', array('_current' => true)), )); return parent::_prepareLayout(); } }
          
          





  4. controllers/Adminhtml/CategoryController.php ,

     <?php class DS_News_Adminhtml_CategoryController extends Mage_Adminhtml_Controller_Action { public function indexAction(){ ... } public function newAction(){ ... } public function editAction(){ ... } public function saveAction(){ ... } public function deleteAction(){ ... } public function newsAction() { $id = (int) $this->getRequest()->getParam('id'); $model = Mage::getModel('dsnews/category')->load($id); Mage::register('current_category', $model); if (Mage::app()->getRequest()->isAjax()) { $this->loadLayout(); echo $this->getLayout()->createBlock('dsnews/adminhtml_category_edit_tabs_news')->toHtml(); } } }
          
          









, «News». , . , , , 3:

 <?php class DS_News_Block_Adminhtml_Category_Edit_Tabs extends Mage_Adminhtml_Block_Widget_Tabs { public function __construct(){ ... } protected function _prepareLayout() { $helper = Mage::helper('dsnews'); $category = Mage::registry('current_category'); $this->addTab('general_section', array( 'label' => $helper->__('General Information'), 'title' => $helper->__('General Information'), 'content' => $this->getLayout()->createBlock('dsnews/adminhtml_category_edit_tabs_general')->toHtml(), )); if($category->getId()){ $this->addTab('news_section', array( 'class' => 'ajax', 'label' => $helper->__('News'), 'title' => $helper->__('News'), 'url' => $this->getUrl('*/*/news', array('_current' => true)), )); } return parent::_prepareLayout(); } }
      
      







, , 2 $this->setId('categoryNewsGrid') , JavaScript , , JavaScript (, ).



ajax_grid_ 2. , , .



, - , ajax ( ) /, . getGridUrl -. array('_current' => true) , , , id .







ステップ19.データグリッドで選択したレコードを保存する
, / . , . , -, . , - . Mage_Adminhtml_Block_Widget_Grid_Serializer .



  1. Block/Adminhtml/Category/Edit/Tabs/News.php

     <?php class DS_News_Block_Adminhtml_Category_Edit_Tabs_News extends Mage_Adminhtml_Block_Widget_Grid { public function __construct() { parent::__construct(); $this->setDefaultFilter(array('ajax_grid_in_category' => 1)); $this->setId('categoryNewsGrid'); $this->setSaveParametersInSession(false); $this->setUseAjax(true); } protected function _prepareCollection() { $collection = Mage::getModel('dsnews/news')->getCollection(); $this->setCollection($collection); return parent::_prepareCollection(); } protected function _prepareColumns() { $helper = Mage::helper('dsnews'); $this->addColumn('ajax_grid_in_category', array( 'align' => 'center', 'header_css_class' => 'a-center', 'index' => 'news_id', 'type' => 'checkbox', 'values' => $this->getSelectedNews(), )); $this->addColumn('ajax_grid_news_id', array( 'header' => $helper->__('News ID'), 'index' => 'news_id', 'width' => '100px', )); $this->addColumn('ajax_grid_title', array( 'header' => $helper->__('Title'), 'index' => 'title', 'type' => 'text', )); $this->addColumn('ajax_grid_created', array( 'header' => $helper->__('Created'), 'index' => 'created', 'type' => 'date', )); return parent::_prepareColumns(); } protected function _addColumnFilterToCollection($column) { if ($column->getId() == 'ajax_grid_in_category') { $collection = $this->getCollection(); $selectedNews = $this->getSelectedNews(); if ($column->getFilter()->getValue()) { $collection->addFieldToFilter('news_id', array('in' => $selectedNews)); } elseif (!empty($selectedNews)) { $collection->addFieldToFilter('news_id', array('nin' => $selectedNews)); } } else { parent::_addColumnFilterToCollection($column); } return $this; } public function getGridUrl() { return $this->getUrl('*/*/news', array('_current' => true, 'grid_only' => 1)); } public function getSelectedNews() { if (!isset($this->_data['selected_news'])) { $selectedNews = Mage::app()->getRequest()->getParam('selected_news', null); if(is_null($selectedNews) || !is_array($selectedNews)){ $category = Mage::registry('current_category'); $selectedNews = $category->getNewsCollection()->getAllIds(); } $this->_data['selected_news'] = $selectedNews; } return $this->_data['selected_news']; } }
          
          





  2. controllers/Adminhtml/CategoryController.php

     <?php class DS_News_Adminhtml_CategoryController extends Mage_Adminhtml_Controller_Action { public function indexAction(){ ... } public function newAction(){ ... } public function editAction(){ ... } public function saveAction() { $categoryId = $this->getRequest()->getParam('id'); if ($data = $this->getRequest()->getPost()) { try { $helper = Mage::helper('dsnews'); $model = Mage::getModel('dsnews/category'); $model->setData($data)->setId($categoryId); $model->save(); $categoryId = $model->getId(); $categoryNews = $model->getNewsCollection()->getAllIds(); if ($selectedNews = $this->getRequest()->getParam('selected_news', null)) { $selectedNews = Mage::helper('adminhtml/js')->decodeGridSerializedInput($selectedNews); } else { $selectedNews = array(); } $setCategory = array_diff($selectedNews, $categoryNews); $unsetCategory = array_diff($categoryNews, $selectedNews); foreach($setCategory as $id){ Mage::getModel('dsnews/news')->setId($id)->setCategoryId($categoryId)->save(); } foreach($unsetCategory as $id){ Mage::getModel('dsnews/news')->setId($id)->setCategoryId(0)->save(); } Mage::getSingleton('adminhtml/session')->addSuccess($this->__('Category was saved successfully')); Mage::getSingleton('adminhtml/session')->setFormData(false); $this->_redirect('*/*/'); } catch (Exception $e) { Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); Mage::getSingleton('adminhtml/session')->setFormData($data); $this->_redirect('*/*/edit', array( 'id' => $categoryId )); } return; } Mage::getSingleton('adminhtml/session')->addError($this->__('Unable to find item to save')); $this->_redirect('*/*/'); } public function deleteAction(){ ... } public function newsAction() { $id = (int) $this->getRequest()->getParam('id'); $model = Mage::getModel('dsnews/category')->load($id); $request = Mage::app()->getRequest(); Mage::register('current_category', $model); if ($request->isAjax()) { $this->loadLayout(); $layout = $this->getLayout(); $root = $layout->createBlock('core/text_list', 'root', array('output' => 'toHtml')); $grid = $layout->createBlock('dsnews/adminhtml_category_edit_tabs_news'); $root->append($grid); if (!$request->getParam('grid_only')) { $serializer = $layout->createBlock('adminhtml/widget_grid_serializer'); $serializer->initSerializerBlock($grid, 'getSelectedNews', 'selected_news', 'selected_news'); $root->append($serializer); } $this->renderLayout(); } } }
          
          









1, ajax_grid_in_category , / , ( / / ). _prepareCollection , _addColumnFilterToCollection . $this->setDefaultFilter(array('ajax_grid_in_category' => 1)); ( ). getSelectedNews , . , , POST- ( ), — .



. . $root = $layout->createBlock(...) root , . , , , . .



initSerializerBlock , . 4 : , , ( ), , getSelectedNews .







ステップ20.美しいURLを使用する
— , HTML/CSS . — . , . . , , , .



  1. sql/dsnews_setup/upgrade-0.0.2-0.0.3.php

     <?php echo '<h1>Upgrade DS News to version 0.0.3</h1>'; exit; $installer = $this; $tableNews = $installer->getTable('dsnews/table_news'); $installer->startSetup(); $installer->getConnection() ->addColumn($tableNews, 'link', array( 'comment' => 'News URL link', 'type' => Varien_Db_Ddl_Table::TYPE_TEXT, 'length' => '255', 'nullable' => true, )); $installer->getConnection() ->addKey($tableNews, 'IDX_UNIQUE_NEWS_LINK', 'link', Varien_Db_Adapter_Interface::INDEX_TYPE_UNIQUE); foreach (Mage::getModel('dsnews/news')->getCollection() as $news) { try { $news->load($news->getId())->setDataChanges(true)->save(); } catch (Exception $e) { $news->setId($news->getId())->setLink($news->getId())->save(); } } $installer->endSetup();
          
          





  2. etc/config.xml

     <?xml version="1.0" ?> <config> <modules> <DS_News> <version>0.0.3</version> </DS_News> </modules> ... </config>
          
          





  3. Helper/Data.php

     <?php class DS_News_Helper_Data extends Mage_Core_Helper_Abstract { public function getImagePath($id = 0){ ... } public function getImageUrl($id = 0){ ... } public function getCategoriesList(){ ... } public function getCategoriesOptions(){ ... } public function prepareUrl($url) { return trim(preg_replace('/-+/', '-', preg_replace('/[^a-z0-9]/sUi', '-', strtolower(trim($url)))), '-'); } }
          
          





  4. Model/News.php

     <?php class DS_News_Model_News extends Mage_Core_Model_Abstract { protected function _construct(){ ... } protected function _afterDelete(){ ... } protected function _beforeSave() { $helper = Mage::helper('dsnews'); if (!$this->getData('link')) { $this->setData('link', $helper->prepareUrl($this->getTitle())); } else { $this->setData('link', $helper->prepareUrl($this->getData('link'))); } return parent::_beforeSave(); } public function getImageUrl(){ ... } }
          
          





  5. Block/Adminhtml/News/Edit/Tabs/General.php

     <?php class DS_News_Block_Adminhtml_News_Edit_Tabs_General extends Mage_Adminhtml_Block_Widget_Form { protected function _prepareForm() { ... $fieldset->addField('link', 'text', array( 'label' => $helper->__('Link'), 'name' => 'link', )); ... } }
          
          





  6. etc/config.xml

     <?xml version="1.0" ?> <config> ... <global> ... <events> <controller_front_init_routers> <observers> <dsnews> <class>DS_News_Controller_Router</class> <method>initControllerRouters</method> </dsnews> </observers> </controller_front_init_routers> </events> ... </global> </config>
          
          





  7. Controller/Router.php

     <?php class DS_News_Controller_Router extends Mage_Core_Controller_Varien_Router_Abstract { public function initControllerRouters($observer) { $front = $observer->getEvent()->getFront(); $front->addRouter('dsnews', $this); } public function match(Zend_Controller_Request_Http $request) { $identifier = trim($request->getPathInfo(), '/'); $cmd = explode('/', $identifier); if ($cmd[0] == 'news') { if (count($cmd) == 1) { return $this->_fillRequest($request); } else { $model = Mage::getModel('dsnews/news')->load($cmd[1], 'link'); if ($model->getId()) { $params = array( 'id' => $model->getId() ); return $this->_fillRequest($request, $params, 'index', 'view'); } } } return false; } protected function _fillRequest($request, $cmd = array(), $controller = 'index', $action = 'index') { $request->setModuleName('news') ->setControllerName($controller) ->setActionName($action) ->setParam('is_routed', 1); if (is_array($cmd) && count($cmd)) { foreach ($cmd as $key => $value) { $request->setParam($key, $value); } } $request->setAlias(Mage_Core_Model_Url_Rewrite::REWRITE_REQUEST_PATH_ALIAS, $request->getPathInfo()); return true; } }
          
          









Upgrade DS News to version 0.0.3 , — , Magento ( ). 1 5 — : . 7, 6 . http://site.com/news/{news-link}



. controller_front_init_routers , $this : $front->addRouter('dsnews', $this) . Mage_Core_Controller_Varien_Router_Abstract , match . , , . match , URL. , . true , , false . _fillRequest — , .



, _fillRequest $request->setModuleName('news') frontName config.xml ( frontend/routers/[module Name]/args/frontName ), .



, , .







各ステップのソースコードはこちらから入手できます



例のコードを更新するため、テキスト内のコードがアーカイブのコードと一致しない場合や、コードが意図したとおりに機能しない場合があります。コードの不正確さや違いに気づいたら、PMで作者にメッセージを書いてください。



All Articles