2011-09-13 28 views
3

最近,我一直在對SEO進行一些研究,以及如何處理使用連字符或下劃線的URI,特別是通過將連字符視爲分隔符的Google。Kohana 3.2。 - 如何在URI中使用連字符

無論如何,急於適應我目前的項目,以符合這個標準,我發現,因爲Kohana使用函數名來定義頁面,我收到了意想不到的' - '警告。

我想知道是否有什麼辦法可以使使用URI中的Kohana喜歡:

http://www.mysite.com/controller/function-name 

顯然,我可以設置一個routeHandler這個......但如果我是讓用戶產生的內容,即新聞。然後,我必須從數據庫中獲取所有文章,生成URI,然後爲每個文章進行路由。

有沒有其他解決方案?

回答

3

注意:這與Laurent's answer中的方法相同,只是稍微多一點OOP。 Kohana允許一個人很容易地重載任何系統類,所以我們可以使用它來爲我們節省一些打字的時間,並且允許將來進行更清晰的更新。

我們可以插入到Kohana的請求流中,並修復網址操作部分的破折號。要做到這一點,我們將覆蓋Request_Client_Internal系統類和它的execute_request()方法。在那裏,我們將檢查request-> action是否有破折號,如果是的話,我們會將它們切換爲下劃線,以允許php正確調用我們的方法。

第1步:打開您的應用程序/ bootstrap.php中和加入這一行:

define('URL_WITH_DASHES_ONLY', TRUE); 

您使用此常量快速禁止對一些要求這個功能,如果你需要強調的網址。

第2步:創建一個新的PHP文件:應用程序/班/請求/客戶機/ internal.php並粘貼此代碼:

<?php defined('SYSPATH') or die('No direct script access.'); 

class Request_Client_Internal extends Kohana_Request_Client_Internal { 

    /** 
    * We override this method to allow for dashes in the action part of the url 
    * (See Kohana_Request_Client_Internal::execute_request() for the details) 
    * 
    * @param Request $request 
    * @return Response 
    */ 
    public function execute_request(Request $request) 
    { 
     // Check the setting for dashes (the one set in bootstrap.php) 
     if (defined('URL_WITH_DASHES_ONLY') and URL_WITH_DASHES_ONLY == TRUE) 
     { 
      // Block URLs with underscore in the action to avoid duplicated content 
      if (strpos($request->action(), '_') !== false) 
      { 
       throw new HTTP_Exception_404('The requested URL :uri was not found on this server.', array(':uri' => $request->uri())); 
      } 

      // Modify action part of the request: transform all dashes to underscores 
      $request->action(strtr($request->action(), '-', '_')); 
     } 
     // We are done, let the parent method do the heavy lifting 
     return parent::execute_request($request); 
    } 

} // end_class Request_Client_Internal 

這樣做是簡單地更換所有的破折號在帶有下劃線的$ request->動作中,因此如果url是/something/foo-bar,Kohana會很樂意將它路由到我們的action_foo_bar()方法。

與此同時,我們使用下劃線來阻止所有操作,以避免重複的內容問題。

+0

請注意,這隻適用於行動,而不是控制器。 '非官方Kohana 3.0 Wiki'有一個類似的解決方案,簡單地擴展Konaha_Request(http://kerkness.ca/kowiki/doku.php?id=routing:using_hyphen_in_urls),它既適用於操作也適用於控制器,但不涉及重複的內容。 – ChrisV

1

沒有辦法直接將連字符串映射到PHP函數,所以你將不得不做路由。

就用戶生成的內容而言,你可以像Stack Exchange那樣做。每次將用戶內容保存到數據庫時,都會爲其生成一個段落(kohana-3-2-how-can-i-use-hyphens-in-uris)並將其與其他信息一起保存。然後,當你需要鏈接到它時,使用唯一的id並將slug附加到末尾(例如:http://stackoverflow.com/questions/7404646/kohana-3-2-how-can-i-use-hyphens-in-uris)以提高可讀性。

+0

好的,例如,它只是我創建的函數,即合法頁面mysite.com/legal/terms-and-conditions。我不得不爲任何我喜歡的東西製作個人路線? – diggersworld

+0

對於任何不適合「//」結構的東西,是的。所以在你的例子中,如果你想要連字符的URL部分,你將不得不。 – Brandon

+0

難道我不能創建具有下劃線的動作函數...然後只需使用字符串替換來將連字符更改爲下劃線? – diggersworld

0

你可以做類似

Route::set('route', '<controller>/<identifier>', array(
    'identifier' => '[a-zA-Z\-]*' 
)) 
->defaults(array(
    'controller' => 'Controller', 
    'action'  => 'show', 
)); 

然後收到您的內容標識符的功能與Request::current()->param('identifier')和手動解析它找到相關數據。

0

有嘗試過各種解決方案之後,我發現,最簡單,最可靠的方法是重寫Kohana_Request_Client_Internal::execute_request。要做到這一點,在「應用程序\類\ Kohana的\請求\客戶端\ internal.php」添加文件在您application文件夾,然後設置其內容:

<?php defined('SYSPATH') or die('No direct script access.'); 
class Kohana_Request_Client_Internal extends Request_Client { 

    /** 
    * @var array 
    */ 
    protected $_previous_environment; 

    /** 
    * Processes the request, executing the controller action that handles this 
    * request, determined by the [Route]. 
    * 
    * 1. Before the controller action is called, the [Controller::before] method 
    * will be called. 
    * 2. Next the controller action will be called. 
    * 3. After the controller action is called, the [Controller::after] method 
    * will be called. 
    * 
    * By default, the output from the controller is captured and returned, and 
    * no headers are sent. 
    * 
    *  $request->execute(); 
    * 
    * @param Request $request 
    * @return Response 
    * @throws Kohana_Exception 
    * @uses [Kohana::$profiling] 
    * @uses [Profiler] 
    * @deprecated passing $params to controller methods deprecated since version 3.1 
    *    will be removed in 3.2 
    */ 
    public function execute_request(Request $request) 
    { 
     // Create the class prefix 
     $prefix = 'controller_'; 

     // Directory 
     $directory = $request->directory(); 

     // Controller 
     $controller = $request->controller(); 

     if ($directory) 
     { 
      // Add the directory name to the class prefix 
      $prefix .= str_replace(array('\\', '/'), '_', trim($directory, '/')).'_'; 
     } 

     if (Kohana::$profiling) 
     { 
      // Set the benchmark name 
      $benchmark = '"'.$request->uri().'"'; 

      if ($request !== Request::$initial AND Request::$current) 
      { 
       // Add the parent request uri 
       $benchmark .= ' « "'.Request::$current->uri().'"'; 
      } 

      // Start benchmarking 
      $benchmark = Profiler::start('Requests', $benchmark); 
     } 

     // Store the currently active request 
     $previous = Request::$current; 

     // Change the current request to this request 
     Request::$current = $request; 

     // Is this the initial request 
     $initial_request = ($request === Request::$initial); 

     try 
     { 
      if (! class_exists($prefix.$controller)) 
      { 
       throw new HTTP_Exception_404('The requested URL :uri was not found on this server.', 
                array(':uri' => $request->uri())); 
      } 

      // Load the controller using reflection 
      $class = new ReflectionClass($prefix.$controller); 

      if ($class->isAbstract()) 
      { 
       throw new Kohana_Exception('Cannot create instances of abstract :controller', 
        array(':controller' => $prefix.$controller)); 
      } 

      // Create a new instance of the controller 
      $controller = $class->newInstance($request, $request->response() ? $request->response() : $request->create_response()); 

      $class->getMethod('before')->invoke($controller); 

      // Determine the action to use 
      /* ADDED */ if (strpos($request->action(), '_') !== false) throw new HTTP_Exception_404('The requested URL :uri was not found on this server.', array(':uri' => $request->uri())); 
      /* MODIFIED */ $action = str_replace('-', '_', $request->action()); /* ORIGINAL: $action = $request->action(); */ 

      $params = $request->param(); 

      // If the action doesn't exist, it's a 404 
      if (! $class->hasMethod('action_'.$action)) 
      { 
       throw new HTTP_Exception_404('The requested URL :uri was not found on this server.', 
                array(':uri' => $request->uri())); 
      } 

      $method = $class->getMethod('action_'.$action); 

      $method->invoke($controller); 

      // Execute the "after action" method 
      $class->getMethod('after')->invoke($controller); 
     } 
     catch (Exception $e) 
     { 
      // Restore the previous request 
      if ($previous instanceof Request) 
      { 
       Request::$current = $previous; 
      } 

      if (isset($benchmark)) 
      { 
       // Delete the benchmark, it is invalid 
       Profiler::delete($benchmark); 
      } 

      // Re-throw the exception 
      throw $e; 
     } 

     // Restore the previous request 
     Request::$current = $previous; 

     if (isset($benchmark)) 
     { 
      // Stop the benchmark 
      Profiler::stop($benchmark); 
     } 

     // Return the response 
     return $request->response(); 
    } 
} // End Kohana_Request_Client_Internal 

然後加連字符的動作,例如,「controller/my-action」,創建一個名爲「my_action()」的動作。

如果用戶嘗試訪問「controller/my_action」(以避免重複的內容),此方法也會引發錯誤。

我知道一些開發人員不喜歡這種方法,但其優點是它不會重命名操作,所以如果您檢查當前操作,它會在任何地方始終稱爲「我的操作」。使用Route或lambda函數方法,動作有時稱爲「my_action」,有時稱爲「my-action」(因爲兩種方法都重命名動作)。