最近我一直在研究搜索引擎优化,以及如何区分使用连字符或下划线的URI,尤其是那些将连字符视为分隔符的谷歌。
无论如何,急于调整我当前的项目以满足这个标准,我发现因为Kohana使用函数名来定义页面,我收到了意外的' - '警告。
我想知道是否有任何方法可以在Kohana中使用URI,如:
http://www.mysite.com/controller/function-name
显然我可以为此设置一个routeHandler ......但是如果我要用户生成的内容,即新闻。然后,我必须从数据库中获取所有文章,生成URI,然后为每个文章进行路由。
有没有替代解决方案?
答案 0 :(得分:3)
注意:这与Laurent's answer中的方法相同,只是略微更多的OOP。 Kohana允许一个人非常容易地重载任何系统类,因此我们可以使用它来为我们节省一些打字,并允许将来更新更新。
我们可以插入Kohana中的请求流并修复URL的操作部分中的破折号。为此,我们将覆盖Request_Client_Internal系统类及其execute_request()方法。在那里我们将检查request->动作是否有破折号,如果是,我们将它们切换到下划线以允许php正确调用我们的方法。
第1步。打开 application / bootstrap.php 并添加以下行:
define('URL_WITH_DASHES_ONLY', TRUE);
如果您需要在网址中使用下划线,则可以使用此常量在某些请求中快速禁用此功能。
第2步。在以下位置创建一个新的php文件: application / classes / request / client / 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-&gt;动作中的所有破折号,因此如果url是 / something / foo-bar ,Kohana现在很乐意将它路由到我们的action_foo_bar () 方法。
同时我们使用下划线阻止所有操作,以避免重复的内容问题。
答案 1 :(得分:1)
无法直接将带连字符的字符串映射到PHP函数,因此您必须进行路由。
就用户生成的内容而言,您可以执行类似Stack Exchange的操作。每次将用户内容保存到数据库时,都会为其生成一个slug(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
)以便于阅读。
答案 2 :(得分:1)
您可以使用lambda函数执行此操作:http://forum.kohanaframework.org/discussion/comment/62581#Comment_62581
答案 3 :(得分:0)
您可以执行类似
的操作Route::set('route', '<controller>/<identifier>', array(
'identifier' => '[a-zA-Z\-]*'
))
->defaults(array(
'controller' => 'Controller',
'action' => 'show',
));
然后在Request::current()->param('identifier')
的函数中接收您的内容标识符,并手动解析以查找相关数据。
答案 4 :(得分:0)
在尝试了各种解决方案后,我发现最简单,最可靠的方法是覆盖Kohana_Request_Client_Internal::execute_request
。为此,请在“application \ classes \ kohana \ request \ client \ 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”(以避免重复内容),此方法也会抛出错误。
我知道有些开发人员不喜欢这种方法,但它的优势在于它不会重命名操作,所以如果你检查当前的操作,它将一直称为“my-action”。使用Route或lambda函数方法,该操作有时会被称为“my_action”,有时会被称为“my-action”(因为这两种方法都重命名了操作)。