深入理解Magento
作者:Alan Storm
翻譯:Hailong Zhang
第五章 – Magento資源配置
對於任何一個更新頻繁的項目來說,保持開發環境和生產環境的數據庫同步是件很頭疼的事情。Magento提供了一套系統,用版本化的資源遷移腳本來解決這個問題。
上一章,我們爲 Helloworld Blogpost 創建了一個模型。我們直接通過SQL語句“CREATE TABLE”來創建數據表。在這一章,我們將爲Helloworld模塊創建一個資源配置(Setup Resource)用於創建數據表。我們也會創建一個模塊升級腳本,用來升級已經安裝的模塊。下面是我們要做的步驟
- 在配置文件中添加資源配置
- 創建資源類文件
- 創建安裝腳本
- 創建升級腳本
- 添加資源配置
修改Helloworld模型的config.xml
- <resources>
- <!-- ... -->
- <helloworld_setup>
- <setup>
- <module>Zhlmmc_Helloworld</module>
- <class>Zhlmmc_Helloworld_Model_Setup_Mysql4_Setup</class>
- </setup>
- <connection>
- <use>core_setup</use>
- </connection>
- </helloworld_setup>
- <!-- ... -->
- </resources>
<helloworld_setup>標籤是用來唯一標識我們正在創建的資源配置。雖然不是強制要求,但是我們應該使用 “modelname_setup”來命名資源配置。<module>標籤的內容是“Packagename_Modulename”。最 後,<class>標籤的內容就是我們將要創建的資源配置類的類名。雖然對於基本的配置來說,沒有必要創建一個單獨的資源配置類,但是爲了更 好的理解資源配置是如何工作的,我們的例子還是創建一個單獨的類。File: app/code/local/Zhlmmc/Helloworld/Model/Setup/Mysql4/Setup.php
- class Zhlmmc_Helloworld_Model_Setup_Mysql4_Setup extends Mage_Core_Model_Resource_Setup {
- }
創建安裝腳本
下面我們將要創建一個安裝腳本。這個安裝腳本包含了“CREATE TABLE”等SQL語句。這個腳本將在模塊初始化的被運行。首先我們來看一下模塊的配置文件
- <modules>
- <Zhlmmc_Helloworld>
- <version>0.1.0</version>
- </Zhlmmc_Helloworld>
- </modules>
這一部分是所有config.xml都必須包含的。它包含了模塊的名稱,還有版本。我們的安裝腳本的名字將基於這個版本號,“0.1.0”。創建以下文件File: app/code/local/Zhlmmc/Helloworld/sql/helloworld_setup/mysql4-install-0.1.0.php
- echo 'Running This Upgrade: '.get_class($this)."\n <br /> \n";
- die("Exit for now");
文件路徑中的“helloworld_setup”應該和上文在config.xml中添加的<helloworld_setup>一致。文件名中的“0.1.0”就是模塊的版本號。清空Magento緩存,訪問任何URL,你應該看到以下內容
- Running This Upgrade: Zhlmmc_Helloworld_Model_Setup_Mysql4_Setup
- Exit for now
- ...
這說明我們的安裝腳本已經被運行了。我們先不放SQL腳本在這裏,先把創建一個資源配置的流程走完。移除“die()”語句,重新裝載頁面,你應該看到你的Upgrade語句在頁面的頂部,再次刷新頁面,頁面應該正常顯示了。
資源版本
Magento的資源配置系統允許你直接拷貝安裝腳本和升級腳本到服務器上,Magento會根據當前模塊的版本自動運行相應的腳本。這樣你就只需要維護一份數據庫遷移腳本。我們先來看看“core_resource”數據表
- mysql> select code,version from core_resource;
- +————————-+————+
- | code | version |
- +————————-+————+
- | adminnotification_setup | 1.0.0 |
- | admin_setup | 0.7.2 |
- | alipay_setup | 0.9.0 |
- | api_setup | 0.8.1 |
- | backup_setup | 0.7.0 |
- | bundle_setup | 0.1.11 |
- | canonicalurl_setup | 0.1.0 |
- | catalogindex_setup | 0.7.10 |
- | cataloginventory_setup | 0.7.5 |
- | catalogrule_setup | 0.7.8 |
- | catalogsearch_setup | 0.7.7 |
- | catalog_setup | 1.4.0.0.21 |
- | checkout_setup | 0.9.5 |
- | chronopay_setup | 0.1.0 |
- | cms_setup | 0.7.13 |
- | compiler_setup | 0.1.0 |
- | contacts_setup | 0.8.0 |
- | core_setup | 0.8.26 |
- | cron_setup | 0.7.1 |
- | customer_setup | 1.4.0.0.6 |
- | cybermut_setup | 0.1.0 |
- | cybersource_setup | 0.7.0 |
- | dataflow_setup | 0.7.4 |
- | directory_setup | 0.8.10 |
- | downloadable_setup | 0.1.16 |
- | eav_setup | 0.7.15 |
- | eway_setup | 0.1.0 |
- | flo2cash_setup | 0.1.1 |
- | giftmessage_setup | 0.7.2 |
- | googleanalytics_setup | 0.1.0 |
- | googlebase_setup | 0.1.1 |
- | googlecheckout_setup | 0.7.3 |
- | googleoptimizer_setup | 0.1.2 |
- | helloworld_setup | 0.1.0 |
- | ideal_setup | 0.1.0 |
- | index_setup | 1.4.0.2 |
- | log_setup | 0.7.7 |
- | moneybookers_setup | 1.2 |
- | newsletter_setup | 0.8.2 |
- | oscommerce_setup | 0.8.10 |
- | paybox_setup | 0.1.3 |
- | paygate_setup | 0.7.1 |
- | payment_setup | 0.7.0 |
- | paypaluk_setup | 0.7.0 |
- | paypal_setup | 0.7.4 |
- | poll_setup | 0.7.2 |
- | productalert_setup | 0.7.2 |
- | protx_setup | 0.1.0 |
- | rating_setup | 0.7.2 |
- | reports_setup | 0.7.10 |
- | review_setup | 0.7.6 |
- | salesrule_setup | 0.7.12 |
- | sales_setup | 0.9.56 |
- | sendfriend_setup | 0.7.4 |
- | shipping_setup | 0.7.0 |
- | sitemap_setup | 0.7.2 |
- | strikeiron_setup | 0.9.1 |
- | tag_setup | 0.7.5 |
- | tax_setup | 0.7.11 |
- | usa_setup | 0.7.1 |
- | weee_setup | 0.13 |
- | widget_setup | 1.4.0.0.0 |
- | wishlist_setup | 0.7.7 |
- +————————-+————+
- 63 rows in set (0.00 sec)
這張表包含了系統中所有安裝的模塊和模塊的版本。你可以看到我們的模塊
- | helloworld_setup | 0.1.0 |
Magento就是根據這個版本來判斷是否需要運行升級腳本的。這裏“helloworld_setup”版本“0.1.0”,而我們的安裝腳本也是 “0.1.0”,所以Magento不會再運行該腳本。如果你需要重新運行安裝腳本(在開發的時候常用到),只要刪除表中相應模塊的數據就行了。讓我們來 試試看
- DELETE from core_resource where code = 'helloworld_setup';
這次我們將通過安裝腳本來創建數據表,所以我們也要刪除之前創建的數據表
- DROP TABLE blog_posts;
添加以下代碼到我們的安裝腳本
- $installer = $this;
- $installer->startSetup();
- $installer->run("
- CREATE TABLE `{$installer->getTable('helloworld/blogpost')}` (
- `blogpost_id` int(11) NOT NULL auto_increment,
- `title` text,
- `post` text,
- `date` datetime default NULL,
- `timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP,
- PRIMARY KEY (`blogpost_id`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
- INSERT INTO `{$installer->getTable('helloworld/blogpost')}` VALUES (1,'My New Title','This is a blog post','2009-07-01 00:00:00','2009-07-02 23:12:30');
- ");
- $installer->endSetup();
清空Magento緩存,訪問任何URL,你應該發現“blog_posts”表又被建立了,擁有一條數據。
解剖配置腳本
讓我們來分析一下上面的代碼。【譯者注:作者在文中混用了“install script”,“upgrade script”和“setup script”。我在翻譯的時候儘量分清。配置腳本包含了安裝腳本和升級腳本。】先看第一行
- $installer = $this;
這個“$this”是什麼呢?每一個配置腳本都是屬於某個資源配置類(Setup Resource class),比如上面我們創建的“Zhlmmc_Helloworld_Model_Setup_Mysql4_Setup”。這些腳本都是在這個資源 配置類的上下文環境中運行的。所以“$this”就是指資源配置類的實例。雖然不是強制的,但是大多數核心模塊的資源配置類都用“$installer” 來代替“$this”,就和我們這裏做的一樣。雖然我們說不是強制的,但是我們最好還是遵守這個約定,除非你有一個很好的理由。
接下來看下面兩個調用
- $installer->startSetup();
- //…
- $installer->endSetup();
如果你打開“Mage_Core_Model_Resource_Setup”類(也就是我們創建的資源配置類的父類)的源碼,你將會看到這兩個方法做了一些SQL準備工作
- public function startSetup()
- {
- $this->_conn->multi_query("SET SQL_MODE='';
- SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
- SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO';
- ");
- return $this;
- }
- public function endSetup()
- {
- $this->_conn->multi_query("
- SET SQL_MODE=IFNULL(@OLD_SQL_MODE,'');
- SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS,0);
- ");
- return $this;
- }
真正的配置邏輯是在“run”方法中
- $installer->run(…);
這個方法的參數就是你要運行的SQL。你可以包含任意數量的SQL,用分號隔開。你可能注意到了以下語句
- $installer->getTable('helloworld/blogpost')
【譯者注:你的第一反應是什麼?是不是聯想到config.xml裏面下面這段代碼?
- <helloworld_mysql4>
- <class>Zhlmmc_Helloworld_Model_Resource_Mysql4</class>
- <entities>
- <blogpost>
- <table>blog_posts</table>
- </blogpost>
- </entities>
- </helloworld_mysql4>
這裏“helloworld/blogpost”就是我們要創建的數據表的URI。Magento先用“helloworld”找到模塊,得到資源模塊 “helloworld_mysql4”,然後在資源模塊下面通過“blogpost”找到類名“blog_posts”。】很顯然,你可以用常量 “blog_posts”來代替調用“getTable”,但是調用這個方法可以保證即使用戶更改了配置文件中的數據表名字,你的配置腳本依然能運行。 “Mage_Core_Model_Resource_Setup”類有很多類似這樣的幫助函數。學習這些函數最好的方法就是閱讀Magento核心模塊 的資源配置類代碼。
模塊升級腳本
上面我們說過配置腳本包括安裝腳本和升級腳本。講完了安裝腳本,我們來講升級腳本。安裝腳本是在第一次安裝模塊的時候使用的,而升級腳本顧名思義就是在升級模塊的時候使用。Magento的資源配置系統使用了版本化的方式來升級模塊。
首先要說明的是,在安裝模塊的時候Magento會執行一次安裝腳本,然後Magento再也不會爲該模塊執行任何安裝腳本了。如果你要更新模塊的數據表就要通過升級腳本來執行。除了命名方式以外,升級腳本和安裝腳本並沒有太大的不同。
創建升級腳本如下
File: app/code/local/Zhlmmc/Helloworld/sql/helloworld_setup/mysql4-upgrade-0.1.0-0.2.0.php
- echo 'Testing our upgrade script (mysql4-upgrade-0.1.0-0.2.0.php) and halting execution to avoid updating the system version number <br />';
- die();
升級腳本和安裝腳本是放在相同目錄下面的,但是命名方式不同。首先是“upgrade”關鍵詞。其次,你會發現這裏我們有兩個版本號,用“-”分開。第一 個版本號“0.1.0”是指從哪個版本升級(起始版本),第二個版本號“0.2.0”是指要升級到哪個版本(目標版本)。
清空Magento緩存,請求任何一個URL,你會發現沒有任何配置腳本被運行。那是因爲,第一,我們已經運行過安裝腳本,第二,目前我們模塊的版本是 “0.1.0”,所以Magento不會運行我們要升級到“0.2.0”的升級腳本。要讓Magento運行這個升級腳本,我們得修改配置文件中的版本號
- <modules>
- <Zhlmmc_Helloworld>
- <version>0.2.0</version>
- </Zhlmmc_Helloworld>
- </modules>
清空Magento緩存,重新請求頁面,你會看到升級腳本的輸出。【譯者注:作者在這裏引入了第二個升級到“0.1.5”的升級腳本,我覺得並沒有必要,我來直接總結一下Magento升級的步驟
- 從數據表“core_resource”中獲得當前模塊的安裝版本
- 從配置文件中獲得當前模塊的版本
- 如果兩個版本一樣,那麼什麼都不做
- 如果#2的版本號小於#1的版本號,我也不知道Magento會幹什麼,理論上是不可能出現的情況
- 如果#2的版本號大於#1的版本號,那麼開始升級程序
- 在配置腳本文件夾內(在上面的例子中是“helloworld_setup”)把所有升級腳本加入隊列
- 在隊列內,按照升級腳本的起始版本排序,升序
- 循環隊列
- 如果隊列中當前腳本的起始版本不等於“core_resource”數據表中當前模塊的版本號,那麼跳過該腳本
- 如果隊列中當前腳本的起始版本等於“core_resource”數據表中當前模塊的版本號並且目標版本小於等於#2的版本號,那麼執行該腳本。
- 循環隊列結束,升級結束
值得注意的是第10步,每次執行一個升級腳本,“core_resource”數據表中的版本號都會被更新。所以如果我們有兩個升級文件“0.1.0-0.1.5”和“0.1.0-0.2.0”,只有一個升級文件會被執行。
下面我們來爲升級腳本添加實質內容
- $installer = $this;
- $installer->startSetup();
- $installer->run("
- ALTER TABLE `{$installer->getTable('helloworld/blogpost')}`
- CHANGE post post text not null;
- ");
- $installer->endSetup();
清空Magento緩存,刷新頁面,你應該看到升級腳本的輸出。如果沒有,請你對照上面講的Magento升級的步驟查找錯誤。
總結
這一章我們講解了Magento是如何處理模塊數據表的安裝和升級的。Magento的資源配置系統使用版本化的升級腳本,這樣就保證了不同版本的 模塊可以使用同一套的升級腳本,便於維護。我們後面的章節也會提到這種升級方式的優點,特別是對於使用EAV模型的模塊來說,這個優點更爲明顯。