joomla源代碼探析續(二十五)JRequest對象的變量獲取過程

Joomla 1.5 RC3版本的SEF存在不少問題,前段時間架站的時候曾經仔細看過這部分,昨天做apache轉向的時候,突然發現又都忘記了,再回憶一次,記錄下來。

/index.php 中$mainframe->route(); 這一函數中實現了從URI中獲取相關參數並填充到JRequest中,我們來看看這個函數的實現過程。

這個函數的代碼清單如下:

function route()
{
 // get the full request URI
 $uri = clone(JURI::getInstance());
 $router =& $this->getRouter();
 $result = $router->parse($uri);
 JRequest::set($result, 'get', false );
}

可以看到,首先克隆了一個JURI,然後$router->parse($uri),實現了uri的解析,返回的數組結果填充到了JRequest中。

先簡略看一下 JURI::getInstance() ,代碼在enviroment/uri.php中,這裏略過了。代碼大體的實際就是兼容了apache與IIS,組成完成的URL路徑,傳遞給JURI的構造器,最終生成JURI對象作爲返回結果。

接着我們來看看$result = $router->parse($uri) 實現了什麼,以下是JRouterSite的parse函數的代碼清單:

function parse(&$uri)
{
 $vars = array();
 // Get the path
 $path = $uri->getPath();
 //Remove the suffix
 if($this->_mode == JROUTER_MODE_SEF)
 {
  // Get the application
  $app =& JFactory::getApplication();
  if($app->getCfg('sef_suffix') && !(substr($path, -9) == 'index.php' || substr($path, -1) == '/'))
  {
   if($suffix = pathinfo($path, PATHINFO_EXTENSION))
   {
    $path = str_replace('.'.$suffix, ', $path);
    $vars['format'] = $suffix;
   }
  }
 }
 //Remove basepath
 $path = substr_replace($path, ', 0, strlen(JURI::base(true)));
 //Remove prefix
 $path = str_replace('index.php', ', $path);
 //Set the route
 $uri->setPath(trim($path , '/'));
 $vars += parent::parse($uri);
 return $vars;
}

這段代碼實際就是去掉了路徑中的 index.php以及在SEF開啓的狀態下的後綴,並調用父類JRouter的parse函數。

JRouter的parse函數代碼清單如下:

unction parse(&$uri)
{
 $vars = array();
 // Process the parsed variables based on custom defined rules
 $vars = $this->_processParseRules($uri);
 // Parse RAW URL
 if($this->_mode == JROUTER_MODE_RAW) {
  $vars += $this->_parseRawRoute($uri);
 }
 // Parse SEF URL
 if($this->_mode == JROUTER_MODE_SEF) {
  $vars += $vars + $this->_parseSefRoute($uri);
 }
 return  array_merge($this->getVars(), $vars);
}

我們來看看關鍵的兩個函數,因爲不會同時發生,我們只來看看 $this->_parseSefRoute($uri)函數。以下是JRouterSite的_parseSefRoute方法代碼清單:

function _parseSefRoute(&$uri)
{
 $vars   = array();
 $menu  =& JSite::getMenu(true);
 $route = $uri->getPath();
 //Handle an empty URL (special case)
 if(empty($route))
 {
  $item = $menu->getDefault();
  //Set the information in the request
  $vars = $item->query;
  //Get the itemid
  $vars['Itemid'] = $item->id;
  // Set the active menu item
  $menu->setActive($vars['Itemid']);
  return $vars;
 }
 //Get the variables from the uri
 $vars = $uri->getQuery(true);
 /*
  * Parse the application route
  */
 if(substr($route, 0, 9) == 'component')
 {
  $segments = explode('/', $route);
  $route      = str_replace('component/'.$segments[1], ', $route);
  $vars['option'] = 'com_'.$segments[1];
  $vars['Itemid'] = null;
 }
 else
 {
  //Need to reverse the array (highest sublevels first)
  $items = array_reverse($menu->getMenu());
  foreach ($items as $item)
  {
   $lenght = strlen($item->route); //get the lenght of the route
   if($lenght > 0 && strpos($route.'/', $item->route.'/') === 0 && $item->type != 'menulink')
   {
    $route   = substr($route, $lenght);
    $vars['Itemid'] = $item->id;
    $vars['option'] = $item->component;
    break;
   }
  }
 }
 // Set the active menu item
 if ( isset($vars['Itemid']) ) {
  $menu->setActive(  $vars['Itemid'] );
 }
 //Set the variables
 $this->setVars($vars);
 /*
  * Parse the component route
  */
 if(!empty($route))
 {
  $segments = explode('/', $route);
  array_shift($segments);
  // Handle component route
  $component = preg_replace('/[^A-Z0-9_\.-]/i', ', $this->_vars['option']);
  // Use the component routing handler if it exists
  $path = JPATH_BASE.DS.'components'.DS.$component.DS.'router.php';
  if (file_exists($path) && count($segments))
  {
   //decode the route segments
   $segments = $this->_decodeSegments($segments);
   require_once $path;
   $function =  substr($component, 4).'ParseRoute';
   $vars =  $function($segments);
   $this->setVars($vars);
  }
 }
 else
 {
  //Set active menu item
  if($item =& $menu->getActive()) {
   $vars = $item->query;
  }
 }
 return $vars;
}

這段代碼比較長,不詳細分析了,實際上首先做了菜單項的比較,然後接着調用$uri->getQuery(true)返回query中的所有名稱/值對,接着在合適的條件下調用相應組件下的router.php中對應路徑解析函數,比如對於content,就是com_content/router.php的ContentParseRoute函數,最終整個函數生成了包含option,view,layout等在內的散列數組並返回。

返回的數據經過merge後,返回給JRequest::set($result, 'get', false )

至此全部的參數數值就寫入到JRequest中了,注意這裏只是 'get'方式傳遞的參數,不包括post方式提交的數據。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章