我正在尝试为N级深度编写路线。所以通常的类别URL看起来像这样:
http://website/my-category/my-subcategory/my-subcategory-level3/my-subcategory-level4
它有一个未知的深度,我的路线必须匹配所有可能的水平。我为此做了一条路线,但我无法从控制器那里得到所有的参数。
$routeCategory = new Zend_Controller_Router_Route_Regex(
'(([a-z0-9-]+)/?){1,}',
array(
'module' => 'default',
'controller' => 'index',
'action' => 'index'
),
array( 1 => 'path'),
'%s'
);
$router->addRoute('category', $routeCategory);
我似乎找不到将路由匹配的params发送到控制器的方法。如果您有更好的解决方案,我愿意接受建议!
答案 0 :(得分:4)
我找到了一个符合我需求的解决方案。我会在这里发布给那些最终会遇到同样事情的人。
问题:
category/subcategory/subsubcategory/...
category/subcategory/../page.html
admin
)<强>解决方案:强>
Zend_Controller_Router_Route_Regex
作为起点,以便我可以从assemble()
方法中受益)实际代码:
<?php
class App_Controller_Router_Route_Category extends Zend_Controller_Router_Route_Regex
{
public function match($path, $partial = false)
{
if (!$partial) {
$path = trim(urldecode($path), '/');
}
$values = explode('/', $path);
$res = (count($values) > 0) ? 1 : 0;
if ($res === 0) {
return false;
}
/**
* Check if first param is an actual module
* If it's a module, let the default routing take place
*/
$modules = array();
$frontController = Zend_Controller_Front::getInstance();
foreach ($frontController->getControllerDirectory() as $module => $path) {
array_push($modules, $module);
}
if(in_array($values[0], $modules)) {
return false;
}
if ($partial) {
$this->setMatchedPath($values[0]);
}
$myValues = array();
$myValues['cmsCategory'] = array();
// array_filter_key()? Why isn't this in a standard PHP function set yet? :)
foreach ($values as $i => $value) {
if (!is_int($i)) {
unset($values[$i]);
} else {
if(preg_match('/.html/', $value)) {
$myValues['cmsObject'] = $value;
} else {
array_push($myValues['cmsCategory'], $value);
}
}
}
$values = $myValues;
$this->_values = $values;
$values = $this->_getMappedValues($values);
$defaults = $this->_getMappedValues($this->_defaults, false, true);
$return = $values + $defaults;
return $return;
}
public function assemble($data = array(), $reset = false, $encode = false, $partial = false)
{
if ($this->_reverse === null) {
require_once 'Zend/Controller/Router/Exception.php';
throw new Zend_Controller_Router_Exception('Cannot assemble. Reversed route is not specified.');
}
$defaultValuesMapped = $this->_getMappedValues($this->_defaults, true, false);
$matchedValuesMapped = $this->_getMappedValues($this->_values, true, false);
$dataValuesMapped = $this->_getMappedValues($data, true, false);
// handle resets, if so requested (By null value) to do so
if (($resetKeys = array_search(null, $dataValuesMapped, true)) !== false) {
foreach ((array) $resetKeys as $resetKey) {
if (isset($matchedValuesMapped[$resetKey])) {
unset($matchedValuesMapped[$resetKey]);
unset($dataValuesMapped[$resetKey]);
}
}
}
// merge all the data together, first defaults, then values matched, then supplied
$mergedData = $defaultValuesMapped;
$mergedData = $this->_arrayMergeNumericKeys($mergedData, $matchedValuesMapped);
$mergedData = $this->_arrayMergeNumericKeys($mergedData, $dataValuesMapped);
/**
* Default Zend_Controller_Router_Route_Regex foreach insufficient
* I need to urlencode values if I bump into an array
*/
if ($encode) {
foreach ($mergedData as $key => &$value) {
if(is_array($value)) {
foreach($value as $myKey => &$myValue) {
$myValue = urlencode($myValue);
}
} else {
$value = urlencode($value);
}
}
}
ksort($mergedData);
$reverse = array();
for($i = 0; $i < count($mergedData['cmsCategory']); $i++) {
array_push($reverse, "%s");
}
if(!empty($mergedData['cmsObject'])) {
array_push($reverse, "%s");
$mergedData['cmsCategory'][] = $mergedData['cmsObject'];
}
$reverse = implode("/", $reverse);
$return = @vsprintf($reverse, $mergedData['cmsCategory']);
if ($return === false) {
require_once 'Zend/Controller/Router/Exception.php';
throw new Zend_Controller_Router_Exception('Cannot assemble. Too few arguments?');
}
return $return;
}
}
<强>用法:强>
<强>路线:强>
$routeCategory = new App_Controller_Router_Route_Category(
'',
array(
'module' => 'default',
'controller' => 'index',
'action' => 'index'
),
array(),
'%s'
);
$router->addRoute('category', $routeCategory);
网址助手:
echo "<br>Url: " . $this->_helper->url->url(array(
'module' => 'default',
'controller' => 'index',
'action' => 'index',
'cmsCategory' => array(
'first-category',
'subcategory',
'subsubcategory')
), 'category');
使用getAllParams()
在控制器中输出示例["cmsCategory"]=>
array(3) {
[0]=>
string(15) "first-category"
[1]=>
string(16) "subcategory"
[2]=>
string(17) "subsubcategory"
}
["cmsObject"]=>
string(15) "my-page.html"
["module"]=>
string(7) "default"
["controller"]=>
string(5) "index"
["action"]=>
string(5) "index"
cmsObject
category/subcategory/subsubcategory/my-page.html
答案 1 :(得分:2)
我已经完成了没有路线...我只路由了第一个参数,然后路由其他人获取控制器内的所有参数
路线:
resources.router.routes.catalog-display.route = /catalog/item/:id
resources.router.routes.catalog-display.defaults.module = catalog
resources.router.routes.catalog-display.defaults.controller = item
resources.router.routes.catalog-display.defaults.action = display
例如:
我用它作为目录,然后进入itemController进入displayAction我检查$ this-&gt; getRequest() - &gt; getParams(),重点是你可以(但我认为你知道它)阅读全部params以键/值的方式传递,例如:“site.com/catalog/item/15/kind/hat/color/red/size/M”将生成一个数组:$params['controller'=>'catalog','action'=>'display','id'=>'15','kind'=>'hat','color'=>'red','size'=>'M'];
答案 2 :(得分:1)
对于使用Zend Framework 2或Zend Framework 3遇到此问题的人,有一个regex route type可以(可能应该)用于OP的路由,其中有数量未知的参数取决于子类别的数量。若要使用,请将以下行添加到路由器配置的顶部:
use Zend\Router\Http\Regex;
然后,您可以使用以下路由来匹配未知数量的类别:
'categories' => [
'type' => Regex::class,
'options' => [
'regex' => '/categories(?<sequence>(/[\w\-]+)+)',
'defaults' => [
'controller' => ApplicationController\Categories::class,
'action' => 'view',
],
'spec' => '%sequence',
],
],
以上路线将与以下路线匹配:
/categories/parent-cat
/categories/parent-cat/child-cat
/categories/parent-cat/sub-child-cat
/categories/parent-cat/sub-sub-child-cat
/categories/parent-cat-2
/categories/parent-cat-2/child-cat
...等等。类别序列通过sequence
参数传递给控制器。您可以在控制器中根据需要处理此参数。