背景是往一个第三方的搜索插件里面加入filter功能。
首先是路径,插件自己定义了一个router,类似于cms。那首先说说router好了,从入口一路追查的话,会发现最后进入的是Mage_Core_Controller_Varien_Front类下面的dispatch()函数。
1 public function dispatch() 2 { 3 $request = $this->getRequest(); 4 5 // If pre-configured, check equality of base URL and requested URL 6 $this->_checkBaseUrl($request); 7 8 $request->setPathInfo()->setDispatched(false); 9 10 $this->_getRequestRewriteController()->rewrite(); 11 12 Varien_Profiler::start('mage::dispatch::routers_match'); 13 $i = 0; 14 while (!$request->isDispatched() && $i++ < 100) { 15 foreach ($this->_routers as $router) { 16 /** @var $router Mage_Core_Controller_Varien_Router_Abstract */ 17 if ($router->match($request)) { 18 break; 19 } 20 } 21 } 22 Varien_Profiler::stop('mage::dispatch::routers_match'); 23 if ($i>100) { 24 Mage::throwException('Front controller reached 100 router match iterations'); 25 } 26 // This event gives possibility to launch something before sending output (allow cookie setting) 27 Mage::dispatchEvent('controller_front_send_response_before', array('front'=>$this)); 28 Varien_Profiler::start('mage::app::dispatch::send_response'); 29 $this->getResponse()->sendResponse(); 30 Varien_Profiler::stop('mage::app::dispatch::send_response'); 31 Mage::dispatchEvent('controller_front_send_response_after', array('front'=>$this)); 32 return $this; 33 }
前面的代码是把url链接里的各项参数放到request类里面,方便后面调用,从第14行开始,magento会把所有继承自Mage_Core_Controller_Varien_Router_Abstract类的函数拉出来一个个循环match函数,直到找到一个匹配request的。
也就是说假如我想自定义路径,就可以继承Mage_Core_Controller_Varien_Router_Abstract类,然后在match函数里写上自己的路由规则,一旦匹配就跳转到自己想他去的controller类。
不过很显然插件自定义的router并不能很好的完成filter的工作,首先贴上,插件的原来的代码:
1 public function match(Zend_Controller_Request_Http $request) 2 { 3 $identifier = trim($request->getPathInfo(), '/'); 4 5 $condition = new Varien_Object(array( 6 'identifier' => $identifier, 7 'continue' => true, 8 )); 9 10 $identifier = $condition->getIdentifier(); 11 12 if ($condition->getRedirectUrl()) { 13 Mage::app()->getFrontController()->getResponse() 14 ->setRedirect($condition->getRedirectUrl()) 15 ->sendResponse(); 16 $request->setDispatched(true); 17 18 return true; 19 } 20 21 if (!$condition->getContinue()) { 22 return false; 23 } 24 25 $page = Mage::getModel('searchlandingpage/page')->checkIdentifier($identifier); 26 //代码原理很简单,对url里的路径拆解,然后查询这个路径是否在自定义的表里面,checkIdentifier()就是sql查询。 27 if (!$page) { 28 return false; 29 } 30 31 $request->setModuleName('searchlandingpage') 32 ->setControllerName('page') 33 ->setActionName('view') 34 ->setParam('q', $page->getQueryText()) 35 ->setParam('id', $page->getId()); 36 //若查询到了就设置request里的各项参数,告诉magento跳转到这里去 37 $request->setAlias( 38 Mage_Core_Model_Url_Rewrite::REWRITE_REQUEST_PATH_ALIAS, 39 $identifier 40 ); 41 42 return true; 43 }
修改后:
1 public function match(Zend_Controller_Request_Http $request) 2 { 3 $helper = Mage::helper('ajaxpriceslider'); 4 $suffix = Mage::getStoreConfig('catalog/seo/category_url_suffix'); 5 $identifier = ltrim($request->getPathInfo(), '/'); 6 $identifier = substr($identifier, 0, strlen($identifier) - strlen($suffix)); 7 $urlSplit = explode($helper->getRoutingSuffix(), $identifier, 2); 8 9 if(isset($urlSplit[0])){ 10 $cat = $urlSplit[0]; 11 }else{ 12 $cat = $identifier; 13 } 14 //这里主要作用是给自定义的路径添加magento的后缀, 如 xxx.html 之类 15 16 $condition = new Varien_Object(array( 17 'identifier' => $cat, 18 'continue' => true, 19 )); 20 21 $cat = $condition->getIdentifier(); 22 23 if ($condition->getRedirectUrl()) { 24 Mage::app()->getFrontController()->getResponse() 25 ->setRedirect($condition->getRedirectUrl()) 26 ->sendResponse(); 27 $request->setDispatched(true); 28 29 return true; 30 } 31 32 if (!$condition->getContinue()) { 33 return false; 34 } 35 36 $page = Mage::getModel('searchlandingpage/page')->checkIdentifier($cat); 37 38 if (!$page) { 39 return false; 40 } 41 42 $request->setModuleName('searchlandingpage') 43 ->setControllerName('page') 44 ->setActionName('view') 45 ->setParam('q', $page->getQueryText()) 46 ->setParam('id', $page->getId()); 47 48 $request->setAlias( 49 Mage_Core_Model_Url_Rewrite::REWRITE_REQUEST_PATH_ALIAS, 50 $cat.$suffix 51 ); 52 // 解析url参数,例如xxx.com/search/chiken_run/shopby/color/brown,green,white-and-green.html的网址,shopby后面的参数会被解析成array('color'=>'brown,green,white-and-green') 53 $params = explode('/', trim($urlSplit[1], '/')); 54 $layerParams = array(); 55 $total = count($params); 56 for ($i = 0; $i < $total - 1; $i++) { 57 if (isset($params[$i + 1])) { 58 $layerParams[$params[$i]] = urldecode($params[$i + 1]); 59 ++$i; 60 } 61 } 62 63 65 $layerParams += $request->getPost(); 67 $request->setParams($layerParams); 68 69 // 这个生成链接用 70 Mage::register('layer_params', $layerParams); 71 $controllerClassName = $this->_validateControllerClassName('Mirasvit_SearchLandingPage', 'page'); 72 73 $controllerInstance = Mage::getControllerInstance($controllerClassName, $request, $this->getFront()->getResponse()); 74 // 这个是立即执行自己定义的controller类的view函数,不这样做的话,magento会继续加载两个系统router 然后修改了$params,导致我删选数据出问题 75 $request->setDispatched(true); 76 $controllerInstance->dispatch('view'); 77 78 return true; 79 }
以上路径修改完了,在点击删选的时候 ajax寻址就能寻到了,但是返回的数据还是有问题的,这时候就需要修改 刚刚定义的controller下面的view函数了。
其实修改就一步,将$this->renderLayout();修改成
if ($this->getRequest()->isAjax()) { $listing = $this->getLayout()->getBlock('search_result_list')->toHtml();//根据页面的layout不同,这里的getBlock也会不同,下面也是 $layer = $this->getLayout()->getBlock('catalogsearch.leftnav')->toHtml(); // Fix urls that contain '___SID=U' $urlModel = Mage::getSingleton('core/url'); $listing = $urlModel->sessionUrlVar($listing); $layer = $urlModel->sessionUrlVar($layer); $response = array( 'listing' => $listing, 'layer' => $layer ); $this->getResponse()->setHeader('Content-Type', 'application/json', true); $this->getResponse()->setBody(json_encode($response)); } else { $this->renderLayout(); }
到这一步删选功能正常了,至于他是如何工作的,我有空补上