Magento 1.x用のモジュールの開発-大きなガイド+ビデオ





こんにちは、Habr! 長い間リリースされたMagento 2にもかかわらず、Magentoの最初のバージョンは、すべての生き物よりも活気があり、まだ私たちを去るつもりはありません。 Magentoチームは、バージョン2のリリース日から3年間、製品の最初のバージョンをサポートします。 2018年11月頃まで。Magento1.xバージョン用に研ぎ澄まされたテーマ、モジュール、サービスの幅広い選択肢が市場に溢れています。 そして、現在Magento 1.xにある多くのサイトは、急いで更新する必要はありません。 多くの作業-少しの排気。 そのため、Magentoの最初のバージョンの開発は依然として関連しており、数年はそうなります。



ただし、この記事では電子商取引ソリューションの開発の見通しについては説明しません。 それから、Magento 1.x(以降、単にMagento)のモジュールを作成するためのガイドをまとめることにしました。 しかし、それは単に指示に従うだけの簡単なガイドではなく、「なぜこのように書き、他の方法では書かないのか」といういくつかの説明があります。 私は簡潔さと十分性の間の中間点を見つけようとしました。 そして何よりも、このガイドはMagentoのモジュール開発の初心者にとって有用です。 しかし、経験豊富なユーザーにとっては、この資料は有益です。



実際、私は各部分を自給自足させようとしました。 一瞬だけに興味があるなら、ガイド全体を走り回るのではなく、特定のセクションから必要な情報をすべて取得できます。 また、セクションの一部のセクションを既に実装している場合は、スキップできます。 ビデオについても同じことが言えます。 仕事に必要なのはビデオレッスンだけですが、ビデオがなくても実行できます。アクションの順序とコメント付きのリストがあります。 いくつかのことはビデオを見たほうが良いですが、 コーディングとともに、操作性のデモがまだあります。 はい、私は何かを見逃す可能性があります。 そのため、ビデオには文書化されていない瞬間があるかもしれませんし、テキスト版にはビデオにない追加があるかもしれません。 これは避けられませんでした、なぜなら すべてが異なる時間に行われました。





準備する



すべては、職場の準備から始まります。私たちの場合は、テストストアがインストールされたサーバーから始まります。



環境の準備ができたら、次のセクションに進むことができます



Ubuntu 16.04 LTS上のサーバー



Ubuntu 16.04配布キットをダウンロードし、「仮想マシン」を構成します。 そして、仮想コンピューターにUbuntuをインストールします。 通常、インストールプロセスは簡単であり、ドキュメントは必要ありませんが、インストールと構成のプロセス全体は、以下のビデオに記載されています。



ビデオ:UBUNTU 16.04のインストール-Nginx + php7-fpm + mysql + samba




必要なソフトウェアをインストールして構成します。



sudo su apt-get install && apt-get upgrade
      
      





ファイルマネージャー、エディター、タスクマネージャーを配置します



 apt-get install mc nano htop
      
      





IPアドレスを静的に構成します(原則として、これは省略できますが、ルーター側で静的アドレスを割り当てます)。



 nano /etc/network/interfaces
      
      





設定例:



 iface eth0 inet static address 192.168.0.100 netmask 255.255.255.0 gateway 192.168.0.1 dns-nameservers 192.168.0.1 8.8.8.8 auto eth0
      
      





ここで、 eth0はネットワークインターフェイスです。 ifconfigを書くことでそれを見ることができます

Nginxウェブサーバー:



 apt-get install nginx
      
      





PHP 7.0 FPM:



 apt-get install php-fpm php-xdebug php-soap php-gd php-mbstring php-mcrypt php-curl php-xml
      
      





MySQL 5.7およびphpMyAdmin:



 apt-get install mysql-server-5.7 phpmyadmin
      
      





ストアファイルが格納されるフォルダの所有者と権限を変更します。



 chown -R dev:dev /var/www chmod -R 777 /var/www
      
      





dev:devはユーザーの名前とグループです。 Ubuntuのインストール時にこの名前を使用しました。

ここで、インストールされたソフトウェアを構成する必要があります。



Nginx



Nginxの3つの構成を作成しました:動的ドメイン、Magento 2の構成(有用)、phpMyAdminの構成。 動的ドメインを使用したいわゆるconfigの動作原理は簡単です。





dynamic.conf
  server { listen 80; server_name $http_host; root /var/www/$http_host; location / { index index.html index.php; try_files $uri $uri/ @handler; expires 30d; } location /. { return 404; } location @handler { rewrite / /index.php; } location ~ .php/ { rewrite ^(.*.php)/ $1 last; } location ~ .php$ { if (!-e $request_filename) { rewrite / /index.php last; } expires off; fastcgi_pass unix:/run/php/php7.0-fpm.sock; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param SCRIPT_NAME $document_root$fastcgi_script_name; fastcgi_param MAGE_RUN_TYPE store; include fastcgi_params; } }
      
      







m2.conf
  # Magento Vars # # Example configuration: upstream fastcgi_backend { server unix:unix:/run/php/php7.0-fpm.sock; } server { set $MAGE_ROOT /var/www/m2.dev; set $MAGE_MODE default; # or production or developer listen 80; server_name m2.dev; root /var/www/m2.dev/pub; index index.php; autoindex off; charset off; add_header 'X-Content-Type-Options' 'nosniff'; add_header 'X-XSS-Protection' '1; mode=block'; location /setup { root $MAGE_ROOT; location ~ ^/setup/index.php { fastcgi_pass fastcgi_backend; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } location ~ ^/setup/(?!pub/). { deny all; } location ~ ^/setup/pub/ { add_header X-Frame-Options "SAMEORIGIN"; } } location /update { root $MAGE_ROOT; location ~ ^/update/index.php { fastcgi_split_path_info ^(/update/index.php)(/.+)$; fastcgi_pass fastcgi_backend; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param PATH_INFO $fastcgi_path_info; include fastcgi_params; } # deny everything but index.php location ~ ^/update/(?!pub/). { deny all; } location ~ ^/update/pub/ { add_header X-Frame-Options "SAMEORIGIN"; } } location / { try_files $uri $uri/ /index.php?$args; } location /pub { location ~ ^/pub/media/(downloadable|customer|import|theme_customization/.*\.xml) { deny all; } alias $MAGE_ROOT/pub; add_header X-Frame-Options "SAMEORIGIN"; } location /static/ { if ($MAGE_MODE = "production") { expires max; } location ~* \.(ico|jpg|jpeg|png|gif|svg|js|css|swf|eot|ttf|otf|woff|woff2)$ { add_header Cache-Control "public"; add_header X-Frame-Options "SAMEORIGIN"; expires +1y; if (!-f $request_filename) { rewrite ^/static/(version\d*/)?(.*)$ /static.php?resource=$2 last; } } location ~* \.(zip|gz|gzip|bz2|csv|xml)$ { add_header Cache-Control "no-store"; add_header X-Frame-Options "SAMEORIGIN"; expires off; if (!-f $request_filename) { rewrite ^/static/(version\d*/)?(.*)$ /static.php?resource=$2 last; } } if (!-f $request_filename) { rewrite ^/static/(version\d*/)?(.*)$ /static.php?resource=$2 last; } add_header X-Frame-Options "SAMEORIGIN"; } location /media/ { try_files $uri $uri/ /get.php?$args; location ~ ^/media/theme_customization/.*\.xml { deny all; } location ~* \.(ico|jpg|jpeg|png|gif|svg|js|css|swf|eot|ttf|otf|woff|woff2)$ { add_header Cache-Control "public"; add_header X-Frame-Options "SAMEORIGIN"; expires +1y; try_files $uri $uri/ /get.php?$args; } location ~* \.(zip|gz|gzip|bz2|csv|xml)$ { add_header Cache-Control "no-store"; add_header X-Frame-Options "SAMEORIGIN"; expires off; try_files $uri $uri/ /get.php?$args; } add_header X-Frame-Options "SAMEORIGIN"; } location /media/customer/ { deny all; } location /media/downloadable/ { deny all; } location /media/import/ { deny all; } location ~ cron\.php { deny all; } location ~ (index|get|static|report|404|503)\.php$ { try_files $uri =404; fastcgi_pass fastcgi_backend; fastcgi_param PHP_FLAG "session.auto_start=off \n suhosin.session.cryptua=off"; fastcgi_param PHP_VALUE "memory_limit=256M \n max_execution_time=600"; fastcgi_read_timeout 600s; fastcgi_connect_timeout 600s; fastcgi_param MAGE_MODE $MAGE_MODE; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } }
      
      







phpmyadmin.conf
  server { listen 80; server_name pma myadmin; root /usr/share/phpmyadmin/; index index.php; location /setup/index.php { deny all; } location ~ .php$ { if (!-e $request_filename) { rewrite / /index.php last; } expires off; fastcgi_pass unix:/run/php/php7.0-fpm.sock; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_param SCRIPT_NAME $document_root$fastcgi_script_name; fastcgi_param MAGE_RUN_TYPE store; include fastcgi_params; } include fastcgi_params; }
      
      





構成をフォルダー/ etc / nginx / sites-availiable /に配置し、フォルダー/ etc / nginx / sites-enabled /にシンボリックリンクを作成します。 または、/ etc / nginx / sites-enabled /フォルダーに配置するだけです



PHP 7.0 FPM



/etc/php/7.0/fpm/php.iniを編集します。 私たちは、原則として、あなたの好みに合わせてカスタマイズできるいくつかのパラメータのみを心配しています。



  max_execution_time = 300 max_input_time = 160 memory_limit = 512M display_errors = On log_errors = On html_errors = On date.timezone = (   )
      
      





Sambaサーバー

私は、sambaを介して作業し、ネットワークドライブをマウントし、静かにファイルをコピーするのが好きです。 しかし、あなたはそれを必要としないかもしれません。 彼らが言うように、味と色について...私の設定は次のとおりです:



smb.conf
 [global] workgroup = WORKGROUP server string = %h server (Samba, Ubuntu) dns proxy = no log file = /var/log/samba/log.%m max log size = 1000 syslog = 0 panic action = /usr/share/samba/panic-action %d server role = standalone server passdb backend = tdbsam obey pam restrictions = yes unix password sync = yes passwd program = /usr/bin/passwd %u passwd chat = *Enter\snew\s*\spassword:* %n\n *Retype\snew\s*\spassword:* %n\n *password\supdated\ssuccessfully* . pam password change = yes map to guest = bad user null passwords = Yes guest account = www-data [www] path = /var/www/ comment = WWW folder guest ok = yes browseable = yes read only = no locking = no force user = www-data force group = www-data
      
      









テストストアのインストール



インストールプロセスは簡単で、特別なスキルは必要ありません。 ただし、わかりやすくするために、ネタバレの下にビデオの指示を隠しておきます。



ビデオ:Magento Test Storeのインストール




ただし、重要な点が1つあります。

MagentoはPHP 7では動作しません。

入手するには、次の修正を使用できます: github.com/Inchoo/Inchoo_PHP7

モジュール作成





構造と構成



ビデオ:Magentoモジュールの構造と構成




レッスンで作成されたIGN_Siteblocks-1.zipモジュールの構造



ストアページ(フロントエンド部分)にブロックを表示するモジュールの例を使用して、モジュールを作成する方法を学びます。 そして最初に、モジュールの名前を思いつきます。 名前は短く、理にかなっている必要があります。 また、名前空間(通常は開発者の会社の名前または彼の名前)を選択する必要があります。 そして、最終的な名前はNamespace_Modulenameという形式を取ります。 この例では、 IGN_Siteblocksを呼び出しました



XML登録ファイルを作成します。



app / etc / modules / IGN_Siteblocks.xml
  <?xml version="1.0" ?> <config> <modules> <IGN_Siteblocks> <active>true</active> <!--   --> <codePool>local</codePool> </IGN_Siteblocks> </modules> </config>
      
      





codePoolについて話します。 それらは3つあります: localcommunitycore



そして、コアでは何も変更せず、システムの基本ファイルがあり、それらを変更する必要がある場合は、直接編集する以外の方法もあるとすぐに判断します。

ローカルコミュニティを安全に使用できます (実際には、 コミュニティをすぐに使用した方が良いですが、この例ではローカルになります)。



ストアの管理パネルの[システム]> [構成]> [詳細]> [モジュール出力の無効化]に移動し、IGN_Siteblocksを確認します。



モジュール用のフォルダーを作成します。



アプリ/コード/ローカル/ IGN /サイトブロック/

  1. ブロック -ページのレンダリングを担当するブロッククラス
  2. コントローラー -コントローラーはリクエストを受け入れます
  3. など -あらゆる種類の構成ファイルがあります
  4. ヘルパー -追加のヘルパークラス
  5. モデル -モデル
  6. sql-インストールスクリプト


Magentoのモジュールは、 MVCパターンを実装します。 モデル、ビュー(ブロック、テンプレート、レイアウト)およびコントローラーがあります。 etcフォルダーにconfig.xmlを作成します



アプリ/コード/ローカル/ IGN /サイトブロック/ etc / config.xml
  <?xml version="1.0" ?> <config> <modules> <IGN_Siteblocks> <version>1.0.0</version> </IGN_Siteblocks> </modules> <global> <!--   , , , ,   --> </global> <frontend> <!--   frontend  : , , ,  --> </frontend> <admin> <!--   admin  : , , --> </admin> <adminhtml> <!--   admin  : , ,  --> </adminhtml> <defalut> <!--   admin  : , ,  --> </defalut> </config>
      
      







ここで、いくつかのモジュール設定のブロック、モデル、コントローラー、ヘルパー、オブザーバー、リバイト、レイアウト、翻訳、標準値を宣言します。



XDEBUG + PHPSTORMコードのデバッグ



ビデオ:XDEBUG + PHPSTORMコードのデバッグ




ここでも、ビデオチュートリアルをご覧になることをお勧めします。 まず、サーバーを構成します。



 apt-get install php-xdebug
      
      





php.iniまたはxdebug.iniの設定を編集します



/etc/php/7.0/conf.d/20-xdebug.ini
 zend_extension = xdebug.so xdebug.idekey = "PHPSTORM" xdebug.remote_autostart = 1 xdebug.remote_connect_back = 1 xdebug.remote_enable = 1 xdebug.remote_port = 9000
      
      







保存し、 サービスphp7.0-fpm restart serviceを再起動することを忘れないでください。 PHPSTORMでは、新しいリモートデバッグ構成を作成します。



適切なアドレスとポートでサーバーを追加します。 IDEキーフィールドに、単語PHPSTORMを入力します。



モデル、コレクション。 データベースを操作します。



ビデオ:モデル、コレクション。 Magentoデータベースの使用




レッスンで作成されたIGN_Siteblocks-2.zipモジュールの構造



モデルは、データおよびデータのみを操作するためのクラスです。 このデータをデータベースに保存する方法に微妙な違いはありません。 このデータのレンダリングに関連するコードはありません。 Magentoでは、これらは顧客、製品、注文などです。



モジュールでモデルを使用するには、config.xmlを構成する必要があります

モデル、ブロック、ヘルパーがグローバルセクションに追加されることを思い出させてください。 config.xmlは次の形式を取ります。



アプリ/コード/ローカル/ IGN /サイトブロック/ etc / config.xml
  <?xml version="1.0" ?> <config> <modules> <IGN_Siteblocks> <version>1.0.0</version> </IGN_Siteblocks> </modules> <global> <models> <siteblocks> <!--    namespace_modulename   modulename --> <class>IGN_Siteblocks_Model</class> <resourceModel>siteblocks_resource</resourceModel> </siteblocks> <siteblocks_resource> <class>IGN_Siteblocks_Resource</class> <entities> <block> <!--   --> <table>ign_siteblock</table> <!--      ""  --> </block> </entities> </siteblocks_resource> </models> <resources> <siteblocks_setup> <!--         install  upgrade  --> <setup> <module>IGN_Siteblocks</module> </setup> </siteblocks_setup> </resources> </global> </config>
      
      







プレフィックスの名前を決定することが重要です(ここでどの用語が良いかわかりません)。 サイトブロックを選択しました。 これは任意の名前であり、通常、名前空間とモジュールの名前、またはモジュールの名前のみから形成されます。 まあ、または開発者を混乱させるために、以前に呪いから魅力を買った完全に任意の行を選択できます。



大文字と小文字を区別せずに明確に選択してください。 誤植が1つあり、長い間掘り進んで問題を探します。 モデルの名前とテーブルへのバインド。 モデル名はモデルファイル名と一致します。 データベース内のテーブルの名前は任意です。 私の場合、モデルに戻るには、次のように書く必要があります。



 Mage::getModel('siteblocks/block');
      
      





これでモデルを追加できます。 ブロックモデルを作成します。 テーブルにアタッチされた各モデルについて、モデル、リソースモデル、コレクションモデルの3つのファイルを作成する必要があります。 このモデルはデータベースの操作から抽象化されています。リソースモデルは以下にあります。 そこで、データを保存する前とデータベースからロードした後に、フィルタリング、ソート、データ処理のロジックを実装します。

Block.phpモデルコード:



アプリ/コード/ローカル/ IGN /サイトブロック/モデル/ Block.php
  <?php class IGN_Siteblocks_Model_Block extends Mage_Core_Model_Abstract { public function _construct() { parent::_construct(); $this->_init('siteblocks/block'); //      config.xml  } }
      
      







Mage_Core_Model_Abstractから継承されたモデル。 リソースモデルをModel / Resourceフォルダーに保存します。



アプリ/コード/ローカル/ IGN /サイトブロック/モデル/リソース/ Block.php
  <?php class IGN_Siteblocks_Model_Resource_Block extends Mage_Core_Model_Resource_Db_Abstract { public function _construct() { $this->_init('siteblocks/block','block_id'); //block_id   PRIMARY KEY  ,   entity_id } }
      
      







アプリ/コード/ローカル/ IGN /サイトブロック/モデル/リソース/ブロック/ Collection.php
  <?php class IGN_Siteblocks_Model_Resource_Block_Collection extends Mage_Core_Model_Resource_Db_Collection_Abstract { public function _construct() { parent::_construct(); $this->_init('siteblocks/block'); } }
      
      







クラスは空ですが、すでに必要な最小限の継承機能を実装しています。

必要に応じてそれらにコードを追加します。 さらにモデルを追加する場合は、テーブルにもう1つのモデルバインドと3つの新しいファイルを追加します。 テーブルに関連付けられていない任意の数のモデルを追加して(何らかの機能を実装するためだけに)、新しいファイルを追加するだけで、 Mage_Core_Model_Abstractから継承する必要はありません。



モデルのテーブルを作成するインストールスクリプトを作成することを忘れないでください。



app / code / local / IGN / Siteblocks / sql / siteblocks_setup / install-1.0.0.sql
  <?php /** @var Mage_Core_Model_Resource_Setup $installer */ $installer = $this; $installer->startSetup(); $table = $installer->getConnection() ->newTable($this->getTable('siteblocks/block')) ->addColumn('block_id',Varien_Db_Ddl_Table::TYPE_INTEGER,null,array( 'identity' => true, 'unsigned' => true, 'nullable' => false, 'primary' => true )) ->addColumn('title',Varien_Db_Ddl_Table::TYPE_VARCHAR,null,array( 'nullable' => false )) ->addColumn('content',Varien_Db_Ddl_Table::TYPE_TEXT,null,array( 'nullable' => false )) ->addColumn('block_status',Varien_Db_Ddl_Table::TYPE_TINYINT,null,array( 'nullable' => false )) ->addColumn('created_at',Varien_Db_Ddl_Table::TYPE_DATETIME,null,array( 'nullable' => false )); $installer->getConnection()->createTable($table); //  $installer->run(" CREATE TABLE IF NOT EXISTS `{$this->getTable('siteblocks/block')}` ( `block_id` int(11) NOT NULL AUTO_INCREMENT, `title` varchar(500) NOT NULL, `content` text NOT NULL, `block_status` tinyint(4) NOT NULL, `created_at` datetime NOT NULL, PRIMARY KEY (`block_id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; "); $installer->endSetup();
      
      







重要な瞬間!



インストールスクリプトがまだないときに、モジュールがインストールされた状態で管理パネルに移動しようとした場合。 ほとんどの場合、インストールスクリプトは二度と実行されません。 この場合、ストアデータベースのcore_resourceテーブルからsiteblocks_setupエントリを見つけて削除する必要があります。



モジュールバージョンをアップグレードする場合。 config.xmlで新しいバージョンを指定します (例: 1.0.1) 。 そして、アップグレードスクリプトupgrade-1.0.0-1.0.1.phpを作成します。 そして、その後のアップグレードと同じ精神で。



モデルとコレクションについて言えば、これらのクラスの最も基本的なメソッドに言及することは間違いありません。



モデルの使用例
  //    block_id = 1 $block = Mage::getModel('siteblocks/block')->load(1); //  $block->delete(); //C $block->save(); //        Mage::getModel('siteblocks/block')->setId(1)->delete(); //     $blocks = Mage::getModel('siteblocks/block')->getCollection(); //   block_id = 1, 2  3 $blocks->addFieldToFilter('block_id',array('in'=>array(1,2,3))) ; echo $blocks->getSelect(); //  SQL  //    $blocks = Mage::getResourceModel('siteblocks/block_collection');
      
      











コントローラーとルーティング



ビデオ:Magentoのコントローラーとルーティング。




レッスンで作成されたIGN_Siteblocks-3.zipモジュールの構造



MVCパターンによると、コントローラーは要求の処理を担当します。 HTTPリクエストの形式で、いわゆる入力信号を受け取ります。 リンクをたどりました-対応するコントローラーが機能しました。



コントローラーを作成する前に、 config.xmlでルーティングを構成します 。 フロントエンドと管理部分のルーティングは個別に構成されます。 そこで、 フロントエンド管理セクションにルーターを追加します。



config.xmlの形式は次のとおりです。



アプリ/コード/ローカル/ IGN /サイトブロック/ etc / config.xml
  <?xml version="1.0" ?> <config> <modules> <IGN_Siteblocks> <version>1.0.0</version> </IGN_Siteblocks> </modules> <global> <models> <siteblocks> <class>IGN_Siteblocks_Model</class> <resourceModel>siteblocks_resource</resourceModel> </siteblocks> <siteblocks_resource> <class>IGN_Siteblocks_Resource</class> <entities> <block> <table>ign_siteblock</table> </block> </entities> </siteblocks_resource> </models> <resources> <siteblocks_setup> <setup> <module>IGN_Siteblocks</module> </setup> </siteblocks_setup> </resources> </global> <frontend> <routers> <siteblocks> <use>standard</use> <args> <module>IGN_Siteblocks</module> <frontName>siteblocks</frontName><!--  ,      --> </args> </siteblocks> </routers> </frontend> <admin> <routers> <adminhtml> <args> <modules> <siteblocks after="Mage_Adminhtml">IGN_Siteblocks_Adminhtml</siteblocks> </modules> </args> </adminhtml> </routers> </admin> <default> </default> </config>
      
      







これで、モジュールのcontrollersフォルダーにコントローラーを作成できます。 フロントエンド部分のコントローラークラスは、 Mage_Core_Controller_Front_Actionクラスを継承する必要があります。



テストコントローラーTestController.phpを作成する



アプリ/コード/ローカル/ IGN /サイトブロック/コントローラー/ TestController.php
 <?php class IGN_Siteblocks_TestController extends Mage_Core_Controller_Front_Action { public function mytestAction() { die('test'); } }
      
      







ここでexample.com/siteblocks/test/mytestのようなURLに移動します 。 「テスト」という白い画面が表示されます。 これが発生しなかった場合、ある段階でエラーが発生しました。



コードを再確認し、ログを読んでください。 URLはルーター( サイトブロック )/コントローラー( テストコントローラー)/アクション( mytestアクション)で構成されます



GETパラメーターは2つの方法で送信できます。





管理コントローラーは、controllers / Adminhtmlフォルダーに作成されます。 フロントエンド部分のコントローラークラスは、 Mage_Adminhtml_Controller_Actionクラスを継承する必要があります。



テストコントローラーTestController.phpを作成します。



アプリ/コード/ローカル/ IGN /サイトブロック/コントローラー/ Adminhtml / TestController.php
 <?php class IGN_Siteblocks_Adminhtml_TestController extends Mage_Adminhtml_Controller_Action { public function mytestAction() { die('admin'); } }
      
      







URL: example.com/admin/test/mytestからアクセスできます-adminは管理パネルへの道です。



そして、ここには微妙な違いがあります。そのようなURLはすでに別のモジュールによって占有されている可能性があります。 2つの解決策があります:コントローラーの名前を競合しない既知の名前(IgntestController.phpなど)に変更するか、コントローラーをサブフォルダーに入れます。



アプリ/コード/ローカル/ IGN /サイトブロック/コントローラー/ Adminhtml /サイトブロック/TestController.php
 <?php class IGN_Siteblocks_Adminhtml_Siteblocks_TestController extends Mage_Adminhtml_Controller_Action { public function mytestAction() { die('admin'); } }
      
      







URLは、 example.com / admin / siteblocks_test / mytestの形式を取ります。





ヘルパー



ビデオ:Magentoのヘルパー




レッスンで作成されたIGN_Siteblocks-4.zipモジュールの構造



Magentoのヘルパークラスは、追加のクラスとして使用されます。 モデル、ブロック、コントローラーの機能に適合しないサードパーティのロジックを実装する必要があります。 ただし、モジュールには少なくとも1つのData.phpヘルパークラスが必要です。



このヘルパーは、デフォルトでテキスト(ラベル、メニュー項目など)およびその他のロジックを翻訳するために使用されます。



ヘルパーでは、設定から設定を読み取るためのメソッドを宣言することをお勧めします。 ヘルパーは、 Mage_Core_Helper_Abstractクラスを継承する必要があります。



アプリ/コード/ loca / IGN / Siteblocks /ヘルパー/ Data.php
 <?php class IGN_Siteblocks_Helper_Data extends Mage_Core_Helper_Abstract { }
      
      







ヘルパー内のテキストを翻訳する__()メソッドがあり、そのアプリケーションは次のようになります。



 echo Mage::helper('siteblocks')->__('Some text')
      
      





config.xmlで翻訳ファイルを宣言します。



アプリ/コード/ローカル/ IGN /サイトブロック/ etc / config.xml
 <?xml version="1.0" ?> <config> <modules> <IGN_Siteblocks> <version>1.0.0</version> </IGN_Siteblocks> </modules> <global> <models> <siteblocks> <class>IGN_Siteblocks_Model</class> <resourceModel>siteblocks_resource</resourceModel> </siteblocks> <siteblocks_resource> <class>IGN_Siteblocks_Resource</class> <entities> <block> <table>ign_siteblock</table> </block> </entities> </siteblocks_resource> </models> <resources> <siteblocks_setup> <setup> <module>IGN_Siteblocks</module> </setup> </siteblocks_setup> </resources> <helpers> <siteblocks> <class>IGN_Siteblocks_Helper</class> </siteblocks> </helpers> </global> <frontend> <routers> <siteblocks> <use>standard</use> <args> <module>IGN_Siteblocks</module> <frontName>siteblocks</frontName> </args> </siteblocks> </routers> <translate> <modules> <IGN_Siteblocks> <files> <default>IGN_Siteblocks.csv</default> </files> </IGN_Siteblocks> </modules> </translate> </frontend> <admin> <routers> <adminhtml> <args> <modules> <siteblocks after="Mage_Adminhtml">IGN_Siteblocks_Adminhtml</siteblocks> </modules> </args> </adminhtml> </routers> </admin> <defalut> </defalut> </config>
      
      







そして、app / locale / en_US /フォルダーにIGN_Siteblocks.csvファイルを作成します。 フォームの内容: 「一部のテキスト」、「一部のテキスト」



独自のヘルパーを使用してテキストを表示しようとしますが、この場合、モジュールの異なる言語へのローカライズが簡素化されます。



翻訳ファイルを適切なロケールにコピーし、2番目の列を翻訳するだけで十分です。コードを詳しく調べる必要はありません。





管理パネルのモジュール構成



ビデオ:Magento管理パネルのモジュール構成




レッスンで作成されたIGN_Siteblocks-5.zipモジュールの構造



モジュールに柔軟性を持たせるために、モジュール設定を含むページを作成します。 これは、純粋にxmlファイルを通じて行われます。 2つのファイルを作成する必要があります。



system.xml-フィールドが追加される場所

adminhtml.xml-セクションとアクセス権が示される場所



また、config.xmlファイルのデフォルトセクションで標準設定を指定できます。



アプリ/コード/ローカル/ IGN /サイトブロック/ etc / config.xml
 <?xml version="1.0" ?> <config> <modules> <IGN_Siteblocks> <version>1.0.0</version> </IGN_Siteblocks> </modules> <global> <models> <siteblocks> <class>IGN_Siteblocks_Model</class> <resourceModel>siteblocks_resource</resourceModel> </siteblocks> <siteblocks_resource> <class>IGN_Siteblocks_Resource</class> <entities> <block> <table>ign_siteblock</table> </block> </entities> </siteblocks_resource> </models> <resources> <siteblocks_setup> <setup> <module>IGN_Siteblocks</module> </setup> </siteblocks_setup> </resources> <helpers> <siteblocks> <class>IGN_Siteblocks_Helper</class> </siteblocks> </helpers> </global> <frontend> <routers> <siteblocks> <use>standard</use> <args> <module>IGN_Siteblocks</module> <frontName>siteblocks</frontName> </args> </siteblocks> </routers> <translate> <modules> <IGN_Siteblocks> <files> <default>IGN_Siteblocks.csv</default> </files> </IGN_Siteblocks> </modules> </translate> </frontend> <admin> <routers> <adminhtml> <args> <modules> <siteblocks after="Mage_Adminhtml">IGN_Siteblocks_Adminhtml</siteblocks> </modules> </args> </adminhtml> </routers> </admin> <defalut> <siteblocks> <settings> <enabled>1</enabled> <block_count>10</block_count> </settings> </siteblocks> </defalut> </config>
      
      







アプリ/コード/ローカル/ IGN /サイトブロック/ etc / adminhtml.xml
 <?xml version="1.0"?> <config> <acl> <resources> <admin> <children> <system> <children> <config> <children> <siteblocks translate="title" module="siteblocks"> <title>Siteblocks</title> </siteblocks> </children> </config> </children> </system> </children> </admin> </resources> </acl> </config>
      
      







アプリ/コード/ローカル/ IGN /サイトブロック/ etc / system.xml
 <?xml version="1.0"?> <config> <tabs> <ign translate="label" module="siteblocks"> <!--      --> <label>IGN</label> <sort_order>2</sort_order> </ign> </tabs> <sections> <siteblocks module="siteblocks" translate="label"> <label>Siteblocks</label> <tab>ign</tab> <!--       --> <frontend>text</frontend> <sort_order>1</sort_order> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>1</show_in_store> <groups> <settings module="siteblocks" translate="label"> <label>Settings</label> <expanded>1</expanded> <sort_order>1</sort_order> <show_in_default>1</show_in_default> <show_in_Website>1</show_in_Website> <show_in_store>1</show_in_store> <fields> <enabled translate="label comment" module="siteblocks"> <label>Enabled</label> <frontend_type>select</frontend_type> <!--       lib/Varien/Data/Form/Element --> <source_model>siteblocks/source_status</source_model> <!--     --> <sort_order>1</sort_order> <show_in_default>1</show_in_default> <show_in_Website>1</show_in_Website> <show_in_store>1</show_in_store> <comment>Is module enabled</comment> </enabled> <blocks_count> <label>Blocks on page</label> <frontend_type>text</frontend_type> <sort_order>2</sort_order> <show_in_default>1</show_in_default> <show_in_Website>1</show_in_Website> <show_in_store>1</show_in_store> <depends><enabled>1</enabled></depends> <!--         --> </blocks_count> <raw_text> <label>Raw text</label> <frontend_type>textarea</frontend_type> <sort_order>3</sort_order> <show_in_default>1</show_in_default> <show_in_Website>1</show_in_Website> <show_in_store>1</show_in_store> <depends><enabled>1</enabled></depends> </raw_text> </fields> </settings> </groups> </siteblocks> </sections> </config>
      
      







設定では、オプションを含むドロップダウンが表示され、これらのオプションの独自のモデルが使用されます。



アプリ/コード/ローカル/ IGN /サイトブロック/モデル/ソース/ Status.php
 <?php class IGN_Siteblocks_Model_Source_Status { const ENABLED = '1'; const DISABLED = '0'; /** * Options getter * * @return array */ public function toOptionArray() { return array( array('value' => self::ENABLED, 'label'=>Mage::helper('siteblocks')->__('Enabled')), array('value' => self::DISABLED, 'label'=>Mage::helper('siteblocks')->__('Disabled')), ); } /** * Get options in "key-value" format * * @return array */ public function toArray() { return array( self::DISABLED => Mage::helper('siteblocks')->__('Disabled'), self::ENABLED => Mage::helper('siteblocks')->__('Enabled'), ); }
      
      











フロントエンドブロック。レイアウト。テンプレート



ビデオ:フロントエンドブロック。レイアウト。Magentoテンプレート




レッスンで作成されたIGN_Siteblocks-6.zip モジュールの構造は



、ストアのフロントエンド部分に関する情報を表示しようとしていますまた、タイトルから推測するのは難しくないため、ブロック、レイアウト、テンプレートの3種類のファイルを使用します。



ブロックは、情報の準備と表示を担当するクラスです。ブロックはテンプレートの表示に使用されますが、常にではありません。テンプレートが使用される場合、それは単にfetchViewメソッドに含まれ







ますしたがって、$ thisを介してテンプレートからブロックにアクセスします



アプリ/コード/ローカル/ IGN /サイトブロック/ブロック/List.php
 <?php class IGN_Siteblocks_Block_List extends Mage_Core_Block_Template { public function getBlocks() { //return Mage::getResourceModel('siteblocks/block_collection'); return Mage::getModel('siteblocks/block')->getCollection() ->addFieldToFilter('block_status',array('eq'=>IGN_Siteblocks_Model_Source_Status::ENABLED)); } }
      
      







ブロックはMage_Core_Block_Templateクラスを継承します。ただし、ユニットの出力内容によって異なります。そのため、たとえば、製品をリストするときは、Mage_Catalog_Block_Product_Listブロックから継承することをお勧めしますレイアウトは、ページの構造、ページに表示する要素とその順序を構築するために使用されます。



レイアウトファイルを作成します。



アプリ/デザイン/フロントエンド/ベース/デフォルト/レイアウト/ siteblocks.xml
 <?xml version="1.0"?> <layout version="1.0.0"> <siteblocks_index_index> <!--   URL example.com/siteblocks/index/index --> <reference name="head"> <action method="setTitle"> <title>My Siteblocks</title> </action> </reference> <reference name="content"> <block name="siteblocks.list" as="siteblocks" type="siteblocks/list" template="siteblocks/list.phtml"/> </reference> </siteblocks_index_index> <catalog_category_default> <!--    handle            --> <reference name="left"> <block name="siteblocks.list" as="siteblocks" type="siteblocks/list" template="siteblocks/list.phtml"/> </reference> <reference name="right"> <block name="siteblocks.list" as="siteblocks" type="siteblocks/list" template="siteblocks/list.phtml"/> </reference> </catalog_category_default> <catalog_product_view> <!--        --> <reference name="product.info.extrahint"> <!--        catalog.xml          --> <block name="siteblocks.list" before="-" as="siteblocks" type="siteblocks/list" template="siteblocks/list.phtml"/> </reference> </catalog_product_view> </layout>
      
      







レイアウトでは、js、cssファイルをヘッドに追加できます。興味のあるページでブロックを追加または削除できます。レイアウトのテーマは非常に広範囲であり、上記から、サイトの複数の場所にブロックを追加する最小限のシンプルなレイアウトを提供しました。



別の方法(モックアップなし)で、コントローラーにHTMLコードを表示できます。



 $html = Mage::app()->getLayout()->createBlock('siteblocks/list')->setTemplate('siteblocks/list.phtml')->toHtml() $this->getResponse()->setBody($html);
      
      





そして、このブロックのみのHTMLコードが表示されます。これは、AJAXリクエストを使用する場合などに必要になることがよくあります。



レイアウトでは、ファイルsiteblocks / list.phtmlに言及しています。テンプレートでデフォルトで指定する場合は省略できます。



 class IGN_Siteblocks_Block_List extends Mage_Core_Block_Template { protected $_template = 'siteblocks/list.phtml'; }
      
      





テンプレートを作成します。



アプリ/デザイン/ベース/デフォルト/テンプレート/サイトブロック/ list.phtml
 <?php foreach($this->getBlocks() as $block):?> <div class="siteblock"> <div class="block-title"><?php echo $block->getTitle()?></div> <div class="block-content"><?php echo $block->getContent()?></div> </div> <?php endforeach;?>
      
      







コードでわかるように、getBlocksブロックメソッドを呼び出して、印刷するレコードのコレクションを返します。TestControllerの名前を変更するか、新しいものを作成します。インデックスコントローラー



アプリ/コード/ローカル/ IGN /サイトブロック/コントローラー/ IndexController.php
 <?php class IGN_Siteblocks_IndexController extends Mage_Core_Controller_Front_Action { public function indexAction() { $this->loadLayout(); #  $this->renderLayout(); # html } }
      
      







出力が表示されるURLは、example.com / siteblocks / index / indexまたはexample.com/siteblocksです。index / indexは省略できます。



レイアウト内のハンドルは、siteblocks_index_indexを使用しますレコードの出力を見るには、それらをデータベースに直接追加するか、編集フォームの開発の次のステップに進む必要があります。





管理インターフェース。グリッド。編集フォーム。



ビデオ:管理インターフェイス。グリッド。Magento編集フォーム




レッスンで作成されたIGN_Siteblocks-7.zip モジュールの構造



管理インターフェースの作成プロセスは、いくつかの段階で構成されています。





メニューにアイテムを追加します。



アプリ/コード/ローカル/ IGN /サイトブロック/ etc / adminhtml.xml
 <?xml version="1.0"?> <config> <acl> <resources> <admin> <children> <system> <children> <config> <children> <siteblocks translate="title" module="siteblocks"> <title>Siteblocks</title> </siteblocks> </children> </config> </children> </system> <cms> <children> <siteblocks translate="title" module="siteblocks"> <title>Siteblocks</title> </siteblocks> </children> </cms> </children> </admin> </resources> </acl> <menu> <cms> <!--        --> <children> <siteblocks translate="title" module="siteblocks"> <title>Siteblocks</title> <action>adminhtml/siteblocks</action> <!--       , index      --> <sort_order>20</sort_order> </siteblocks> </children> </cms> </menu> </config>
      
      







正しいセクションコード(cmsの例)は、標準のMagentoモジュールのadminhtml.xmlファイルにあります。そこで、独自のセクションを作成する方法を参照してください。aclブロックの情報を複製することを忘れないでください



コントローラーと1つのアクションを作成して開始します。



アプリ/コード/ローカル/ IGN /サイトブロック/コントローラー/ Adminhtml / SiteblocksController.php
 <?php class IGN_Siteblocks_Adminhtml_SiteblocksController extends Mage_Adminhtml_Controller_Action { public function indexAction() { $this->loadLayout(); $this->_addContent($this->getLayout()->createBlock('siteblocks/adminhtml_siteblocks')); $this->renderLayout(); } }
      
      







管理パネルのレイアウトを作成できますが、必要なブロックをコントローラーに直接追加できます。ここで、コンテンツにページを追加しました。インデックスアクションは、グリッドレコードを含むページを表示します。



これで、ブロックの作成に進むことができます。



アプリ/コード/ローカル/ IGN / Siteblocks / Block / Adminhtml / Siteblocks.php
 <?php class IGN_Siteblocks_Block_Adminhtml_Siteblocks extends Mage_Adminhtml_Block_Widget_Grid_Container { public function __construct() { $this->_controller = 'adminhtml_siteblocks'; $this->_blockGroup = 'siteblocks'; $this->_headerText = Mage::helper('siteblocks')->__('Siteblocks'); $this->_addButtonLabel = Mage::helper('siteblocks')->__('Add New Block'); parent::__construct(); } }
      
      







このようなプロパティ値を登録した理由は、Mage_Adminhtml_Block_Widget_Grid_Containerクラスのメソッドで確認







できます。こうして、グリッドブロックのブロックタイプが形成されます。



アプリ/コード/ローカル/ IGN / Siteblocks / Block / Adminhtml / Siteblocks / Grid.php
 <?php class IGN_Siteblocks_Block_Adminhtml_Siteblocks_Grid extends Mage_Adminhtml_Block_Widget_Grid { public function __construct() { parent::__construct(); $this->setId('cmsBlockGrid'); $this->setDefaultSort('block_identifier'); $this->setDefaultDir('ASC'); } protected function _prepareCollection() { $collection = Mage::getModel('siteblocks/block')->getCollection(); /* @var $collection Mage_Cms_Model_Mysql4_Block_Collection */ $this->setCollection($collection); return parent::_prepareCollection(); } protected function _prepareColumns() { $this->addColumn('title', array( 'header' => Mage::helper('siteblocks')->__('Title'), 'align' => 'left', 'index' => 'title', )); $this->addColumn('block_status', array( 'header' => Mage::helper('cms')->__('Status'), 'align' => 'left', 'type' => 'options', 'options' => Mage::getModel('siteblocks/source_status')->toArray(), 'index' => 'block_status' )); $this->addColumn('created_at', array( 'header' => Mage::helper('siteblocks')->__('Created At'), 'index' => 'created_at', 'type' => 'date', )); return parent::_prepareColumns(); } protected function _prepareMassaction() { $this->setMassactionIdField('block_id'); $this->getMassactionBlock()->setIdFieldName('block_id'); $this->getMassactionBlock() ->addItem('delete', array( 'label' => Mage::helper('siteblocks')->__('Delete'), 'url' => $this->getUrl('*/*/massDelete'), 'confirm' => Mage::helper('siteblocks')->__('Are you sure?') ) ) ->addItem('status', array( 'label' => Mage::helper('siteblocks')->__('Update status'), 'url' => $this->getUrl('*/*/massStatus'), 'additional' => array('block_status'=> array( 'name' => 'block_status', 'type' => 'select', 'class' => 'required-entry', 'label' => Mage::helper('siteblocks')->__('Status'), 'values' => Mage::getModel('siteblocks/source_status')->toOptionArray() ) ) ) ); return $this; } /** * Row click url * * @return string */ public function getRowUrl($row) { return $this->getUrl('*/*/edit', array('block_id' => $row->getId())); } }
      
      







この場合のグリッドブロックはこの形式を取ります。原則として、メソッドとプロパティの名前により、列の追加方法、編集ページでのURLの形成方法、レコードのコレクションがテーブルでの出力用に準備される方法を理解できます。



デフォルトの列タイプとその構築の原則は、app / code / core / Mage / Adminhtml / Block / Widget / Grid / Column / Renderer / folderにあることに注意してください



編集ページも、コンテナブロックとフォームブロックの2つのブロックで構成されます。



アプリ/コード/ローカル/ IGN /サイトブロック/ブロック/ Adminhtml /サイトブロック/ Edit.php
 <?php class IGN_Siteblocks_Block_Adminhtml_Siteblocks_Edit extends Mage_Adminhtml_Block_Widget_Form_Container { public function __construct() { $this->_objectId = 'block_id'; $this->_controller = 'adminhtml_siteblocks'; $this->_blockGroup = 'siteblocks'; parent::__construct(); $this->_updateButton('save', 'label', Mage::helper('siteblocks')->__('Save Block')); $this->_updateButton('delete', 'label', Mage::helper('siteblocks')->__('Delete Block')); $this->_addButton('saveandcontinue', array( 'label' => Mage::helper('adminhtml')->__('Save and Continue Edit'), 'onclick' => 'saveAndContinueEdit()', 'class' => 'save', ), -100); $this->_formScripts[] = " function saveAndContinueEdit(){ editForm.submit($('edit_form').action+'back/edit/'); } "; } /** * Get edit form container header text * * @return string */ public function getHeaderText() { if (Mage::registry('siteblocks_block')->getId()) { return Mage::helper('siteblocks')->__("Edit Block '%s'", $this->escapeHtml(Mage::registry('siteblocks_block')->getTitle())); } else { return Mage::helper('siteblocks')->__('New Block'); } } }
      
      







そして、ここでプロパティの値は親クラスのメソッドに合わせて調整され、ブロックタイプsiteblocks / adminhtml_siteblocks_edit_formフォーム



クラスを取得します



アプリ/コード/ローカル/ IGN /サイトブロック/ブロック/ Adminhtml /サイトブロック/編集/ Form.php
 <?php class IGN_Siteblocks_Block_Adminhtml_Siteblocks_Edit_Form extends Mage_Adminhtml_Block_Widget_Form { /** * Init form */ public function __construct() { parent::__construct(); $this->setId('block_form'); $this->setTitle(Mage::helper('siteblocks')->__('Block Information')); } protected function _prepareForm() { $model = Mage::registry('siteblocks_block'); $form = new Varien_Data_Form( array( 'id' => 'edit_form', 'action' => $this->getUrl('*/*/save',array('block_id'=>$this->getRequest()->getParam('block_id'))), 'method' => 'post' ) ); $form->setHtmlIdPrefix('block_'); $fieldset = $form->addFieldset('base_fieldset', array('legend'=>Mage::helper('siteblocks')->__('General Information'), 'class' => 'fieldset-wide')); if ($model->getBlockId()) { $fieldset->addField('block_id', 'hidden', array( 'name' => 'block_id', )); } $fieldset->addField('title', 'text', array( 'name' => 'title', 'label' => Mage::helper('siteblocks')->__('Block Title'), 'title' => Mage::helper('siteblocks')->__('Block Title'), 'required' => true, )); $fieldset->addField('block_status', 'select', array( 'label' => Mage::helper('siteblocks')->__('Status'), 'title' => Mage::helper('siteblocks')->__('Status'), 'name' => 'block_status', 'required' => true, 'options' => Mage::getModel('siteblocks/source_status')->toArray(), )); $fieldset->addField('content', 'textarea', array( 'name' => 'content', 'label' => Mage::helper('siteblocks')->__('Content'), 'title' => Mage::helper('siteblocks')->__('Content'), 'style' => 'height:36em', 'required' => true, )); $form->setValues($model->getData()); $form->setUseContainer(true); $this->setForm($form); return parent::_prepareForm(); } }
      
      







フィールドは簡単な方法で追加され、オプションの明確なセットがあり、標準フィールドのタイプはlib / Varien / Data / Form / Element /フォルダーにあります。ここで、なぜサイトブロックモデルのインスタンスがあるのか​​を見てみましょう。$ model = Mage :: registry( 'siteblocks_block'); 残りのアクションをコントローラーに追加します。レコードを編集、保存、削除するアクションが必要です。また、ユーザーがテーブル内の複数の行を選択し、これらのマークされたエントリの削除ボタンをクリックできる場合、一括削除およびステータス変更のアクションを追加します。



コントローラーの形式は次のとおりです。



アプリ/コード/ローカル/ IGN /サイトブロック/コントローラー/ Adminhtml / SiteblocksController.php
 <?php class IGN_Siteblocks_Adminhtml_SiteblocksController extends Mage_Adminhtml_Controller_Action { public function indexAction() { $this->loadLayout(); $this->_addContent($this->getLayout()->createBlock('siteblocks/adminhtml_siteblocks')); $this->renderLayout(); } public function newAction() { $this->_forward('edit'); } public function editAction() { $id = $this->getRequest()->getParam('block_id'); Mage::register('siteblocks_block',Mage::getModel('siteblocks/block')->load($id)); $blockObject = (array)Mage::getSingleton('adminhtml/session')->getBlockObject(true); if(count($blockObject)) { Mage::registry('siteblocks_block')->setData($blockObject); } $this->loadLayout(); $this->_addContent($this->getLayout()->createBlock('siteblocks/adminhtml_siteblocks_edit')); $this->renderLayout(); } public function saveAction() { try { $id = $this->getRequest()->getParam('block_id'); $block = Mage::getModel('siteblocks/block')->load($id); /*$block ->setTitle($this->getRequest()->getParam('title')) ->setContent($this->getRequest()->getParam('content')) ->setBlockStatus($this->getRequest()->getParam('block_status')) ->save();*/ $block ->setData($this->getRequest()->getParams()) ->setCreatedAt(Mage::app()->getLocale()->date()) ->save(); if(!$block->getId()) { Mage::getSingleton('adminhtml/session')->addError('Cannot save the block'); } } catch(Exception $e) { Mage::logException($e); Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); Mage::getSingleton('adminhtml/session')->setBlockObject($block->getData()); return $this->_redirect('*/*/edit',array('block_id'=>$this->getRequest()->getParam('block_id'))); } Mage::getSingleton('adminhtml/session')->addSuccess('Block was saved successfully!'); $this->_redirect('*/*/'.$this->getRequest()->getParam('back','index'),array('block_id'=>$block->getId())); } public function deleteAction() { $block = Mage::getModel('siteblocks/block') ->setId($this->getRequest()->getParam('block_id')) ->delete(); if($block->getId()) { Mage::getSingleton('adminhtml/session')->addSuccess('Block was deleted successfully!'); } $this->_redirect('*/*/'); } public function massStatusAction() { $statuses = $this->getRequest()->getParams(); try { $blocks= Mage::getModel('siteblocks/block') ->getCollection() ->addFieldToFilter('block_id',array('in'=>$statuses['massaction'])); foreach($blocks as $block) { $block->setBlockStatus($statuses['block_status'])->save(); } } catch(Exception $e) { Mage::logException($e); Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); return $this->_redirect('*/*/'); } Mage::getSingleton('adminhtml/session')->addSuccess('Blocks were updated!'); return $this->_redirect('*/*/'); } public function massDeleteAction() { $blocks = $this->getRequest()->getParams(); try { $blocks= Mage::getModel('siteblocks/block') ->getCollection() ->addFieldToFilter('block_id',array('in'=>$blocks['massaction'])); foreach($blocks as $block) { $block->delete(); } } catch(Exception $e) { Mage::logException($e); Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); return $this->_redirect('*/*/'); } Mage::getSingleton('adminhtml/session')->addSuccess('Blocks were deleted!'); return $this->_redirect('*/*/'); } }
      
      







これで、モジュールでレコードを編集し、フロントエンド部分に表示できます。





イベントとリスナー



ビデオ:Magentoのイベントとリスナー




レッスンで作成されたIGN_Siteblocks-8.zip モジュールの構造



Magentoでイベントリスナーテンプレートを使用できます。モジュールでサイトの特定の瞬間をキャッチできるのは何ですか。ダイナミズム、柔軟性を追加し、自動化を強化します。



また、Magentoには多くの標準イベントが実装されています。 「Mage :: dispatchEvent」というテキストのMagentoファイルを検索します。または、リンクをご覧ください。これは明示的なイベントによるもので、各モデル、各ブロックまたはコントローラーアクションで発生するイベントがまだあります。原則として、これは事前および事後イベントです。



model_save_before、model_save_after、controller_action_predispatch、controller_action_postdispatch、core_block_abstract_to_html_before、core_block_abstract_to_html_after



さらに、クラスのevent_prefixまたはコントローラーのルート名を使用するイベント(siteblocks_save_before、controller_action_predispatch_siteblocks ...)



さまざまなバリエーションがあり、このシステムのおかげで、目的のイベントを簡単に「キャッチ」できます。



コード内の任意の場所でイベントを直接作成できます。



 Mage::dispatchEvent('some_event_name',array('myparam' => $someVar));
      
      





リスナーはconfig.xmlで宣言されています。また、3つのオプションがあります:globaladminhtmlfrontendしたがって、これはリスナーに働きかけたいだけの分離です。設定は次の形式を取ります。



アプリ/コード/ローカル/ IGN /サイトブロック/ etc / config.xml
 <?xml version="1.0" ?> <config> <modules> <IGN_Siteblocks> <version>1.0.0</version> </IGN_Siteblocks> </modules> <global> <blocks> <siteblocks> <class>IGN_Siteblocks_Block</class> </siteblocks> </blocks> <models> <siteblocks> <class>IGN_Siteblocks_Model</class> <resourceModel>siteblocks_resource</resourceModel> </siteblocks> <siteblocks_resource> <class>IGN_Siteblocks_Model_Resource</class> <entities> <block> <table>ign_siteblock</table> </block> </entities> </siteblocks_resource> </models> <resources> <siteblocks_setup> <setup> <module>IGN_Siteblocks</module> </setup> </siteblocks_setup> </resources> <helpers> <siteblocks> <class>IGN_Siteblocks_Helper</class> </siteblocks> </helpers> </global> <frontend> <events> <checkout_cart_product_add_after> <!--      --> <observers> <siteblocks> <class>siteblocks/observer</class> <method>checkout_cart_product_add_after</method> <!--         --> <type>model</type> </siteblocks> </observers> </checkout_cart_product_add_after> </events> <layout> <updates> <siteblocks module="siteblocks"> <file>siteblocks.xml</file> </siteblocks> </updates> </layout> <routers> <siteblocks> <use>standard</use> <args> <module>IGN_Siteblocks</module> <frontName>siteblocks</frontName> </args> </siteblocks> </routers> <translate> <modules> <IGN_Siteblocks> <files> <default>IGN_Siteblocks.csv</default> </files> </IGN_Siteblocks> </modules> </translate> </frontend> <admin> <routers> <adminhtml> <args> <modules> <siteblocks after="Mage_Adminhtml">IGN_Siteblocks_Adminhtml</siteblocks> </modules> </args> </adminhtml> </routers> </admin> <default> <siteblocks> <settings> <enabled>1</enabled> <block_count>10</block_count> </settings> </siteblocks> </default> </config>
      
      







バスケットに製品を追加するイベントにリスナーを1人追加しました。次に、リスナークラスを作成する必要があります。このクラスがなくても、モデルにロジックを追加できます。しかし、これは悪い形です。したがって、Observer.php



アプリ/コード/ローカル/ IGN /サイトブロック/モデル/ Observer.php
 <?php class IGN_Siteblocks_Model_Observer { /** * @param $bserver Varien_Event_Observer */ //   camelCase  .  :   =   //     , : checkoutCartProductAddAfter public function checkout_cart_product_add_after($observer) { var_dump($observer->getEvent()->getData('quote_item')->getData());die; } }
      
      







このメソッドでは、必要なすべての操作を実行できます。次に、バスケットからアイテムの内容を印刷します。(後でこのコードをコメントアウトします。そうしないと、バスケットに製品を追加できません)。





Cronおよびスケジュールされたタスク



ビデオ:MagentoのCronおよびスケジュールされたタスク




レッスンで作成されたIGN_Siteblocks-9.zip モジュールの構造は、モジュール



の作業プロセスとストアの作業を自動化する際のもう1つの引数です。スケジュールされたタスクを作成することもできます。



まず第一に、Magentoクラウンの起動を設定する必要があり、既に起動されているMagentoファイルは、どのタスクを実行するかによって自動的に配布されます。コンソールでMagento cronをセットアップします。



 crontab -e * * * * * php /var/www/magento.dev/cron.php
      
      





ここでの詳細情報:help.ubuntu.ru/wiki/cronまたは、設定はできませんが、必要なときにクラウンを実行します。example.com/ cron.phpのようなリンクをクリックするだけ



で、config.xmlのタスクを別のcrontabブロックで宣言します。更新されたファイルビュー:



アプリ/コード/ローカル/ IGN /サイトブロック/ etc / config.xml
 <?xml version="1.0" ?> <config> <modules> <IGN_Siteblocks> <version>1.0.0</version> </IGN_Siteblocks> </modules> <global> <blocks> <siteblocks> <class>IGN_Siteblocks_Block</class> </siteblocks> </blocks> <models> <siteblocks> <class>IGN_Siteblocks_Model</class> <resourceModel>siteblocks_resource</resourceModel> </siteblocks> <siteblocks_resource> <class>IGN_Siteblocks_Model_Resource</class> <entities> <block> <table>ign_siteblock</table> </block> </entities> </siteblocks_resource> </models> <resources> <siteblocks_setup> <setup> <module>IGN_Siteblocks</module> </setup> </siteblocks_setup> </resources> <helpers> <siteblocks> <class>IGN_Siteblocks_Helper</class> </siteblocks> </helpers> </global> <frontend> <events> <controller_action_predispatch> </controller_action_predispatch> <checkout_cart_product_add_after> <observers> <siteblocks> <class>siteblocks/observer</class> <method>checkout_cart_product_add_after</method> <type>model</type> </siteblocks> </observers> </checkout_cart_product_add_after> </events> <layout> <updates> <siteblocks module="siteblocks"> <file>siteblocks.xml</file> </siteblocks> </updates> </layout> <routers> <siteblocks> <use>standard</use> <args> <module>IGN_Siteblocks</module> <frontName>siteblocks</frontName> </args> </siteblocks> </routers> <translate> <modules> <IGN_Siteblocks> <files> <default>IGN_Siteblocks.csv</default> </files> </IGN_Siteblocks> </modules> </translate> </frontend> <admin> <routers> <adminhtml> <args> <modules> <siteblocks after="Mage_Adminhtml">IGN_Siteblocks_Adminhtml</siteblocks> </modules> </args> </adminhtml> </routers> </admin> <default> <siteblocks> <settings> <enabled>1</enabled> <block_count>10</block_count> </settings> </siteblocks> </default> <crontab> <jobs> <siteblocks_clear_cache> <!--   --> <schedule> <cron_expr>*/10 * * * *</cron_expr> <!--  10  --> </schedule> <run> <model>siteblocks/cron::siteblocks_clear_cache</model> <!--   ,     --> </run> </siteblocks_clear_cache> </jobs> </crontab> </config>
      
      







タスクには、個別のファイルCron.phpを使用します



アプリ/コード/ローカル/ IGN /サイトブロック/モデル/ Cron.php
 <?php class IGN_Siteblocks_Model_Cron { public function siteblocks_clear_cache() { //do something here Mage::app()->cleanCache(array('siteblocks_blocks')); } }
      
      











管理パネルでレンダラーを使用する



ビデオ:Magento管理領域でのレンダリングの使用




レッスンで作成されたIGN_Siteblocks-10.zip モジュールの構造



多くの場合、標準の要素では目的の機能を実装するには不十分です。したがって、目的の要素のレンダラーを作成することができ、このプロセスに多くの時間は必要ありません。



フォーム要素のレンダラーを作成することを検討してください。管理フォームがあります:



アプリ/コード/ローカル/ IGN /サイトブロック/ブロック/ Adminhtml /サイトブロック/編集/ Form.php
 <?php class IGN_Siteblocks_Block_Adminhtml_Siteblocks_Edit_Form extends Mage_Adminhtml_Block_Widget_Form { /** * Init form */ public function __construct() { parent::__construct(); $this->setId('block_form'); $this->setTitle(Mage::helper('siteblocks')->__('Block Information')); } protected function _prepareForm() { $model = Mage::registry('siteblocks_block'); $form = new Varien_Data_Form( array( 'id' => 'edit_form', 'action' => $this->getUrl('*/*/save',array('block_id'=>$this->getRequest()->getParam('block_id'))), 'method' => 'post', 'enctype' => 'multipart/form-data' ) ); $form->setHtmlIdPrefix('block_'); $fieldset = $form->addFieldset('base_fieldset', array( 'legend'=>Mage::helper('siteblocks')->__('General Information'), 'class' => 'fieldset-wide') ); if ($model->getBlockId()) { $fieldset->addField('block_id', 'hidden', array( 'name' => 'block_id', )); } $fieldset->addField('title', 'text', array( 'name' => 'title', 'label' => Mage::helper('siteblocks')->__('Block Title'), 'title' => Mage::helper('siteblocks')->__('Block Title'), 'required' => true, )); #1           #       .../Block/Adminhtml/Siteblocks/Edit/Renderer/Myimage.php $fieldset->addType('myimage','IGN_Siteblocks_Block_Adminhtml_Siteblocks_Edit_Renderer_Myimage'); #       -,     lib/Varien/Data/Form/Element/Myimage.php $fieldset->addField('image', 'myimage', array( 'name' => 'image', 'label' => Mage::helper('siteblocks')->__('Image'), 'title' => Mage::helper('siteblocks')->__('Image'), 'required' => true, )); $fieldset->addField('block_status', 'select', array( 'label' => Mage::helper('siteblocks')->__('Status'), 'title' => Mage::helper('siteblocks')->__('Status'), 'name' => 'block_status', 'required' => true, 'options' => Mage::getModel('siteblocks/source_status')->toArray(), )); $fieldset->addField('content', 'textarea', array( 'name' => 'content', 'label' => Mage::helper('siteblocks')->__('Content'), 'title' => Mage::helper('siteblocks')->__('Content'), 'style' => 'height:36em', 'required' => true, )); $form->setValues($model->getData()); $form->setUseContainer(true); $this->setForm($form); return parent::_prepareForm(); } }
      
      







フォームにはレンダラーを作成するための2つのオプションがあり、任意のオプションを使用できますが、lib / Varien / Data / Form / Element /フォルダーにファイルを作成するオプションに感銘を受けました。 なぜならこの場合、例に従って、<frontend_type> myimage </ frontend_type>を穏やかに示すsystem.xmlのフィールドで同じレンダラーを使用できます。



ファイルの内容:



アプリ/コード/ローカル/ IGN /サイトブロック/ブロック/ Adminhtml /サイトブロック/編集/レンダラー/ Myimage.php
 <?php class IGN_Siteblocks_Block_Adminhtml_Siteblocks_Edit_Renderer_Myimage extends Varien_Data_Form_Element_Abstract { /** * Constructor * * @param array $data */ public function __construct($data) { parent::__construct($data); $this->setType('file'); } /** * Return element html code * * @return string */ public function getElementHtml() { $html = ''; if ((string)$this->getValue()) { $url = $this->_getUrl(); if( !preg_match("/^http\:\/\/|https\:\/\//", $url) ) { $url = Mage::getBaseUrl('media') . 'siteblocks' .DS.$url; } $html = '<a href="' . $url . '"' . ' onclick="imagePreview(\'' . $this->getHtmlId() . '_image\'); return false;">' . '<img src="' . $url . '" id="' . $this->getHtmlId() . '_image" title="' . $this->getValue() . '"' . ' alt="' . $this->getValue() . '" height="100" width="100" class="small-image-preview v-middle" />' . '</a> '; /*$additional = Mage::app()->getLayout()->createBlock('Mage_Adminhtml_Block_Template'); $additional->setTemplate('siteblocks/image.phtml') ->setImageUrl($url); $html = $additional->toHtml();*/ #       ,   html    ,      } $this->setClass('input-file'); $html .= parent::getElementHtml(); return $html; } /** * Return html code of hidden element * * @return string */ protected function _getHiddenInput() { return '<input type="hidden" name="' . parent::getName() . '[value]" value="' . $this->getValue() . '" />'; } /** * Get image preview url * * @return string */ protected function _getUrl() { return $this->getValue(); } /** * Return name * * @return string */ public function getName() { return $this->getData('name'); } }
      
      









lib / Varien / Data / Form / Element / Myimage.php
 <?php class Varien_Data_Form_Element_Myimage extends Varien_Data_Form_Element_Abstract { /** * Constructor * * @param array $data */ public function __construct($data) { parent::__construct($data); $this->setType('file'); } /** * Return element html code * * @return string */ public function getElementHtml() { $html = ''; if ((string)$this->getValue()) { $url = $this->_getUrl(); if( !preg_match("/^http\:\/\/|https\:\/\//", $url) ) { $url = Mage::getBaseUrl('media') . 'siteblocks' .DS.$url; } $html = '<a href="' . $url . '"' . ' onclick="imagePreview(\'' . $this->getHtmlId() . '_image\'); return false;">' . '<img src="' . $url . '" id="' . $this->getHtmlId() . '_image" title="' . $this->getValue() . '"' . ' alt="' . $this->getValue() . '" height="150" width="150" class="small-image-preview v-middle" />' . '</a> '; /*$additional = Mage::app()->getLayout()->createBlock('Mage_Adminhtml_Block_Template'); $additional->setTemplate('siteblocks/image.phtml') ->setImageUrl($url); $html = $additional->toHtml();*/ #       ,   html    ,      } $this->setClass('input-file'); $html .= parent::getElementHtml(); return $html; } /** * Return html code of hidden element * * @return string */ protected function _getHiddenInput() { return '<input type="hidden" name="' . parent::getName() . '[value]" value="' . $this->getValue() . '" />'; } /** * Get image preview url * * @return string */ protected function _getUrl() { return $this->getValue(); } /** * Return name * * @return string */ public function getName() { return $this->getData('name'); } }
      
      







これらのファイルの内容を標準のlib / Varien / Data / Form / Element / Image.phpからコピーし

、ニーズに合わせてコードを調整しました。



次に、Grid列のレンダラーを作成しましょう。



これに加えて、モジュール機能にいくつかの追加を行いました。画像の読み込みと保存の機能を作成する必要がありました。



アプリ/コード/ローカル/ IGN / Siteblocks / Block / Adminhtml / Siteblocks / Grid.php
 <?php class IGN_Siteblocks_Block_Adminhtml_Siteblocks_Grid extends Mage_Adminhtml_Block_Widget_Grid { public function __construct() { parent::__construct(); $this->setId('cmsBlockGrid'); $this->setDefaultSort('block_identifier'); $this->setDefaultDir('ASC'); } protected function _prepareCollection() { $collection = Mage::getModel('siteblocks/block')->getCollection(); /* @var $collection Mage_Cms_Model_Mysql4_Block_Collection */ $this->setCollection($collection); return parent::_prepareCollection(); } protected function _prepareColumns() { $this->addColumn('title', array( 'header' => Mage::helper('siteblocks')->__('Title'), 'align' => 'left', 'index' => 'title', )); $this->addColumn('image', array( 'header' => Mage::helper('siteblocks')->__('Image'), 'align' => 'left', 'index' => 'image', 'filter' => false, <!--      --> 'sortable' => false,<!--      --> 'renderer' => 'IGN_Siteblocks_Block_Adminhtml_Siteblocks_Grid_Renderer_Image', // 'renderer' => 'siteblocks/adminhtml_siteblocks_grid_renderer_image' #  )); $this->addColumn('block_status', array( 'header' => Mage::helper('cms')->__('Status'), 'align' => 'left', 'type' => 'options', 'options' => Mage::getModel('siteblocks/source_status')->toArray(), 'index' => 'block_status' )); $this->addColumn('created_at', array( 'header' => Mage::helper('siteblocks')->__('Created At'), 'index' => 'created_at', 'type' => 'date', )); return parent::_prepareColumns(); } protected function _prepareMassaction() { $this->setMassactionIdField('block_id'); $this->getMassactionBlock()->setIdFieldName('block_id'); $this->getMassactionBlock() ->addItem('delete', array( 'label' => Mage::helper('siteblocks')->__('Delete'), 'url' => $this->getUrl('*/*/massDelete'), 'confirm' => Mage::helper('siteblocks')->__('Are you sure?') ) ) ->addItem('status', array( 'label' => Mage::helper('siteblocks')->__('Update status'), 'url' => $this->getUrl('*/*/massStatus'), 'additional' => array('block_status'=> array( 'name' => 'block_status', 'type' => 'select', 'class' => 'required-entry', 'label' => Mage::helper('siteblocks')->__('Status'), 'values' => Mage::getModel('siteblocks/source_status')->toOptionArray() ) ) ) ); return $this; } /** * Row click url * * @return string */ public function getRowUrl($row) { return $this->getUrl('*/*/edit', array('block_id' => $row->getId())); } }
      
      







アプリ/コード/ローカル/ IGN /サイトブロック/ブロック/ Adminhtml /サイトブロック/グリッド/レンダラー/ Image.php
 <?php class IGN_Siteblocks_Block_Adminhtml_Siteblocks_Grid_Renderer_Image extends Mage_Adminhtml_Block_Widget_Grid_Column_Renderer_Abstract { public function render(Varien_Object $row) #       { if( ! $row->getImage()) { return ''; } $url = Mage::getBaseUrl('media') . 'siteblocks' .DS .$row->getImage(); $html = "<img src='$url' width='100' height='auto'>"; return $html; } }
      
      







レンダラーで、$ src URLを生成し、画像のhtmlコードを表示します。これで、表に写真が表示されます。



画像をモジュールにロードするには、いくつかの追加が必要です。



1. config.xmlのバージョンを1.0.1

にアップグレードします2. upgrade-1.0.0-1.0.1.phpファイルを作成します



app / code / local / IGN / Siteblocks / sql / siteblocks_setup / upgrade-1.0.0-1.0.1.php
 <?php /** @var Mage_Core_Model_Resource_Setup $installer */ $installer = $this; $installer->startSetup(); $installer->run(" ALTER TABLE `{$this->getTable('siteblocks/block')}` ADD `image` TEXT NOT NULL; "); $installer->endSetup();
      
      







3.コントローラーで、適切なコードを追加します。



アプリ/コード/ローカル/ IGN /サイトブロック/コントローラー/ Adminhtml / SiteblocksController.php
 <?php class IGN_Siteblocks_Adminhtml_SiteblocksController extends Mage_Adminhtml_Controller_Action { public function indexAction() { $this->loadLayout(); $this->_addContent($this->getLayout()->createBlock('siteblocks/adminhtml_siteblocks')); $this->renderLayout(); } public function newAction() { $this->_forward('edit'); } public function editAction() { $id = $this->getRequest()->getParam('block_id'); Mage::register('siteblocks_block',Mage::getModel('siteblocks/block')->load($id)); $blockObject = (array)Mage::getSingleton('adminhtml/session')->getBlockObject(true); if(count($blockObject)) { Mage::registry('siteblocks_block')->setData($blockObject); } $this->loadLayout(); $this->_addContent($this->getLayout()->createBlock('siteblocks/adminhtml_siteblocks_edit')); $this->renderLayout(); } //    protected function _uploadFile($fieldName,$model) { if( ! isset($_FILES[$fieldName])) { return false; } $file = $_FILES[$fieldName]; if(isset($file['name']) && (file_exists($file['tmp_name']))){ if($model->getId()){ unlink(Mage::getBaseDir('media').DS.$model->getData($fieldName)); } try { $path = Mage::getBaseDir('media') . DS . 'siteblocks' . DS; $uploader = new Varien_File_Uploader($file); $uploader->setAllowedExtensions(array('jpg','png','gif','jpeg')); $uploader->setAllowRenameFiles(true); $uploader->setFilesDispersion(false); $uploader->save($path, $file['name']); $model->setData($fieldName,$uploader->getUploadedFileName()); return true; } catch(Exception $e) { return false; } } } public function saveAction() { try { $id = $this->getRequest()->getParam('block_id'); $block = Mage::getModel('siteblocks/block')->load($id); /*$block ->setTitle($this->getRequest()->getParam('title')) ->setContent($this->getRequest()->getParam('content')) ->setBlockStatus($this->getRequest()->getParam('block_status')) ->save();*/ $block ->setData($this->getRequest()->getParams()); $this->_uploadFile('image',$block); //    $block ->setCreatedAt(Mage::app()->getLocale()->date()) ->save(); if(!$block->getId()) { Mage::getSingleton('adminhtml/session')->addError('Cannot save the block'); } } catch(Exception $e) { Mage::logException($e); Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); Mage::getSingleton('adminhtml/session')->setBlockObject($block->getData()); return $this->_redirect('*/*/edit',array('block_id'=>$this->getRequest()->getParam('block_id'))); } Mage::getSingleton('adminhtml/session')->addSuccess('Block was saved successfully!'); $this->_redirect('*/*/'.$this->getRequest()->getParam('back','index'),array('block_id'=>$block->getId())); } public function deleteAction() { $block = Mage::getModel('siteblocks/block') ->setId($this->getRequest()->getParam('block_id')) ->delete(); if($block->getId()) { Mage::getSingleton('adminhtml/session')->addSuccess('Block was deleted successfully!'); } $this->_redirect('*/*/'); } public function massStatusAction() { $statuses = $this->getRequest()->getParams(); try { $blocks= Mage::getModel('siteblocks/block') ->getCollection() ->addFieldToFilter('block_id',array('in'=>$statuses['massaction'])); foreach($blocks as $block) { $block->setBlockStatus($statuses['block_status'])->save(); } } catch(Exception $e) { Mage::logException($e); Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); return $this->_redirect('*/*/'); } Mage::getSingleton('adminhtml/session')->addSuccess('Blocks were updated!'); return $this->_redirect('*/*/'); } public function massDeleteAction() { $blocks = $this->getRequest()->getParams(); try { $blocks= Mage::getModel('siteblocks/block') ->getCollection() ->addFieldToFilter('block_id',array('in'=>$blocks['massaction'])); foreach($blocks as $block) { $block->delete(); } } catch(Exception $e) { Mage::logException($e); Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); return $this->_redirect('*/*/'); } Mage::getSingleton('adminhtml/session')->addSuccess('Blocks were deleted!'); return $this->_redirect('*/*/'); } }
      
      







4.メディア/サイトブロック/フォルダーを作成し、適切な書き込み権限を割り当てることを忘れないでください。



フロントエンドでの画像の表示を忘れないでください。



テンプレートを編集します。



アプリ/デザイン/フロントエンド/ベース/デフォルト/テンプレート/サイトブロック/ list.phtml
 <?php foreach($this->getBlocks() as $block):?> <div class="siteblock"> <div class="block-title"><?php echo $block->getTitle()?></div> <div class="block-image"> <?php if($block->getImage()):?> <img src="<?php echo $block->getImageSrc()?>" height="150" width="auto" alt="<?php $block->getTitle()?>" title="<?php $block->getTitle()?>"> <?php endif;?> </div> <div class="block-content"><?php echo $block->getContent() ?></div> </div> <?php endforeach;?>
      
      







モデルに新しいgetImageSrcメソッドを追加しました。そのリストを次に示します。



アプリ/コード/ローカル/ IGN /サイトブロック/モデル/ Block.php
 <?php /** * Class IGN_Siteblocks_Model_Block * @method getBlockStatus() * @method getContent() * @method getImage() */ class IGN_Siteblocks_Model_Block extends Mage_Core_Model_Abstract { protected $_eventPrefix = 'siteblocks_block'; public function _construct() { parent::_construct(); $this->_init('siteblocks/block'); } public function getImageSrc() { return Mage::getBaseUrl('media') . 'siteblocks' . DS . $this->getImage(); } }
      
      







アップロードされたフルサイズの画像を表示することはお勧めできませんが、現在の主なタスクはレンダラーを記述することです。





WYSIWYGエディターの使用



ビデオ:Magento管理パネルでWYSIWYGエディターを使用する




レッスンで作成されたモジュールIGN_Siteblocks-11.zip



WYSIWYG の構造は、表示されるものが取得するものです(表示されるものは取得するものです)。これは、コンテンツを作成するための便利なエディターです。そして、私たちのモジュールにはアプリケーションがあります。ただし、その組み込みは予想ほど単純ではありません。私たちは、管理パネルのレイアウトを作成する必要があることに気付きました。



app / design / adminhtml / default / default / layout / siteblocks.xml
 <?xml version="1.0"?> <layout version="1.0.0"> <adminhtml_siteblocks_edit> <!--       --> <update handle="editor"/> <!--     handle      js  css   ,      cms.xml --> </adminhtml_siteblocks_edit> <adminhtml_system_config_edit> <update handle="editor"/> </adminhtml_system_config_edit> </layout>
      
      







次に、編集フォームを更新する必要があります。



アプリ/コード/ローカル/ IGN /サイトブロック/ブロック/ Adminhtml /サイトブロック/編集/ Form.php
 <?php class IGN_Siteblocks_Block_Adminhtml_Siteblocks_Edit_Form extends Mage_Adminhtml_Block_Widget_Form { /** * Init form */ public function __construct() { parent::__construct(); $this->setId('block_form'); $this->setTitle(Mage::helper('siteblocks')->__('Block Information')); } protected function _prepareForm() { $model = Mage::registry('siteblocks_block'); $form = new Varien_Data_Form( array( 'id' => 'edit_form', 'action' => $this->getUrl('*/*/save',array('block_id'=>$this->getRequest()->getParam('block_id'))), 'method' => 'post', 'enctype' => 'multipart/form-data' ) ); $form->setHtmlIdPrefix('block_'); $fieldset = $form->addFieldset('base_fieldset', array( 'legend'=>Mage::helper('siteblocks')->__('General Information'), 'class' => 'fieldset-wide') ); if ($model->getBlockId()) { $fieldset->addField('block_id', 'hidden', array( 'name' => 'block_id', )); } $fieldset->addField('title', 'text', array( 'name' => 'title', 'label' => Mage::helper('siteblocks')->__('Block Title'), 'title' => Mage::helper('siteblocks')->__('Block Title'), 'required' => true, )); //$fieldset->addType('myimage','IGN_Siteblocks_Block_Adminhtml_Siteblocks_Edit_Renderer_Myimage'); $fieldset->addField('image', 'myimage', array( 'name' => 'image', 'label' => Mage::helper('siteblocks')->__('Image'), 'title' => Mage::helper('siteblocks')->__('Image'), 'required' => true, )); $fieldset->addField('block_status', 'select', array( 'label' => Mage::helper('siteblocks')->__('Status'), 'title' => Mage::helper('siteblocks')->__('Status'), 'name' => 'block_status', 'required' => true, 'options' => Mage::getModel('siteblocks/source_status')->toArray(), )); #   $fieldset->addField('content', 'editor', array( 'name' => 'content', 'label' => Mage::helper('siteblocks')->__('Content'), 'title' => Mage::helper('siteblocks')->__('Content'), 'style' => 'height:36em', 'required' => true, 'config' => Mage::getSingleton('cms/wysiwyg_config')->getConfig() )); $form->setValues($model->getData()); $form->setUseContainer(true); $this->setForm($form); return parent::_prepareForm(); } //  ,       head,      protected function _prepareLayout() { parent::_prepareLayout(); if (Mage::getSingleton('cms/wysiwyg_config')->isEnabled()) { $this->getLayout()->getBlock('head')->setCanLoadTinyMce(true); } } }
      
      







これらのアクションの後、退屈なテキストエリアの代わりに、便利なエディターフィールドが得られます。構成ページのフィールドに対して同じことを行いたい場合は、基本的に標準のエディター要素のコピーアンドペーストである新しいレンダラーを作成する必要があります。



lib / Varien / Data / Form / Element / Myeditor.php
 <?php class Varien_Data_Form_Element_Myeditor extends Varien_Data_Form_Element_Editor { public function __construct($attributes=array()) { parent::__construct($attributes); #      if (Mage::getSingleton('cms/wysiwyg_config')->isEnabled()) { Mage::app()->getLayout()->getBlock('head')->setCanLoadTinyMce(true); $this->setData('config',Mage::getSingleton('cms/wysiwyg_config')->getConfig()); } if($this->isEnabled()) { $this->setType('wysiwyg'); $this->setExtType('wysiwyg'); } else { $this->setType('textarea'); $this->setExtType('textarea'); } } }
      
      







system.xmlは次のようになります。



アプリ/コード/ローカル/ IGN /サイトブロック/ etc / system.xml
 <?xml version="1.0"?> <config> <tabs> <ign translate="label" module="siteblocks"> <label>IGN</label> <sort_order>2</sort_order> </ign> </tabs> <sections> <siteblocks module="siteblocks" translate="label"> <label>Siteblocks</label> <tab>ign</tab> <frontend>text</frontend> <sort_order>1</sort_order> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>1</show_in_store> <groups> <settings module="siteblocks" translate="label"> <label>Settings</label> <expanded>1</expanded> <sort_order>1</sort_order> <show_in_default>1</show_in_default> <show_in_Website>1</show_in_Website> <show_in_store>1</show_in_store> <fields> <enabled translate="label comment" module="siteblocks"> <label>Enabled</label> <frontend_type>select</frontend_type> <source_model>siteblocks/source_status</source_model> <sort_order>1</sort_order> <show_in_default>1</show_in_default> <show_in_Website>1</show_in_Website> <show_in_store>1</show_in_store> <comment>Is module enabled</comment> </enabled> <blocks_count> <label>Blocks on page</label> <frontend_type>text</frontend_type> <sort_order>2</sort_order> <show_in_default>1</show_in_default> <show_in_Website>1</show_in_Website> <show_in_store>1</show_in_store> <depends><enabled>1</enabled></depends> </blocks_count> <raw_text> <label>Raw text</label> <frontend_type>myeditor</frontend_type> <!--    frontend_type --> <sort_order>3</sort_order> <show_in_default>1</show_in_default> <show_in_Website>1</show_in_Website> <show_in_store>1</show_in_store> <depends><enabled>1</enabled></depends> </raw_text> <myimage> <label>Image</label> <frontend_type>myimage</frontend_type> <sort_order>3</sort_order> <show_in_default>1</show_in_default> <show_in_Website>1</show_in_Website> <show_in_store>1</show_in_store> <depends><enabled>1</enabled></depends> </myimage> </fields> </settings> </groups> </siteblocks> </sections> </config>
      
      







このモジュールでは、これは必須フィールドではなく、例として作成されています。しかし、この方法でコンテンツをフロントエンドに表示します。



アプリ/デザイン/フロントエンド/ベース/デフォルト/テンプレート/サイトブロック/ list.phtml
 <?php foreach($this->getBlocks() as $block):?> <div class="siteblock"> <div class="block-title"><?php echo $block->getTitle()?></div> <div class="block-image"> <?php if($block->getImage()):?> <img src="<?php echo $block->getImageSrc()?>" height="150" width="auto" alt="<?php $block->getTitle()?>" title="<?php $block->getTitle()?>"> <?php endif;?> </div> <div class="block-content"><?php echo $this->getBlockContent($block)?></div> </div> <?php endforeach;?>
      
      







ブロックでは、このために新しいgetBlockContentメソッドが作成されました。



app / local / IGN / Siteblocks / Block / List.php
 <?php class IGN_Siteblocks_Block_List extends Mage_Core_Block_Template { public function getBlocks() { //return Mage::getResourceModel('siteblocks/block_collection'); $items = Mage::getModel('siteblocks/block')->getCollection() ->addFieldToFilter('block_status',array('eq'=>IGN_Siteblocks_Model_Source_Status::ENABLED)); return $items; } public function getBlockContent($block) { $processor = Mage::helper('cms')->getBlockTemplateProcessor(); $html = $processor->filter($block->getContent()); return $html; } }
      
      











ルール条件を使用する



ビデオ:Magentoでルール条件を使用する




レッスンで作成したIGN_Siteblocks-12.zip モジュールの構造



次のステップは、モジュールに条件を追加することです。同じことがMagentoプロモーションルールでも使用されています。そして、ここでは2種類の条件が用意されています。最初は、2番目のバスケットで製品属性が使用されます。以下のレシピでは最初のケースについて説明しますが、違いはいくつかの行の置換のみです。



なぜ条件が必要なのですか?ブロックを表示する場所を選択するために、条件を使用します。たとえば、価格が100ドル未満の製品ページ、または16 GBのメモリと2015年の製造日がある特定のカテゴリのすべての電話。ここではユーザーケースについては説明しません。



作成順序:



1.モジュールバージョンを更新し、テーブルに新しい列が追加されるようにアップグレードスクリプトを追加します。conditions_serializedなどTEXT



app / code / local / IGN / Siteblocks / sql / siteblocks_setup / upgrade-1.0.1-1.0.2.php
 <?php /** @var Mage_Core_Model_Resource_Setup $installer */ $installer = $this; $installer->startSetup(); $installer->run(" ALTER TABLE `{$this->getTable('siteblocks/block')}` ADD `conditions_serialized` TEXT NOT NULL; "); $installer->endSetup();
      
      







2.モデルはMage_Rule_Model_Abstractを継承する必要があります。そして、2つのメソッドを宣言する必要があります:getConditionsInstancegetActionInstance



アプリ/コード/ローカル/ IGN /サイトブロック/モデル/ Observer.php
 <?php /** * Class IGN_Siteblocks_Model_Block * @method getBlockStatus() * @method getContent() * @method getImage() */ class IGN_Siteblocks_Model_Block extends Mage_Rule_Model_Abstract { protected $_eventPrefix = 'siteblocks_block'; # ,      ,     public function getActionsInstance() { return Mage::getModel('catalogrule/rule_action_collection'); } public function getConditionsInstance() { return Mage::getModel('catalogrule/rule_condition_combine'); } public function _construct() { parent::_construct(); $this->_init('siteblocks/block'); } public function getImageSrc() { return Mage::getBaseUrl('media') . 'siteblocks' . DS . $this->getImage(); } }
      
      







getConditionsInstanceメソッドへのすべての注意ここで、Catalog Price Rulesのような条件を使用します。製品のプロパティと属性のみ。ショッピングカート価格ルールのような条件が必要な場合は、Mage :: getModel( 'salesrule / rule_condition_combine');を使用する必要があります。



バスケット内のデータに基づいてブロックをいつ表示するかを決定する場合は、salesruleを使用します。また、独自のモデルを作成し、その中に任意の条件を実装できます。



3. コントローラーでsaveActionを更新する必要があります。



アプリ/コード/ローカル/ IGN /サイトブロック/コントローラー/ Adminhtml / SiteblocksController.php
 <?php class IGN_Siteblocks_Adminhtml_SiteblocksController extends Mage_Adminhtml_Controller_Action { public function indexAction() { $this->loadLayout(); $this->_addContent($this->getLayout()->createBlock('siteblocks/adminhtml_siteblocks')); $this->renderLayout(); } public function newAction() { $this->_forward('edit'); } public function editAction() { $id = $this->getRequest()->getParam('block_id'); Mage::register('siteblocks_block',Mage::getModel('siteblocks/block')->load($id)); $blockObject = (array)Mage::getSingleton('adminhtml/session')->getBlockObject(true); if(count($blockObject)) { Mage::registry('siteblocks_block')->setData($blockObject); } $this->loadLayout(); $this->_addContent($this->getLayout()->createBlock('siteblocks/adminhtml_siteblocks_edit')); $this->renderLayout(); } protected function _uploadFile($fieldName,$model) { if( ! isset($_FILES[$fieldName])) { return false; } $file = $_FILES[$fieldName]; if(isset($file['name']) && (file_exists($file['tmp_name']))){ if($model->getId()){ unlink(Mage::getBaseDir('media').DS.$model->getData($fieldName)); } try { $path = Mage::getBaseDir('media') . DS . 'siteblocks' . DS; $uploader = new Varien_File_Uploader($file); $uploader->setAllowedExtensions(array('jpg','png','gif','jpeg')); $uploader->setAllowRenameFiles(true); $uploader->setFilesDispersion(false); $uploader->save($path, $file['name']); $model->setData($fieldName,$uploader->getUploadedFileName()); return true; } catch(Exception $e) { return false; } } } public function saveAction() { try { $id = $this->getRequest()->getParam('block_id'); /** @var IGN_Siteblocks_Model_Block $block */ $block = Mage::getModel('siteblocks/block')->load($id); /*$block ->setTitle($this->getRequest()->getParam('title')) ->setContent($this->getRequest()->getParam('content')) ->setBlockStatus($this->getRequest()->getParam('block_status')) ->save();*/ #      $data = $this->getRequest()->getParams(); if (isset($data['rule']['conditions'])) { $data['conditions'] = $data['rule']['conditions']; } unset($data['rule']); # setData  loadPost $block ->loadPost($data); $this->_uploadFile('image',$block); $block ->setCreatedAt(Mage::app()->getLocale()->date()) ->save(); if(!$block->getId()) { Mage::getSingleton('adminhtml/session')->addError('Cannot save the block'); } } catch(Exception $e) { Mage::logException($e); Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); Mage::getSingleton('adminhtml/session')->setBlockObject($block->getData()); return $this->_redirect('*/*/edit',array('block_id'=>$this->getRequest()->getParam('block_id'))); } Mage::getSingleton('adminhtml/session')->addSuccess('Block was saved successfully!'); $this->_redirect('*/*/'.$this->getRequest()->getParam('back','index'),array('block_id'=>$block->getId())); } public function deleteAction() { $block = Mage::getModel('siteblocks/block') ->setId($this->getRequest()->getParam('block_id')) ->delete(); if($block->getId()) { Mage::getSingleton('adminhtml/session')->addSuccess('Block was deleted successfully!'); } $this->_redirect('*/*/'); } public function massStatusAction() { $statuses = $this->getRequest()->getParams(); try { $blocks= Mage::getModel('siteblocks/block') ->getCollection() ->addFieldToFilter('block_id',array('in'=>$statuses['massaction'])); foreach($blocks as $block) { $block->setBlockStatus($statuses['block_status'])->save(); } } catch(Exception $e) { Mage::logException($e); Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); return $this->_redirect('*/*/'); } Mage::getSingleton('adminhtml/session')->addSuccess('Blocks were updated!'); return $this->_redirect('*/*/'); } public function massDeleteAction() { $blocks = $this->getRequest()->getParams(); try { $blocks= Mage::getModel('siteblocks/block') ->getCollection() ->addFieldToFilter('block_id',array('in'=>$blocks['massaction'])); foreach($blocks as $block) { $block->delete(); } } catch(Exception $e) { Mage::logException($e); Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); return $this->_redirect('*/*/'); } Mage::getSingleton('adminhtml/session')->addSuccess('Blocks were deleted!'); return $this->_redirect('*/*/'); } }
      
      







4.管理者レイアウトを更新します。



アプリ/コード/デザイン/ adminhtml /デフォルト/デフォルト/レイアウト/ siteblocks.xml
 <?xml version="1.0"?> <layout version="1.0.0"> <adminhtml_siteblocks_edit> <update handle="editor"/> <!--     js  --> <reference name="head"> <action method="setCanLoadExtJs"><flag>1</flag></action> <action method="setCanLoadRulesJs"><flag>1</flag></action> </reference> </adminhtml_siteblocks_edit> <adminhtml_system_config_edit> <update handle="editor"/> </adminhtml_system_config_edit> </layout>
      
      







5.フォームの管理ファイルを編集します。ここで、条件デザイナーを追加します。



アプリ/コード/ローカル/ IGN /サイトブロック/ブロック/ Adminhtml /サイトブロック/編集/ Form.php
 <?php class IGN_Siteblocks_Block_Adminhtml_Siteblocks_Edit_Form extends Mage_Adminhtml_Block_Widget_Form { /** * Init form */ public function __construct() { parent::__construct(); $this->setId('block_form'); $this->setTitle(Mage::helper('siteblocks')->__('Block Information')); } protected function _prepareForm() { $model = Mage::registry('siteblocks_block'); $form = new Varien_Data_Form( array( 'id' => 'edit_form', 'action' => $this->getUrl('*/*/save',array('block_id'=>$this->getRequest()->getParam('block_id'))), 'method' => 'post', 'enctype' => 'multipart/form-data' ) ); $form->setHtmlIdPrefix('block_'); $fieldset = $form->addFieldset('base_fieldset', array( 'legend'=>Mage::helper('siteblocks')->__('General Information'), 'class' => 'fieldset-wide') ); if ($model->getBlockId()) { $fieldset->addField('block_id', 'hidden', array( 'name' => 'block_id', )); } $fieldset->addField('title', 'text', array( 'name' => 'title', 'label' => Mage::helper('siteblocks')->__('Block Title'), 'title' => Mage::helper('siteblocks')->__('Block Title'), 'required' => true, )); //$fieldset->addType('myimage','IGN_Siteblocks_Block_Adminhtml_Siteblocks_Edit_Renderer_Myimage'); $fieldset->addField('image', 'myimage', array( 'name' => 'image', 'label' => Mage::helper('siteblocks')->__('Image'), 'title' => Mage::helper('siteblocks')->__('Image'), 'required' => true, )); $fieldset->addField('block_status', 'select', array( 'label' => Mage::helper('siteblocks')->__('Status'), 'title' => Mage::helper('siteblocks')->__('Status'), 'name' => 'block_status', 'required' => true, 'options' => Mage::getModel('siteblocks/source_status')->toArray(), )); $fieldset->addField('content', 'editor', array( 'name' => 'content', 'label' => Mage::helper('siteblocks')->__('Content'), 'title' => Mage::helper('siteblocks')->__('Content'), 'style' => 'height:36em', 'required' => true, 'config' => Mage::getSingleton('cms/wysiwyg_config')->getConfig() )); #    $model->getConditions()->setJsFormObject('block_conditions_fieldset'); $renderer = Mage::getBlockSingleton('adminhtml/widget_form_renderer_fieldset') ->setTemplate('promo/fieldset.phtml') ->setNewChildUrl($this->getUrl('*/promo_catalog/newConditionHtml/form/block_conditions_fieldset')); $conditionsFieldset = $form->addFieldset('conditions_fieldset', array( 'legend'=>Mage::helper('siteblocks')->__('Conditions'), 'class' => 'fieldset-wide') )->setRenderer($renderer); $conditionsFieldset->addField('conditions', 'text', array( 'name' => 'conditions', 'label' => Mage::helper('siteblocks')->__('Conditions'), 'title' => Mage::helper('siteblocks')->__('Conditions'), 'required' => true, ))->setRule($model)->setRenderer(Mage::getBlockSingleton('rule/conditions')); $form->setValues($model->getData()); $form->setUseContainer(true); $this->setForm($form); return parent::_prepareForm(); } protected function _prepareLayout() { parent::_prepareLayout(); if (Mage::getSingleton('cms/wysiwyg_config')->isEnabled()) { #    ,    2   $this->getLayout()->getBlock('head')->setCanLoadExtJs(true); $this->getLayout()->getBlock('head')->setCanLoadRulesJs(true); $this->getLayout()->getBlock('head')->setCanLoadTinyMce(true); } } }
      
      







次の行に注意してください。



 $this->getUrl('*/promo_catalog/newConditionHtml/form/block_conditions_fieldset')
      
      





ショッピングカート価格ルールを使用する場合:



 $this->getUrl('*/promo_quote/newConditionHtml/form/block_conditions_fieldset')
      
      





別の重要なポイントを探します。



block_conditions_fieldset -どこblock_一致している必要があります$ form-> setHtmlIdPrefix( 'block_' );



そして、それは管理者側のすべてです。ここで、フロントエンドの条件の検証を追加します。このために、List.phpブロックを編集します



アプリ/コード/ローカル/ IGN /サイトブロック/ブロック/List.php
 <?php class IGN_Siteblocks_Block_List extends Mage_Core_Block_Template { public function getBlocks() { //return Mage::getResourceModel('siteblocks/block_collection'); $items = Mage::getModel('siteblocks/block')->getCollection() ->addFieldToFilter('block_status',array('eq'=>IGN_Siteblocks_Model_Source_Status::ENABLED)); $filteredItems = $items; #      . if(Mage::registry('current_product') instanceof Mage_Catalog_Model_Product) { $filteredItems = array(); /** @var IGN_Siteblocks_Model_Block $item */ foreach ($items as $item) { #  validate    ,     if($item->validate(Mage::registry('current_product'))) { $filteredItems[] = $item; } } } return $filteredItems; } public function getBlockContent($block) { $processor = Mage::helper('cms')->getBlockTemplateProcessor(); $html = $processor->filter($block->getContent()); return $html; } }
      
      







バリデータの使用は非常に簡単です。このケースでは、ブロックの出力がクリーチャーページで発生せず、この場合に検証するものがない場合、条件を無視します。





編集ページでタブを使用する



ビデオ:Magentoの編集ページでタブを使用する




レッスンで作成されたIGN_Siteblocks-13.zipモジュールの構造



多くのフィールドがある場合、タブは便利で便利です。フィールドをグループに分割し、各グループが独自のタブを作成します。タブを追加するにはいくつかのオプションがあります。まず、タブクラスを作成し、その出力を編集ページに追加する必要があります。クラス自体は次のようになります。



アプリ/コード/ローカル/ IGN /サイトブロック/ブロック/ Adminhtml /サイトブロック/編集/ Tabs.php
 <?php class IGN_Siteblocks_Block_Adminhtml_Siteblocks_Edit_Tabs extends Mage_Adminhtml_Block_Widget_Tabs { public function __construct() { parent::__construct(); $this->setId('block_tabs'); $this->setDestElementId('edit_form'); $this->setTitle(Mage::helper('siteblocks')->__('Block Information')); } #      .       protected function _prepareLayout() { $this->addTab('main_tab',array( 'label' => $this->__('Main'), 'title' => $this->__('Main'), 'content' => $this->getLayout()->createBlock('siteblocks/adminhtml_siteblocks_edit_tab_main')->toHtml() )); /*$this->addTab('conditions_tab',array( 'label' => $this->__('Conditions'), 'title' => $this->__('Conditions'), 'content' => $this->getLayout()->createBlock('siteblocks/adminhtml_siteblocks_edit_tab_conditions')->toHtml() ));*/ $this->addTab('conditions_tab','siteblocks/adminhtml_siteblocks_edit_tab_conditions'); return parent::_prepareLayout(); } }
      
      







addTabメソッドの実装を見てください。配列、オブジェクト、文字列をフィードできることがわかります。そして、いくつかの違いがあります。ここでは、ビデオを見て、それを明確に示すことをお勧めします。しかし、ここで一言言います。



メソッドに文字列を渡す場合、タブクラスはMage_Adminhtml_Block_Widget_Tab_Interfaceインターフェイスを実装する必要があります



そうしないと、エラーが発生します。また、インターフェースには4つのメソッドの実装が必要です。したがって、この例では、デモ用に2つのオプションを使用します。実際には、同じ方法でタブを追加することをお勧めします。



ソースファイルForm.phpからコピーしたタブの内容を見てみましょう



アプリ/コード/ローカル/ IGN /サイトブロック/ブロック/ Adminhtml /サイトブロック/編集/タブ/ Main.php
 <?php class IGN_Siteblocks_Block_Adminhtml_Siteblocks_Edit_Tab_Main extends Mage_Adminhtml_Block_Widget_Form { /** * Init form */ public function __construct() { parent::__construct(); $this->setId('main_form'); $this->setTitle(Mage::helper('siteblocks')->__('Block Information')); } protected function _prepareForm() { $model = Mage::registry('siteblocks_block'); $form = new Varien_Data_Form(); $form->setHtmlIdPrefix('main_'); $fieldset = $form->addFieldset('base_fieldset', array( 'legend'=>Mage::helper('siteblocks')->__('General Information'), 'class' => 'fieldset-wide') ); if ($model->getBlockId()) { $fieldset->addField('block_id', 'hidden', array( 'name' => 'block_id', )); } $fieldset->addField('title', 'text', array( 'name' => 'title', 'label' => Mage::helper('siteblocks')->__('Block Title'), 'title' => Mage::helper('siteblocks')->__('Block Title'), 'required' => true, )); //$fieldset->addType('myimage','IGN_Siteblocks_Block_Adminhtml_Siteblocks_Edit_Renderer_Myimage'); $fieldset->addField('image', 'myimage', array( 'name' => 'image', 'label' => Mage::helper('siteblocks')->__('Image'), 'title' => Mage::helper('siteblocks')->__('Image'), 'required' => true, )); $fieldset->addField('block_status', 'select', array( 'label' => Mage::helper('siteblocks')->__('Status'), 'title' => Mage::helper('siteblocks')->__('Status'), 'name' => 'block_status', 'required' => true, 'options' => Mage::getModel('siteblocks/source_status')->toArray(), )); $fieldset->addField('content', 'editor', array( 'name' => 'content', 'label' => Mage::helper('siteblocks')->__('Content'), 'title' => Mage::helper('siteblocks')->__('Content'), 'style' => 'height:36em', 'required' => true, 'config' => Mage::getSingleton('cms/wysiwyg_config')->getConfig() )); $form->setValues($model->getData()); $this->setForm($form); return parent::_prepareForm(); } protected function _prepareLayout() { parent::_prepareLayout(); if (Mage::getSingleton('cms/wysiwyg_config')->isEnabled()) { $this->getLayout()->getBlock('head')->setCanLoadTinyMce(true); } } }
      
      







アプリ/コード/ローカル/ IGN /サイトブロック/ブロック/ Adminhtml /サイトブロック/編集/タブ/ Conditions.php
 <?php class IGN_Siteblocks_Block_Adminhtml_Siteblocks_Edit_Tab_Conditions extends Mage_Adminhtml_Block_Widget_Form implements Mage_Adminhtml_Block_Widget_Tab_Interface { #,    public function getTabTitle() { return $this->__('Conditions'); } public function getTabLabel() { return $this->__('Conditions'); } public function canShowTab() { return true; } public function isHidden() { return false; } /** * Init form */ public function __construct() { parent::__construct(); $this->setId('conditions_form'); $this->setTitle(Mage::helper('siteblocks')->__('Block Conditions')); } protected function _prepareForm() { $model = Mage::registry('siteblocks_block'); $form = new Varien_Data_Form(); $form->setHtmlIdPrefix('block_'); $model->getConditions()->setJsFormObject('block_conditions_fieldset'); $renderer = Mage::getBlockSingleton('adminhtml/widget_form_renderer_fieldset') ->setTemplate('promo/fieldset.phtml') ->setNewChildUrl($this->getUrl('*/promo_catalog/newConditionHtml/form/block_conditions_fieldset')); $conditionsFieldset = $form->addFieldset('conditions_fieldset', array( 'legend'=>Mage::helper('siteblocks')->__('Conditions'), 'class' => 'fieldset-wide') )->setRenderer($renderer); $conditionsFieldset->addField('conditions', 'text', array( 'name' => 'conditions', 'label' => Mage::helper('siteblocks')->__('Conditions'), 'title' => Mage::helper('siteblocks')->__('Conditions'), 'required' => true, ))->setRule($model)->setRenderer(Mage::getBlockSingleton('rule/conditions')); $form->setValues($model->getData()); $this->setForm($form); return parent::_prepareForm(); } protected function _prepareLayout() { parent::_prepareLayout(); if (Mage::getSingleton('cms/wysiwyg_config')->isEnabled()) { $this->getLayout()->getBlock('head')->setCanLoadTinyMce(true); } } }
      
      







元のForm.phpファイルをコピーしました。分離されたフォーム要素。フラグを削除することを忘れないでください$ form-> setUseContainer(true); したがって、フォームのソースファイルからフィールドを削除できます。



アプリ/コード/ローカル/ IGN /サイトブロック/ブロック/ Adminhtml /サイトブロック/編集/ Form.php
 <?php class IGN_Siteblocks_Block_Adminhtml_Siteblocks_Edit_Form extends Mage_Adminhtml_Block_Widget_Form { /** * Init form */ public function __construct() { parent::__construct(); $this->setId('block_form'); $this->setTitle(Mage::helper('siteblocks')->__('Block Information')); } protected function _prepareForm() { $model = Mage::registry('siteblocks_block'); $form = new Varien_Data_Form( array( 'id' => 'edit_form', 'action' => $this->getUrl('*/*/save',array('block_id'=>$this->getRequest()->getParam('block_id'))), 'method' => 'post', 'enctype' => 'multipart/form-data' ) ); $form->setHtmlIdPrefix('block_'); $form->setValues($model->getData()); $form->setUseContainer(true); $this->setForm($form); return parent::_prepareForm(); } protected function _prepareLayout() { parent::_prepareLayout(); if (Mage::getSingleton('cms/wysiwyg_config')->isEnabled()) { $this->getLayout()->getBlock('head')->setCanLoadTinyMce(true); } } }
      
      







タブブロックの出力を描画する方法。



コントローラーのメソッド番号1:



アプリ/コード/ローカル/ IGN /サイトブロック/コントローラー/ Adminhtml / SiteblocksController.php
 <?php class IGN_Siteblocks_Adminhtml_SiteblocksController extends Mage_Adminhtml_Controller_Action { public function indexAction() { $this->loadLayout(); $this->_addContent($this->getLayout()->createBlock('siteblocks/adminhtml_siteblocks')); $this->renderLayout(); } public function newAction() { $this->_forward('edit'); } public function editAction() { $id = $this->getRequest()->getParam('block_id'); Mage::register('siteblocks_block',Mage::getModel('siteblocks/block')->load($id)); $blockObject = (array)Mage::getSingleton('adminhtml/session')->getBlockObject(true); if(count($blockObject)) { Mage::registry('siteblocks_block')->setData($blockObject); } $this->loadLayout(); #     $this->_addLeft($this->getLayout()->createBlock('siteblocks/adminhtml_siteblocks_edit_tabs')); $this->_addContent($this->getLayout()->createBlock('siteblocks/adminhtml_siteblocks_edit')); $this->renderLayout(); } protected function _uploadFile($fieldName,$model) { if( ! isset($_FILES[$fieldName])) { return false; } $file = $_FILES[$fieldName]; if(isset($file['name']) && (file_exists($file['tmp_name']))){ if($model->getId()){ unlink(Mage::getBaseDir('media').DS.$model->getData($fieldName)); } try { $path = Mage::getBaseDir('media') . DS . 'siteblocks' . DS; $uploader = new Varien_File_Uploader($file); $uploader->setAllowedExtensions(array('jpg','png','gif','jpeg')); $uploader->setAllowRenameFiles(true); $uploader->setFilesDispersion(false); $uploader->save($path, $file['name']); $model->setData($fieldName,$uploader->getUploadedFileName()); return true; } catch(Exception $e) { return false; } } } public function saveAction() { try { $id = $this->getRequest()->getParam('block_id'); /** @var IGN_Siteblocks_Model_Block $block */ $block = Mage::getModel('siteblocks/block')->load($id); /*$block ->setTitle($this->getRequest()->getParam('title')) ->setContent($this->getRequest()->getParam('content')) ->setBlockStatus($this->getRequest()->getParam('block_status')) ->save();*/ $data = $this->getRequest()->getParams(); if (isset($data['rule']['conditions'])) { $data['conditions'] = $data['rule']['conditions']; } unset($data['rule']); $block ->loadPost($data); $this->_uploadFile('image',$block); $block ->setCreatedAt(Mage::app()->getLocale()->date()) ->save(); if(!$block->getId()) { Mage::getSingleton('adminhtml/session')->addError('Cannot save the block'); } } catch(Exception $e) { Mage::logException($e); Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); Mage::getSingleton('adminhtml/session')->setBlockObject($block->getData()); return $this->_redirect('*/*/edit',array('block_id'=>$this->getRequest()->getParam('block_id'))); } Mage::getSingleton('adminhtml/session')->addSuccess('Block was saved successfully!'); $this->_redirect('*/*/'.$this->getRequest()->getParam('back','index'),array('block_id'=>$block->getId())); } public function deleteAction() { $block = Mage::getModel('siteblocks/block') ->setId($this->getRequest()->getParam('block_id')) ->delete(); if($block->getId()) { Mage::getSingleton('adminhtml/session')->addSuccess('Block was deleted successfully!'); } $this->_redirect('*/*/'); } public function massStatusAction() { $statuses = $this->getRequest()->getParams(); try { $blocks= Mage::getModel('siteblocks/block') ->getCollection() ->addFieldToFilter('block_id',array('in'=>$statuses['massaction'])); foreach($blocks as $block) { $block->setBlockStatus($statuses['block_status'])->save(); } } catch(Exception $e) { Mage::logException($e); Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); return $this->_redirect('*/*/'); } Mage::getSingleton('adminhtml/session')->addSuccess('Blocks were updated!'); return $this->_redirect('*/*/'); } public function massDeleteAction() { $blocks = $this->getRequest()->getParams(); try { $blocks= Mage::getModel('siteblocks/block') ->getCollection() ->addFieldToFilter('block_id',array('in'=>$blocks['massaction'])); foreach($blocks as $block) { $block->delete(); } } catch(Exception $e) { Mage::logException($e); Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); return $this->_redirect('*/*/'); } Mage::getSingleton('adminhtml/session')->addSuccess('Blocks were deleted!'); return $this->_redirect('*/*/'); } }
      
      







しかし、このベンチャーを放棄し、レイアウトでメソッド番号2を使用します。



app / design / adminhtml / default / default / layout / siteblocks.xml
 <?xml version="1.0"?> <layout version="1.0.0"> <adminhtml_siteblocks_edit> <update handle="editor"/> <reference name="head"> <action method="setCanLoadExtJs"><flag>1</flag></action> <action method="setCanLoadRulesJs"><flag>1</flag></action> </reference> <!--       --> <reference name="left"> <block type="siteblocks/adminhtml_siteblocks_edit_tabs" name="siteblocks_tabs"> <!-- 2 c     --> <block name="conditions_tab" type="siteblocks/adminhtml_siteblocks_edit_tab_conditions"/> <action method="addTab"><name>my_conditions</name><block>conditions_tab</block></action> <action method="addTab"><name>my_conditions</name><block>siteblocks/adminhtml_siteblocks_edit_tab_conditions</block></action> </block> </reference> </adminhtml_siteblocks_edit> <adminhtml_system_config_edit> <update handle="editor"/> </adminhtml_system_config_edit> </layout>
      
      







最後に、アドバイスの1つとして、すぐに2か所にタブを追加しないでください。1つはレイアウトに、もう1つはブロックにあります。レイアウト内の1つの場所、すべて、またはブロック内のすべてを追加します。





編集ページおよびフロントエンドでの商品の出力テーブル(グリッド)。



ビデオ:Magentoの編集ページでタブを使用する




レッスンで作成されたIGN_Siteblocks-14.zip モジュールの構造ここで、モジュールに



最終機能を追加します-ブロックとともにフロントエンドに表示される製品をマークする機能。



代替の関連製品の一種。ブロックに適した条件を備えた商品のページに、テキストと商品を含むブロックを出力する非常に有用な有用な事例が頭の中に形成されています。



新しいタブを追加します。



アプリ/コード/ローカル/ IGN /サイトブロック/ブロック/ Adminhtml /サイトブロック/編集/ Tabs.php
 <?php class IGN_Siteblocks_Block_Adminhtml_Siteblocks_Edit_Tabs extends Mage_Adminhtml_Block_Widget_Tabs { public function __construct() { parent::__construct(); $this->setId('block_tabs'); $this->setDestElementId('edit_form'); $this->setTitle(Mage::helper('siteblocks')->__('Block Information')); } protected function _prepareLayout() { $this->addTab('main_tab',array( 'label' => $this->__('Main'), 'title' => $this->__('Main'), 'content' => $this->getLayout()->createBlock('siteblocks/adminhtml_siteblocks_edit_tab_main')->toHtml() )); $this->addTab('conditions_tab',array( 'label' => $this->__('Conditions'), 'title' => $this->__('Conditions'), 'content' => $this->getLayout()->createBlock('siteblocks/adminhtml_siteblocks_edit_tab_conditions')->toHtml() )); //     AJAX,         $this->addTab('products_tab','siteblocks/adminhtml_siteblocks_edit_tab_products'); return parent::_prepareLayout(); } }
      
      







タブはAJAXを使用します。これはコードで見ることができます。リクエスト用のURLもあります。



アプリ/コード/ローカル/ IGN /サイトブロック/ブロック/ Adminhtml /サイトブロック/編集/タブ/ Products.php
 <?php class IGN_Siteblocks_Block_Adminhtml_Siteblocks_Edit_Tab_Products extends Mage_Adminhtml_Block_Widget_Form implements Mage_Adminhtml_Block_Widget_Tab_Interface { public function getTabTitle() { return $this->__('Products'); } public function getTabLabel() { return $this->__('Products'); } public function canShowTab() { return true; } public function isHidden() { return false; } public function getClass() { return 'ajax'; } public function getTabClass() { return 'ajax'; } #URL  , ('_current'=>true)     ,     block_id    public function getTabUrl() { return $this->getUrl('*/*/products',array('_current'=>true)); } }
      
      







なぜならタブはAJAXを使用しているため、コントローラーにアクションを追加する必要があります。そして、先を見ると、saveActionにどのロジックが追加されたかがわかり、マークされた製品が保存されます。



アプリ/コード/ローカル/ IGN /サイトブロック/コントローラー/ Adminhtml / SiteblocksController.php
 <?php class IGN_Siteblocks_Adminhtml_SiteblocksController extends Mage_Adminhtml_Controller_Action { public function indexAction() { $this->loadLayout(); $this->_addContent($this->getLayout()->createBlock('siteblocks/adminhtml_siteblocks')); $this->renderLayout(); } public function newAction() { $this->_forward('edit'); } public function editAction() { $id = $this->getRequest()->getParam('block_id'); Mage::register('siteblocks_block',Mage::getModel('siteblocks/block')->load($id)); $blockObject = (array)Mage::getSingleton('adminhtml/session')->getBlockObject(true); if(count($blockObject)) { Mage::registry('siteblocks_block')->setData($blockObject); } $this->loadLayout(); //$this->_addLeft($this->getLayout()->createBlock('siteblocks/adminhtml_siteblocks_edit_tabs')); $this->_addContent($this->getLayout()->createBlock('siteblocks/adminhtml_siteblocks_edit')); $this->renderLayout(); } protected function _uploadFile($fieldName,$model) { if( ! isset($_FILES[$fieldName])) { return false; } $file = $_FILES[$fieldName]; if(isset($file['name']) && (file_exists($file['tmp_name']))){ if($model->getId()){ unlink(Mage::getBaseDir('media').DS.$model->getData($fieldName)); } try { $path = Mage::getBaseDir('media') . DS . 'siteblocks' . DS; $uploader = new Varien_File_Uploader($file); $uploader->setAllowedExtensions(array('jpg','png','gif','jpeg')); $uploader->setAllowRenameFiles(true); $uploader->setFilesDispersion(false); $uploader->save($path, $file['name']); $model->setData($fieldName,$uploader->getUploadedFileName()); return true; } catch(Exception $e) { return false; } } } public function saveAction() { try { $id = $this->getRequest()->getParam('block_id'); /** @var IGN_Siteblocks_Model_Block $block */ $block = Mage::getModel('siteblocks/block')->load($id); /*$block ->setTitle($this->getRequest()->getParam('title')) ->setContent($this->getRequest()->getParam('content')) ->setBlockStatus($this->getRequest()->getParam('block_status')) ->save();*/ $data = $this->getRequest()->getParams(); #         $links = $this->getRequest()->getPost('links', array()); if (array_key_exists('products', $links)) { $selectedProducts = Mage::helper('adminhtml/js')->decodeGridSerializedInput($links['products']); $products = array(); foreach($selectedProducts as $product => $position) { $products[$product] = isset($position['position']) ? $position['position'] : $product; } $data['products'] = $products; } if (isset($data['rule']['conditions'])) { $data['conditions'] = $data['rule']['conditions']; } unset($data['rule']); $block ->loadPost($data); $this->_uploadFile('image',$block); $block ->setCreatedAt(Mage::app()->getLocale()->date()) ->save(); if(!$block->getId()) { Mage::getSingleton('adminhtml/session')->addError('Cannot save the block'); } } catch(Exception $e) { Mage::logException($e); Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); Mage::getSingleton('adminhtml/session')->setBlockObject($block->getData()); return $this->_redirect('*/*/edit',array('block_id'=>$this->getRequest()->getParam('block_id'))); } Mage::getSingleton('adminhtml/session')->addSuccess('Block was saved successfully!'); $this->_redirect('*/*/'.$this->getRequest()->getParam('back','index'),array('block_id'=>$block->getId())); } public function deleteAction() { $block = Mage::getModel('siteblocks/block') ->setId($this->getRequest()->getParam('block_id')) ->delete(); if($block->getId()) { Mage::getSingleton('adminhtml/session')->addSuccess('Block was deleted successfully!'); } $this->_redirect('*/*/'); } public function massStatusAction() { $statuses = $this->getRequest()->getParams(); try { $blocks= Mage::getModel('siteblocks/block') ->getCollection() ->addFieldToFilter('block_id',array('in'=>$statuses['massaction'])); foreach($blocks as $block) { $block->setBlockStatus($statuses['block_status'])->save(); } } catch(Exception $e) { Mage::logException($e); Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); return $this->_redirect('*/*/'); } Mage::getSingleton('adminhtml/session')->addSuccess('Blocks were updated!'); return $this->_redirect('*/*/'); } public function massDeleteAction() { $blocks = $this->getRequest()->getParams(); try { $blocks= Mage::getModel('siteblocks/block') ->getCollection() ->addFieldToFilter('block_id',array('in'=>$blocks['massaction'])); foreach($blocks as $block) { $block->delete(); } } catch(Exception $e) { Mage::logException($e); Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); return $this->_redirect('*/*/'); } Mage::getSingleton('adminhtml/session')->addSuccess('Blocks were deleted!'); return $this->_redirect('*/*/'); } #2     AJAX  public function productsAction() { $this->loadLayout() ->renderLayout(); } public function productsgridAction() { $this->loadLayout() ->renderLayout(); } }
      
      







コントローラーのコードから、レイアウトを更新する必要があることは明らかです。



app / design / adminhtml / default / default / layout / adminhtml.xml
 <?xml version="1.0"?> <layout version="1.0.0"> <adminhtml_siteblocks_edit> <update handle="editor"/> <reference name="head"> <action method="setCanLoadExtJs"><flag>1</flag></action> <action method="setCanLoadRulesJs"><flag>1</flag></action> </reference> <reference name="left"> <block type="siteblocks/adminhtml_siteblocks_edit_tabs" name="siteblocks_tabs"> <!-- <block name="conditions_tab" type="siteblocks/adminhtml_siteblocks_edit_tab_conditions"/> <action method="addTab"><name>my_conditions</name><block>conditions_tab</block></action>--> <!--<action method="addTab"><name>my_conditions</name><block>siteblocks/adminhtml_siteblocks_edit_tab_conditions</block></action>--> </block> </reference> </adminhtml_siteblocks_edit> <adminhtml_system_config_edit> <update handle="editor"/> </adminhtml_system_config_edit> <!--    ,     ,        --> <adminhtml_siteblocks_products> <block type="core/text_list" name="root" output="toHtml"> <block type="siteblocks/adminhtml_siteblocks_edit_tab_products_grid" name="siteblocks_products"/> <block type="adminhtml/widget_grid_serializer" name="siteblocks_products_serializer"> <reference name="siteblocks_products_serializer"> <action method="initSerializerBlock"> <grid_block_name>siteblocks_products</grid_block_name> <data_callback>getSelectedBlockProducts</data_callback> <hidden_input_name>links[products]</hidden_input_name> <reload_param_name>siteblocks_products</reload_param_name> </action> <action method="addColumnInputName"> <input_name>position</input_name> </action> </reference> </block> </block> </adminhtml_siteblocks_products> <!--       --> <adminhtml_siteblocks_productsgrid> <block type="core/text_list" name="root" output="toHtml"> <block type="siteblocks/adminhtml_siteblocks_edit_tab_products_grid" name="block_products"/> </block> </adminhtml_siteblocks_productsgrid> </layout>
      
      







適切なブロックの命名に注意してください。プロジェクトの名前を変更します。すべての場所で同期的に名前を変更します。



管理インターフェイスの最後の要素は、テーブルクラスになります。



アプリ/コード/ローカル/ IGN /サイトブロック/ブロック/ Adminhtml /サイトブロック/編集/タブ/製品/ Grid.php
 <?php class IGN_Siteblocks_Block_Adminhtml_Siteblocks_Edit_Tab_Products_Grid extends Mage_Adminhtml_Block_Widget_Grid { protected $_block; /** * Set grid params * */ public function __construct() { parent::__construct(); $this->setId('siteblocks_product_grid'); $this->setDefaultSort('entity_id'); $this->setUseAjax(true); if ($this->_getBlock()->getId()) { $this->setDefaultFilter(array('in_products'=>1)); } if ($this->isReadonly()) { $this->setFilterVisibility(false); } } protected function _getBlock() { if(!$this->_block) { $this->_block = Mage::getModel('siteblocks/block')->load($this->getRequest()->getParam('block_id')); } return $this->_block; } protected function _addColumnFilterToCollection($column) { // Set custom filter for in product flag if ($column->getId() == 'in_products') { $productIds = $this->_getSelectedProducts(); if (empty($productIds)) { $productIds = 0; } if ($column->getFilter()->getValue()) { $this->getCollection()->addFieldToFilter('entity_id', array('in'=>$productIds)); } else { if($productIds) { $this->getCollection()->addFieldToFilter('entity_id', array('nin'=>$productIds)); } } } else { parent::_addColumnFilterToCollection($column); } return $this; } /** * Checks when this block is readonly * * @return boolean */ public function isReadonly() { return $this->_getBlock()->getUpsellReadonly(); } protected function _prepareCollection() { #        $collection = Mage::getResourceModel('catalog/product_collection') ->addAttributeToSelect('*'); if ($this->isReadonly()) { $productIds = $this->_getSelectedProducts(); if (empty($productIds)) { $productIds = array(0); } $collection->addFieldToFilter('entity_id', array('in'=>$productIds)); } $this->setCollection($collection); return parent::_prepareCollection(); } /** * Add columns to grid * * @return Mage_Adminhtml_Block_Widget_Grid */ protected function _prepareColumns() { #       if (!$this->_getBlock()->getUpsellReadonly()) { $this->addColumn('in_products', array( 'header_css_class' => 'a-center', 'type' => 'checkbox', 'name' => 'in_products', 'values' => $this->_getSelectedProducts(), 'align' => 'center', 'index' => 'entity_id' )); } $this->addColumn('entity_id', array( 'header' => Mage::helper('catalog')->__('ID'), 'sortable' => true, 'width' => 60, 'index' => 'entity_id' )); $this->addColumn('name', array( 'header' => Mage::helper('catalog')->__('Name'), 'index' => 'name' )); $this->addColumn('type', array( 'header' => Mage::helper('catalog')->__('Type'), 'width' => 100, 'index' => 'type_id', 'type' => 'options', 'options' => Mage::getSingleton('catalog/product_type')->getOptionArray(), )); $sets = Mage::getResourceModel('eav/entity_attribute_set_collection') ->setEntityTypeFilter(Mage::getModel('catalog/product')->getResource()->getTypeId()) ->load() ->toOptionHash(); $this->addColumn('set_name', array( 'header' => Mage::helper('catalog')->__('Attrib. Set Name'), 'width' => 130, 'index' => 'attribute_set_id', 'type' => 'options', 'options' => $sets, )); $this->addColumn('status', array( 'header' => Mage::helper('catalog')->__('Status'), 'width' => 90, 'index' => 'status', 'type' => 'options', 'options' => Mage::getSingleton('catalog/product_status')->getOptionArray(), )); $this->addColumn('visibility', array( 'header' => Mage::helper('catalog')->__('Visibility'), 'width' => 90, 'index' => 'visibility', 'type' => 'options', 'options' => Mage::getSingleton('catalog/product_visibility')->getOptionArray(), )); $this->addColumn('sku', array( 'header' => Mage::helper('catalog')->__('SKU'), 'width' => 80, 'index' => 'sku' )); $this->addColumn('price', array( 'header' => Mage::helper('catalog')->__('Price'), 'type' => 'currency', 'currency_code' => (string) Mage::getStoreConfig(Mage_Directory_Model_Currency::XML_PATH_CURRENCY_BASE), 'index' => 'price' )); $this->addColumn('position', array( 'header' => Mage::helper('catalog')->__('Position'), 'name' => 'position', 'type' => 'number', 'width' => 60, 'validate_class' => 'validate-number', 'index' => 'position', 'editable' => true )); return parent::_prepareColumns(); } # URL       public function getGridUrl() { return $this->_getData('grid_url') ? $this->_getData('grid_url') : $this->getUrl('*/*/productsgrid', array('_current'=>true)); } protected function _getSelectedProducts() { return array_keys($this->getSelectedBlockProducts()); } public function getSelectedBlockProducts() { $selected = $this->getRequest()->getParam('siteblocks_products'); $products = array(); foreach ($this->_getBlock()->getProducts() as $product => $position) { $products[$product] = array('position' => $position); } foreach ($selected as $product) { if(!isset($products[$product])) { $products[$product] = array('position'=>$product); } } return $products; } }
      
      







製品を正常に保存するには、バージョンを更新し、新しいアップグレードスクリプトを作成して、新しい列を追加する必要があります。



app / code / local / IGN / Siteblocks / sql / siteblocks_setup / upgrade-1.0.2-1.0.3.php
 <?php /** @var Mage_Core_Model_Resource_Setup $installer */ $installer = $this; $installer->startSetup(); $installer->run(" ALTER TABLE `{$this->getTable('siteblocks/block')}` ADD `products` TEXT NOT NULL; "); $installer->endSetup();
      
      







モデルの小さな変換。



アプリ/コード/ローカル/ IGN /サイトブロック/モデル/ Block.php
 <?php /** * Class IGN_Siteblocks_Model_Block * @method getBlockStatus() * @method getContent() * @method getImage() */ class IGN_Siteblocks_Model_Block extends Mage_Rule_Model_Abstract { protected $_eventPrefix = 'siteblocks_block'; public function getActionsInstance() { return Mage::getModel('catalogrule/rule_action_collection'); } public function getConditionsInstance() { return Mage::getModel('catalogrule/rule_condition_combine'); } public function _construct() { parent::_construct(); $this->_init('siteblocks/block'); } public function getImageSrc() { return Mage::getBaseUrl('media') . 'siteblocks' . DS . $this->getImage(); } #      protected function _beforeSave() { parent::_beforeSave(); if(is_array($this->getData('products'))) { $this->setData('products',json_encode($this->getData('products'))); } } #      protected function _afterLoad() { parent::_beforeSave(); if(!empty($this->getData('products'))) { $this->setData('products',(array)json_decode($this->getData('products'))); } } # ,      public function getProducts() { if(!is_array($this->getData('products'))) { $this->setData('products',(array)json_decode($this->getData('products'))); } return $this->getData('products'); } }
      
      







商品を割り当てることができます。ここで、それらをフロントエンドで正しく表示する必要があります。これらの目的のために、アップセルからコピーし、ニーズに合わせて編集した新しいテンプレートを作成しました。



アプリ/デザイン/フロントエンド/ベース/デフォルト/テンプレート/サイトブロック/製品/ list.php
 <?php if(count($this->getLoadedProductCollection()->getItems())): ?> <div class="box-collateral box-up-sell"> <h2><?php echo $this->__('You may also like') ?></h2> <ul class="products-grid products-grid--max-4-col" id="upsell-product-table"> <?php foreach ($this->getLoadedProductCollection()->getItems() as $_link): ?> <li> <a href="<?php echo $_link->getProductUrl() ?>" title="<?php echo $this->escapeHtml($_link->getName()) ?>" class="product-image"> <img src="<?php echo $this->helper('catalog/image')->init($_link, 'small_image')->resize(280) ?>" alt="<?php echo $this->escapeHtml($_link->getName()) ?>" /> </a> <h3 class="product-name"><a href="<?php echo $_link->getProductUrl() ?>" title="<?php echo $this->escapeHtml($_link->getName()) ?>"><?php echo $this->escapeHtml($_link->getName()) ?></a></h3> <?php echo $this->getPriceHtml($_link, true, '-upsell') ?> </li> <?php endforeach; ?> </ul> </div> <?php endif ?>
      
      







list.phtmlブロック出力テンプレートも更新します。



アプリ/デザイン/フロントエンド/ベース/デフォルト/テンプレート/サイトブロック/ list.php
 <?php foreach($this->getBlocks() as $block):?> <div class="siteblock"> <div class="block-title"><?php echo $block->getTitle()?></div> <div class="block-image"> <?php if($block->getImage()):?> <img src="<?php echo $block->getImageSrc()?>" height="150" width="auto" alt="<?php $block->getTitle()?>" title="<?php $block->getTitle()?>"> <?php endif;?> </div> <div class="block-content"><?php echo $this->getBlockContent($block)?></div> <div class="block-product-list"> <?php echo $this->getProductsList($block)?> </div> </div> <?php endforeach;?>
      
      







そして、List.phpブロックに必要な変更:



アプリ/コード/ローカル/ IGN /サイトブロック/ブロック/List.php
 <?php class IGN_Siteblocks_Block_List extends Mage_Core_Block_Template { public function getBlocks() { //return Mage::getResourceModel('siteblocks/block_collection'); $items = Mage::getModel('siteblocks/block')->getCollection() ->addFieldToFilter('block_status',array('eq'=>IGN_Siteblocks_Model_Source_Status::ENABLED)); $filteredItems = $items; if(Mage::registry('current_product') instanceof Mage_Catalog_Model_Product) { $filteredItems = array(); /** @var IGN_Siteblocks_Model_Block $item */ foreach ($items as $item) { if($item->validate(Mage::registry('current_product'))) { $filteredItems[] = $item; } } } return $filteredItems; } public function getBlockContent($block) { $processor = Mage::helper('cms')->getBlockTemplateProcessor(); $html = $processor->filter($block->getContent()); return $html; } //      public function getProductsList($block) { $products = $block->getProducts(); asort($products); $collection = Mage::getResourceModel('catalog/product_collection') ->addFieldToFilter('entity_id',array('in'=>array_keys($products))) ->addAttributeToSelect('*'); /** @var Mage_Catalog_Block_Product_List $list */ $list = $this->getLayout()->createBlock('catalog/product_list'); $list->setCollection($collection); $list->setTemplate('siteblocks/product/list.phtml'); return $list->toHtml(); } }
      
      







商品用に独自のブロックを作成することもできますが、タスクには標準のブロックを使用できます。



したがって、サイトのいくつかの場所でブロックを表示できるモジュールを取得しました。製品ページのブロックの出力は、条件のチェック(ルール条件)で実行されます。便利なWYSIWYGエディターを使用してコンテンツを入力します。



また、ブロックとともに、いくつかの製品を表示できます。いくつかの変更を加えれば、実際の使用を簡単に見つけることができるモジュール。作成されたモジュールを含む公開リポジトリそして、このガイドは、独自の支払い方法と配送方法を作成するプロセスを考慮しなければ完全ではありません。







支払方法モジュールの作成



ビデオ:Magentoの支払い方法モジュールの開発




パブリックリポジトリ:bitbucket.org/dvman8bit/ign_payment



これは、秘密コードを入力して注文の支払いを行うことができる支払い方法になります。これが注文に対して支払ういくつかの詳細の入力であると想像してみましょう。テーマを開発し、本格的なフォームにすることができます。私たちの仕事は、最小限の行動を理解して、将来の本格的な支払い方法の基礎を作ることです。



支払い方法には、2つのブロック、2つのテンプレート、2つのxmlファイル、1つのモデルのファイルが含まれます。

system.xmlから始めましょう。既存の[支払い方法]タブに新しいセクションを追加します。



アプリ/コード/コミュニティ/ IGN /支払い/ etc / system.xml
 <?xml version="1.0"?> <config> <sections> <payment> <groups> <ignpayment translate="label"> <label>IGN Payment</label> <frontend_type>text</frontend_type> <sort_order>30</sort_order> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>1</show_in_store> <fields> <active translate="label"> <label>Enabled</label> <frontend_type>select</frontend_type> <source_model>adminhtml/system_config_source_yesno</source_model> <sort_order>1</sort_order> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>0</show_in_store> </active> <order_status translate="label"> <label>New Order Status</label> <frontend_type>select</frontend_type> <source_model>adminhtml/system_config_source_order_status_newprocessing</source_model> <sort_order>2</sort_order> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>0</show_in_store> </order_status> <payment_action translate="label"> <label>Automatically Invoice All Items</label> <frontend_type>select</frontend_type> <source_model>payment/source_invoice</source_model> <sort_order>3</sort_order> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>0</show_in_store> <depends> <order_status separator=",">processing,processed_ogone</order_status> </depends> </payment_action> <sort_order translate="label"> <label>Sort Order</label> <frontend_type>text</frontend_type> <sort_order>100</sort_order> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>0</show_in_store> <frontend_class>validate-number</frontend_class> </sort_order> <title translate="label"> <label>Title</label> <frontend_type>text</frontend_type> <sort_order>1</sort_order> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>1</show_in_store> </title> <allowspecific translate="label"> <label>Payment from Applicable Countries</label> <frontend_type>allowspecific</frontend_type> <sort_order>50</sort_order> <source_model>adminhtml/system_config_source_payment_allspecificcountries</source_model> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>0</show_in_store> </allowspecific> <specificcountry translate="label"> <label>Payment from Specific Countries</label> <frontend_type>multiselect</frontend_type> <sort_order>51</sort_order> <source_model>adminhtml/system_config_source_country</source_model> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>0</show_in_store> <can_be_empty>1</can_be_empty> </specificcountry> <min_order_total translate="label"> <label>Minimum Order Total</label> <frontend_type>text</frontend_type> <sort_order>98</sort_order> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>0</show_in_store> </min_order_total> <max_order_total translate="label"> <label>Maximum Order Total</label> <frontend_type>text</frontend_type> <sort_order>99</sort_order> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>0</show_in_store> </max_order_total> <secret_code translate="label"> <label>Secret Code</label> <frontend_type>text</frontend_type> <sort_order>99</sort_order> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>0</show_in_store> </secret_code> </fields> </ignpayment> </groups> </payment> </sections> </config>
      
      







system.xmlでは、ほとんどすべてのフィールドが標準です。シークレットコードを入力する新しいフィールドを1つだけ追加しました。



アプリ/コード/コミュニティ/ IGN /支払い/ etc / config.xml
 <?xml version="1.0"?> <config> <modules> <IGN_Payment> <version>1.0.0</version> </IGN_Payment> </modules> <global> <models> <ignpayment> <class>IGN_Payment_Model</class> </ignpayment> </models> <resources> <payment_setup> <setup> <module>IGN_Payment</module> </setup> </payment_setup> </resources> <blocks> <ignpayment> <class>IGN_Payment_Block</class> </ignpayment> </blocks> <helpers> <ignpayment> <class>IGN_Payment_Helper</class> </ignpayment> </helpers> </global> <frontend> <translate> <modules> <IGN_Payment> <files> <default>IGN_Payment.csv</default> </files> </IGN_Payment> </modules> </translate> </frontend> <adminhtml> <translate> <modules> <IGN_Payment> <files> <default>IGN_Payment.csv</default> </files> </IGN_Payment> </modules> </translate> </adminhtml> <default> <payment> <ignpayment> <active>1</active> <model>ignpayment/method</model> <!--      --> <order_status>pending</order_status> <title>Secret Code</title> <allowspecific>0</allowspecific> <sort_order>1</sort_order> <group>offline</group> </ignpayment> </payment> </default> </config>
      
      







それでは、最も重要な部分であるMethod.phpモデルに移りましょう。



アプリ/コード/コミュニティ/ IGN /支払い/モデル/ Method.php
 <?php class IGN_Payment_Model_Method extends Mage_Payment_Model_Method_Abstract { //     protected $_code = 'ignpayment'; // block type protected $_formBlockType = 'ignpayment/form'; protected $_infoBlockType = 'ignpayment/info'; //      ,         public function validate() { $code = Mage::app()->getRequest()->getParam('secret_code'); if($code != $this->getConfigData('secret_code')) { Mage::throwException(Mage::helper('ignpayment')->__("This code doesn't work!")); } return parent::validate(); } }
      
      







必ずMage_Payment_Model_Method_Abstractクラスから継承してくださいこのクラスの内部を見ると、デフォルト値とメソッドを備えた多数のプロパティが表示されます。プロパティとメソッドには非常にわかりやすい名前が付いているため、何かが特に重要な場合は、クラスにコピーしてニーズに対応する値を示します。



モデルはメソッド



(order()、capture()、void()、refund()など)を実装することを覚えています。そして、支払い方法が支払いサービスのサーバーと「通信」する必要がある場合、メソッドをクラスにコピーし、適切なスクリプトをそれらに追加します。



ここで、フロントエンド部分でのメソッドの結論を処理します。そして、ここで2つのクラスを作成します。Form.phpは、チェックアウトブロックに支払い方法を表示するために使用されます。



アプリ/コード/コミュニティ/ IGN /支払い/ブロック/ Form.php
 <?php /** * Payment method form base block */ class IGN_Payment_Block_Form extends Mage_Payment_Block_Form { public function _construct() { parent::_construct(); // ,    ,        $this->setTemplate('ignpayment/form.phtml'); } }
      
      







このブロックは、注文ページの情報ブロックに表示されます。



アプリ/コード/コミュニティ/ IGN /支払い/ブロック/ Info.php
 <?php class IGN_Payment_Block_Info extends Mage_Payment_Block_Info { protected function _construct() { parent::_construct(); $this->setTemplate('ignpayment/info.phtml'); } }
      
      







そして、ブロックに対応するテンプレート:



アプリ/デザイン/フロントエンド/ベース/デフォルト/テンプレート/ ignpayment / form.phtml
 <!--   id,      payment_form_,    -  --> <div id="payment_form_ignpayment" style="display: none"> <input type="text" name="secret_code" autocomplete="off"> <!--          --> </div>
      
      







info.phtmlファイルの内容は標準ですが、ニーズに合わせて変更できます。



アプリ/デザイン/フロントエンド/ベース/デフォルト/テンプレート/ ignpayment / info.phtml
 <p><strong><?php echo $this->escapeHtml($this->getMethod()->getTitle()) ?></strong></p> <?php if ($_specificInfo = $this->getSpecificInformation()):?> <table> <tbody> <?php foreach ($_specificInfo as $_label => $_value):?> <tr> <th><strong><?php echo $this->escapeHtml($_label)?>:</strong></th> </tr> <tr> <td><?php echo nl2br(implode($this->getValueAsArray($_value, true), "\n"))?></td> </tr> <?php endforeach; ?> </tbody> </table> <?php endif;?> <?php echo $this->getChildHtml()?>
      
      







これが支払い方法の基本です。さらなる編集は、特定の支払いサービスの作業に強く依存します。決済サービスが「ノック」して取引の詳細を渡すコントローラーが必要になる場合があります。また、コントローラーの作成と、ヘルパーの作成については上記で説明しましたが、ここでは省略しました。





配送方法モジュール



ビデオ:Magentoの配送方法の開発




公開リポジトリ:bitbucket.org/dvman8bit/ign_shipment



独自の配信方法を作成するために必要なアクションを見てみましょう。モジュールはBelposhtaで動作します。なぜなら私自身はベラルーシ出身で、これは私にとって非常に重要です。BelposhtaにはパブリックAPIはありません。また、キャプチャはありませんので、価格を尋ねるのは簡単です。



配信方法には、少なくとも3つのファイルが必要です。2つのxmlと1つのモデル、ヘルパーを引き続き使用します。合計4。



アプリ/コード/コミュニティ/ IGN /出荷/ etc / config.xml
 <?xml version="1.0"?> <config> <modules> <IGN_Shipment> <version>1.0.0</version> </IGN_Shipment> </modules> <global> <models> <ignshipment> <class>IGN_Shipment_Model</class> </ignshipment> </models> <helpers> <ignshipment> <class>IGN_Shipment_Helper</class> </ignshipment> </helpers> </global> <adminhtml> <translate> <modules> <IGN_Shipment> <files> <default>IGN_Shipment.csv</default> </files> </IGN_Shipment> </modules> </translate> </adminhtml> <frontend> <translate> <modules> <IGN_Shipment> <files> <default>IGN_Shipment.csv</default> </files> </IGN_Shipment> </modules> </translate> </frontend> <default> <carriers> <ignshipment> <active>1</active> <sallowspecific>0</sallowspecific> <model>ignshipment/carrier</model> <!--    --> <name>IGN Shipment</name> <price>5.00</price> <title>IGN Shipment</title> <type>I</type> <specificerrmsg>This shipping method is currently unavailable. If you would like to ship using this shipping method, please contact us.</specificerrmsg> <handling_type>F</handling_type> <packet_max_weight>2000</packet_max_weight> </ignshipment> </carriers> </default> </config>
      
      









アプリ/コード/コミュニティ/ IGN /出荷/ etc / system.xml
 <?xml version="1.0"?> <config> <sections> <carriers> <groups> <ignshipment translate="label"> <label>IGN Shipping</label> <frontend_type>text</frontend_type> <sort_order>2</sort_order> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>1</show_in_store> <fields> <active translate="label"> <label>Enabled</label> <frontend_type>select</frontend_type> <source_model>adminhtml/system_config_source_yesno</source_model> <sort_order>1</sort_order> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>0</show_in_store> </active> <name translate="label"> <label>Method Name</label> <frontend_type>text</frontend_type> <sort_order>3</sort_order> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>1</show_in_store> </name> <price translate="label"> <label>Price</label> <frontend_type>text</frontend_type> <validate>validate-number validate-zero-or-greater</validate> <sort_order>5</sort_order> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>0</show_in_store> </price> <handling_type translate="label"> <label>Calculate Handling Fee</label> <frontend_type>select</frontend_type> <source_model>shipping/source_handlingType</source_model> <sort_order>7</sort_order> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>0</show_in_store> </handling_type> <handling_fee translate="label"> <label>Handling Fee</label> <frontend_type>text</frontend_type> <validate>validate-number validate-zero-or-greater</validate> <sort_order>8</sort_order> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>0</show_in_store> </handling_fee> <sort_order translate="label"> <label>Sort Order</label> <frontend_type>text</frontend_type> <sort_order>100</sort_order> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>0</show_in_store> </sort_order> <title translate="label"> <label>Title</label> <frontend_type>text</frontend_type> <sort_order>2</sort_order> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>1</show_in_store> </title> <type translate="label"> <label>Type</label> <frontend_type>select</frontend_type> <source_model>adminhtml/system_config_source_shipping_flatrate</source_model> <sort_order>4</sort_order> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>0</show_in_store> </type> <sallowspecific translate="label"> <label>Ship to Applicable Countries</label> <frontend_type>select</frontend_type> <sort_order>90</sort_order> <frontend_class>shipping-applicable-country</frontend_class> <source_model>adminhtml/system_config_source_shipping_allspecificcountries</source_model> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>0</show_in_store> </sallowspecific> <specificcountry translate="label"> <label>Ship to Specific Countries</label> <frontend_type>multiselect</frontend_type> <sort_order>91</sort_order> <source_model>adminhtml/system_config_source_country</source_model> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>0</show_in_store> <can_be_empty>1</can_be_empty> </specificcountry> <showmethod translate="label"> <label>Show Method if Not Applicable</label> <frontend_type>select</frontend_type> <sort_order>92</sort_order> <source_model>adminhtml/system_config_source_yesno</source_model> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>0</show_in_store> </showmethod> <specificerrmsg translate="label"> <label>Displayed Error Message</label> <frontend_type>textarea</frontend_type> <sort_order>80</sort_order> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>1</show_in_store> </specificerrmsg> <packet_max_weight> <label>Packet Max Weight</label> <frontend_type>text</frontend_type> <sort_order>80</sort_order> <show_in_default>1</show_in_default> <show_in_website>1</show_in_website> <show_in_store>1</show_in_store> </packet_max_weight> </fields> </ignshipment> </groups> </carriers> </sections> </config>
      
      







これで、Carrier.phpモデルを作成できます



アプリ/コード/コミュニティ/ IGN /出荷/モデル/ Carrier.php
 <?php class IGN_Shipment_Model_Carrier extends Mage_Shipping_Model_Carrier_Abstract implements Mage_Shipping_Model_Carrier_Interface { protected $_code = 'ignshipment'; public function collectRates(Mage_Shipping_Model_Rate_Request $request) { /** @var Mage_Shipping_Model_Rate_Result $result */ $result = Mage::getModel('shipping/rate_result'); $weight = $request->getPackageWeight(); /** @var Mage_Shipping_Model_Rate_Result_Method $method */ $method = Mage::getModel('shipping/rate_result_method'); $method->setCarrier($this->_code); $method->setCarrierTitle($this->getConfigData('title')); //           if($weight > $this->getConfigData('packet_max_weight')) { $this->_getBoxMethod($weight,$method); } else { $this->_getPacketMethod($weight,$method); } $result->append($method); return $result; } protected function _getPacketMethod($weight,$method) { $method->setMethod('packet'); $method->setMethodTitle('Packet belpost'); $sum = Mage::helper('ignshipment')->getPacketCost($weight); $method->setPrice($sum/19050); } protected function _getBoxMethod($weight,$method) { $method->setMethod('box'); $method->setMethodTitle('Box belpost'); $sum = Mage::helper('ignshipment')->getBoxCost($weight); $method->setPrice($sum/19050); } //        API public function isTrackingAvailable() { return false; } public function getAllowedMethods() { //    2  .   2000 ,   return array( 'packet' => 'Packet belpost', 'box' => 'Box belpost' ); } }
      
      







Mage_Shipping_Model_Carrier_Abstractクラスからモデルを継承します。インターフェイスはオプションです。私たちのロジックは、ボックスの数をカウントする機能をまだ使用していません。これは、配送コストにも影響します。ただし、この場合、各ボックスをその重量でカウントし、コストを合計する必要があります。すべての製品が1つの共通ボックスに収まることを受け入れます。



私がヘルパーに持ってきたベルポクタとの「コミュニケーション」の論理。技術的には、HTTPリクエストを行って価格を尋ねるだけで、このコードがモデルで行うことはありません。



アプリ/コード/コミュニティ/ IGN /出荷/ヘルパー/ Data.php
 <?php class IGN_Shipment_Helper_Data extends Mage_Core_Helper_Abstract { public function getPacketCost($weight) { $request = new Zend_Http_Client(); $request->setUri('http://tarifikator.belpost.by/forms/international/packet.php'); $request->setParameterPost(array( 'who'=>'ur', 'type'=>'registered', 'priority'=>'priority', 'to'=>'other', 'weight'=>$weight )); $response = $request->request(Zend_Http_Client::POST); $html = $response->getBody(); $tag_regex = "/<blockquote>(.*)<\/blockquote>/im"; $sum_reqex = "/(\d+)/is"; preg_match_all($tag_regex, $html, $matches, PREG_PATTERN_ORDER); if(isset($matches[1]) && isset($matches[1][0])) { preg_match($sum_reqex,$matches[1][0],$matches); if(isset($matches[0])) { return (float)$matches[0]; } } //   ,       //          return Mage::getStoreConfig('carriers/ignshipment/price'); } public function getBoxCost($weight) { $request = new Zend_Http_Client(); $request->setUri('http://tarifikator.belpost.by/forms/international/ems.php'); $request->setParameterPost(array( 'who'=>'ur', 'type'=>'goods', 'to'=>'n10', //  .           , ..  Magento  US, NZ, AU,     n1,n2,n3  . 'weight'=>$weight )); $response = $request->request(Zend_Http_Client::POST); $html = $response->getBody(); $tag_regex = "/<blockquote>(.*)<\/blockquote>/im"; $sum_reqex = "/(\d+)/is"; preg_match_all($tag_regex, $html, $matches, PREG_PATTERN_ORDER); if(isset($matches[1]) && isset($matches[1][0])) { preg_match($sum_reqex,$matches[1][0],$matches); if(isset($matches[0])) { return $matches[0]; } } //   ,       //          return Mage::getStoreConfig('carriers/ignshipment/price'); } }
      
      







おそらく、私の常連に質問があります。彼らにも質問がありますが、「作品-触らない」という原則に任せましょう。



価格を「認識する」プロセスを掘り下げることはできません。これはすべて、例としてのみ提供されています。製品版では、このようなコードは機能しません。一般に、サービスの形で開発し、キャッシングを追加する価値がありますが、それでもコスト計算式を計算するのは良いことです。そうしないと、メールサーバーが使用できない場合、またはデザインを更新するときに問題が発生します。サイトのどこかでコストを計算するための式を検索するか、友好的なメールの従業員からのメールで尋ねることができます。



まとめると。配送方法は、総重量に基づいてコストを計算できます。重量は商品の標準属性から取得されます。また、管理者が各製品にそれを示すのが面倒ではなかった場合、すべてが機能します。



結論として、皆さんの成功をお祈りします。そして、おそらく多くのエラーについては、できればLANに書き込みます。



ps私は、瞬間をつかみ、私の小さなyoutubeチャンネルを宣伝するしかありませんさあ、Magentoだけでなく、そこにストリーマーがあります。そして、まもなくMagento 2の分析を取り上げます。



最高!



All Articles