我正在使用CakePHP 2.4
我有一个网址,例如/sent?note=123&test=abc
我想删除 note
参数,同时将 url 的其余部分给我。
/sent?test=abc
我有一段代码可以工作,但仅适用于查询参数。我想了解如何改进我的代码,使其适用于:
- 命名参数
- 传递的参数
- 主题标签
例如
/sent/name1:value1?note=123&test=abc#top
这是我到目前为止编写的代码。 https://github.com/simkimsia/UtilityComponents/blob/master/Controller/Component/RequestExtrasHandlerComponent.php#L79
更新第三部分:
让我用更多的例子来说明我所说的更通用的答案是什么意思。
更通用的答案应该假设没有关于 url 模式的先验知识。
假设给定此网址
/sent/name1:value1?note=123&test=abc
我只想摆脱查询参数note
并返回
/sent/name1:value1?test=abc
更通用的解决方案应该可以把这个 url 还给我。
另一个例子。这次去掉命名参数。
假设再次给定此网址
/sent/name1:value1?note=123&test=abc
我想摆脱name1
并回来:
/sent?note=123&test=abc
同样,更通用的解决方案也应该能够实现这一点。
更新第二部分:
我正在寻找一个更通用的答案。假设 Web 应用不知道 url 称为已发送。您也不知道查询参数是否包含单词注释或测试。我如何仍能完成上述任务?
我希望能够对任何操作使用相同的代码。这样,我可以将其打包到组件中以便轻松重用。
更新第一部分:
我知道标签不会传递给 PHP。所以请忽略它。
有关如何从主题标签中获取值的线索:
- https://stackoverflow.com/a/7817134/80353
- https://stackoverflow.com/a/940996/80353
使用 mod_rewrite 怎么样?
您可以通过其他方式处理您的网址:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule ^/sent/name:(.*)?note=(.*)&test=([az-AZ])(#(.*))$ /sent/name:$1/note:$2/test:$3$4
</IfModule>
我不确定正则表达式,但这可能会以干净的方式将变量传递给 cakePHP(但我还没有测试过它(
[编辑]
但是如果你想在不知道 urls 模式的情况下工作,那么你可以使用 $this->request
数组 : 与类似 URL
action/id:10/test:sample?sothertest=othersample&lorem=ipsum
我可以在我的控制器中使用它获取所有参数:
// In your controller's method
$arguments= array_merge_recursive($this->request->named,$this->request->query);
然后,$arguments
将是一个包含命名和传递参数的数组:
array(
'id' => '10',
'test' => 'sample',
'sothertest' => 'othersample',
'lorem' => 'ipsum'
)
好点了吗?
[编辑2]如果您知道必须删除哪个参数,并直接重定向到新URL,这应该可以工作:
action/id:10/test:sample?knownParam=value&lorem=ipsum
或与
action/id:10/knownParam:value?othertest=othersample&lorem=ipsum
在控制器/应用控制器操作中:
// Name of the known param
$knownParam = 'knownParam';
// Arguments
$arguments = array_merge_recursive($this->request->named, $this->request->query);
if (key_exists($knownParam, $arguments)) {
// Unset in named params:
unset($arguments[$knownParam]);
// Creating url:
$url = array(
'admin' => $this->request->params['prefix'],
'plugin' => $this->request->params['plugin'],
'controller' => $this->request->params['controller'],
'action' => $this->request->params['action']
);
// Adding args
foreach ($arguments as $k => $v) {
$url[$k] = $v;
}
// Redirect
$this->redirect($url);
}
这会将两个网址重定向到
action/id:10/param1:value1/param2:value2
没有"知道参数"...
假设您创建了以下路由:
Router::connect('/projects/:id/quotations/:quotation_id/*',
array(
'controller' => 'quotations',
'action' => 'get_all_by_project', "[method]" => "GET"),
array(
'pass' => array('id', 'quotation_id'),
'id' => '[0-9]+',
'quotation_id' => '[0-9]+'
),
array(
'named' => array(
'name1',
'name2',
'name3'
)
)
);
在这条路线上:
- 传递的参数将是强制参数,
id
和服从顺序的quotation_id
作为第一个和第二个传递的参数 - 命名参数将是可选参数
name1
、name2
和name3
。 - 当然,查询参数也是可选的,具体取决于 url 中的实际内容。
- 您需要在末尾使用星号,以便命名参数可以通过
让我们假设以下漂亮的网址和同一动作的丑陋网址:
/projects/1/quotations/23/name2:value2/name3:value3/name1:value1?note=abc&test=123 (pretty)
/quotations/get_all_by_project/1/23/name2:value2/name3:value3/name1:value1?note=abc&test=123 (ugly)
答案的第一部分:让我们只考虑删除查询参数note
的场景。
我们应该回来了
/projects/1/quotations/23/name2:value2/name3:value3/name1:value1?test=123 (pretty)
/quotations/get_all_by_project/1/23/name2:value2/name3:value3/name1:value1?test=123 (ugly)
以下组件方法将起作用。我已经在丑陋和漂亮的网址上测试了它。
public function removeQueryParameters($parameters, $here = '') {
if (empty($here)) {
$here = $this->controller->request->here;
}
$query = $this->controller->request->query;
$validQueryParameters = array();
foreach($query as $param=>$value) {
if (!in_array($param, $parameters)) {
$validQueryParameters[$param] = $value;
}
}
$queryString = $this->_reconstructQueryString($validQueryParameters);
return $here . $queryString;
}
protected function _reconstructQueryString($queryParameters = array()) {
$queryString = '';
foreach($queryParameters as $param => $value) {
$queryString .= $param . '=' . $value . '&';
}
if (strlen($queryString) > 0) {
$queryString = substr($queryString, 0, strlen($queryString) - 1);
$queryString = '?' . $queryString;
}
return $queryString;
}
这就是调用组件方法的方式。
$newUrl = $this->RequestExtrasHandler->removeQueryParameters(array('note'));
RequestExtrasHandler
是我编写的具有上述方法的组件的名称。
答案的第二部分:让我们只考虑删除命名参数 name2
的场景。
我们应该回来了
/projects/1/quotations/23/name3:value3/name1:value1?test=123 (pretty)
/quotations/get_all_by_project/1/23/name3:value3/name1:value1?test=123 (ugly)
以下组件方法将起作用。我已经在丑陋和漂亮的网址上测试了它。
public function removeNamedParameters($parameters, $here = '') {
if (empty($here)) {
$here = $this->controller->request->here;
}
$query = $this->controller->request->query;
$named = $this->controller->request->params['named'];
$newHere = $here;
foreach($named as $param=>$value) {
if (in_array($param, $parameters)) {
$namedString = $param . ':' . $value;
$newHere = str_replace($namedString, "", $newHere);
}
}
$queryString = $this->_reconstructQueryString($query);
return $newHere . $queryString;
}
这就是调用组件方法的方式。
$newUrl = $this->RequestExtrasHandler->removeNamedParameters(array('name2'));
RequestExtrasHandler
是我编写的具有上述方法的组件的名称。
答案的第三部分:在我意识到传递的参数是强制性的之后,我发现根本没有真正的业务需要删除传递的参数。
另一个问题是,与命名参数和查询参数不同,传递的参数往往没有键存在于$this->controller->request->params['pass']
$this->controller->request->params['pass']
通常采用数字索引数组的形式。
因此,取出正确的传递参数存在巨大的挑战。
因此,我不会创建任何方法来删除传递的参数。
在此处查看代码的详细信息:
https://github.com/simkimsia/UtilityComponents/blob/d044da690c7b83c72a50ab97bfa1843c14355507/Controller/Component/RequestExtrasHandlerComponent.php#L89
也许简单的php函数可以做你想做的事
$url = '/sent?note=123&test=abc'; //for example
$unwanted_string = substr($url, 0,strrpos($url,'&') + 1);
$unwanted_string = str_replace('/sent?', '', $unwanted_string);
$url = str_replace($unwanted_string, '', $url);