最近這幾天一直在仔細研究magento,發先一個小問題,不知道算不算bug,因爲網絡上流傳的教程都是這麼教的。
首先,我是想重寫產品詳細頁,配置如下:
<Edcy_Shopping_Product>
<from><![CDATA[#^/catalog/product/#]]></from>
<to>/shopping/product/</to>
</Edcy_Shopping_Product>
控制器裏面也並沒有做什麼東西,詳細如下
public function viewAction(){
// header("Content-Type: text/xml");
// die(Mage::app()->getConfig()->getNode()->asXML());
// exit;
echo '覆蓋過的....';
parent::viewAction();
}
這樣開啓模塊的話,我們就可以訪問了。但是產品詳細頁有重寫的,所以存在兩個url訪問;如下
http://www.edcy.com/index.php/electronics/cameras/olympus-stylus-750-7-1mp-digital-camera.html
http://www.edcy.com/index.php/catalog/product/view/id/46/category/12
開啓重寫的話,一般我們也就訪問第一url。
問題就來了,第一個url對於重寫確實完全沒有反應的。它訪問的還是core裏面的catalog模塊裏的東西。
仔細看magento的初始化文件mage.php文件,找到run方法,在run方法裏調用了app/code/core/Mage/core/model/app.php文件裏的run方法。
在這個方法裏找到這一句
$this->getFrontController()->dispatch();
這裏就是獲取控制器顯示視圖的地方了。
在看看dispath方法,這個方法在app/code/core/Mage/core/controller/Varien/Front.php文件裏面。
下面是這個方法的具體代碼
public function dispatch()
{
$request = $this->getRequest();
// If pre-configured, check equality of base URL and requested URL
$this->_checkBaseUrl($request);
$request->setPathInfo()->setDispatched(false);
//這裏是去查數據庫重寫的
if (!$request->isStraight()) {
Varien_Profiler::start('mage::dispatch::db_url_rewrite');
Mage::getModel('core/url_rewrite')->rewrite();
Varien_Profiler::stop('mage::dispatch::db_url_rewrite');
}
//這裏是查找xml裏面對於模塊重寫的
Varien_Profiler::start('mage::dispatch::config_url_rewrite');
$this->rewrite();
Varien_Profiler::stop('mage::dispatch::config_url_rewrite');
Varien_Profiler::start('mage::dispatch::routers_match');
$i = 0;
//現在就比較奇怪的是重寫了後沒有執行第二個rewrite方法
while (!$request->isDispatched() && $i++<100) {
foreach ($this->_routers as $router) {
if ($router->match($this->getRequest())) {
break;
}
}
}
Varien_Profiler::stop('mage::dispatch::routers_match');
if ($i>100) {
Mage::throwException('Front controller reached 100 router match iterations');
}
// This event gives possibility to launch something before sending output (allow cookie setting)
Mage::dispatchEvent('controller_front_send_response_before', array('front'=>$this));
Varien_Profiler::start('mage::app::dispatch::send_response');
$this->getResponse()->sendResponse();
Varien_Profiler::stop('mage::app::dispatch::send_response');
Mage::dispatchEvent('controller_front_send_response_after', array('front'=>$this));
return $this;
}
我們再看看第二個rewrite方法到底是做了什麼.
public function rewrite()
{
$request = $this->getRequest();
$config = Mage::getConfig()->getNode('global/rewrite');
if (!$config) {
return;
}
//前面是判斷有無找到重寫節點
//下面循環節點preg_replace替換,然後設置pathinfo。
foreach ($config->children() as $rewrite) {
$from = (string)$rewrite->from;
$to = (string)$rewrite->to;
if (empty($from) || empty($to)) {
continue;
}
$from = $this->_processRewriteUrl($from);
$to = $this->_processRewriteUrl($to);
$pathInfo = preg_replace($from, $to, $request->getPathInfo());
if (isset($rewrite->complete)) {
$request->setPathInfo($pathInfo);
} else {
$request->rewritePathInfo($pathInfo);
}
}
}
這下原因就很明顯了,第二個url先是查找數據庫裏的重寫,找到一條catalog/product/view/id/46/category/12這樣的target_path(這裏可以去core_url_rewrite數據表裏查查看)。
同時因爲你的配置文件裏的正則表達式是寫成這樣的
#^/catalog/product/#
這樣就匹配不到要查找的重寫地址了。
改的話,我們可以把配置文件裏的重寫配置改成這樣
<Edcy_Shopping_Product>
<from><![CDATA[#^/?catalog/product/#]]></from>
<to>/shopping/product/</to>
</Edcy_Shopping_Product>
這樣就行了。我們就既可以匹配到以/開頭的同時又可以匹配到沒有/的,這裏最好就加上斜槓,因爲這樣我們纔好區分模塊。理論上是一個模塊是以/開頭,這樣更容易匹配(想如果catalog前面還有一些字母的話),也方便區分。
還有一種方法是修改第一個rewrite方法把/加上,就是core裏的url文件夾裏rewrite的model。核心代碼這裏就不建議修改了。
因爲網上的教程都是把這個congfig.xml裏重寫的配置寫成第一種,所以建議重寫模塊都寫第二種配置。