Zend Navigation 和 Zend Router 问题 - 未找到正确的活动页面
好的。我正在使用 Zend 构建 CMS。它并不像看起来那么简单,但对我来说仍然是最好的解决方案。我有一个带有 ID 和 PARENT 的树形系统,PARENT 标记子项所在的页面。反正。简单的东西。
每次创建或排序页面时路线已重新生成。
我将在此处复制用于创建导航和路线的整个 Admin_Pages_Model 代码。
导航在这里创建: (我认为不需要模块/控制器/操作信息,因为它是从路由器加载的)
public function createNavigation($locale = false){
$root = $this->getRoot($locale);
$navigation = array();
$router = array();
foreach($root as $row){
$navigation[$row["id"]] = array(
"label" => $row["name"],
"module" => "frontend",
"controller" => "page",
"action" => "show",
"route" => "route_".$row["id"],
"visible" => (boolean) $row["active"],
"lastmod" => ($row["modified"] ? $row["modified"] : $row["created"])
);
$children = $this->getChildren($row["id"]);
if(count($children)){
foreach($children as $child){
$navigation[$row["id"]]["pages"][$child["id"]] = $this->_createNavigation($child["id"]);
}
}
}
$nav = new Zend_Navigation(new Zend_Config($navigation));
$this->createRoutes();
if(!$locale){
Crcms_Config::setConfig("navigation_sitemap", $nav->toArray());
} else {
Crcms_Config::setConfig("navigation_".$locale, $nav->toArray());
}
}
private function _createNavigation($id){
$page = $this->getPage($id);
$navigation = array(
"label" => $page["name"],
"module" => "frontend",
"controller" => "page",
"action" => "show",
"route" => "route_".$page["id"],
"visible" => (boolean) $page["active"],
"lastmod" => ($page["modified"] ? $page["modified"] : $page["created"])
);
$children = $this->getChildren($page["id"]);
if(count($children)){
foreach($children as $child){
$navigation["pages"][$child["id"]] = $this->_createNavigation($child["id"]);
}
}
return $navigation;
}
最后 - 在将导航保存到数据库之前,它调用 $this->createRoutes();代码如下:
public function createRoutes(){
$root = $this->getRoot($locale);
foreach($root as $row){
$slugPath = "/".$row["slug"]."";
$router["route_".$row["id"]] = array(
"route" => $slugPath.".html",
"defaults" => array(
"pageId" => $row["id"],
"locale" => $row["locale"],
"module" => "frontend",
"controller" => "page",
"action" => "show"
)
);
$children = $this->getChildren($row["id"]);
if(count($children)){
foreach($children as $child){
$router = array_merge($router, $this->_createRoutes($child["id"], $slugPath."/".$child["slug"].""));
}
}
}
$routerConfig = new Zend_Config($router);
Crcms_Config::setConfig("frontend_router", $routerConfig->toArray());
}
private function _createRoutes($id, $slugPath){
$page = $this->getPage($id);
$router["route_".$page["id"]] = array(
"route" => $slugPath.".html",
"defaults" => array(
"pageId" => $page["id"],
"locale" => $page["locale"],
"module" => "frontend",
"controller" => "page",
"action" => "show"
)
);
$children = $this->getChildren($page["id"]);
if(count($children)){
foreach($children as $child){
$router = array_merge($router, $this->_createRoutes($child["id"], $slugPath."/".$child["slug"].""));
}
}
return $router;
}
现在一切都是数据库了。 在我的 boostrap 中,我加载:
protected function _initPostFrontController(){
$this->bootstrap('frontController');
$front = $this->getResource("FrontController");
$frontendRouterConfig = new Zend_Config(Crcms_Config::getConfig("frontend_router"));
$router = $front->getRouter();
$router->addConfig($frontendRouterConfig);
$front
->setParam("prefixDefaultModule", true)
->registerPlugin(new Global_Setup())
->registerPlugin(new Global_Auth())
->registerPlugin(new Global_Translation())
->registerPlugin(new Global_LayoutLoader());
}
这是我的 Global_Setup:
class Global_Setup extends Zend_Controller_Plugin_Abstract {
public function preDispatch (Zend_Controller_Request_Abstract $request){
$front = Zend_Controller_Front::getInstance();
$errorHandler = $front->getPlugin("Zend_Controller_Plugin_ErrorHandler");
$errorHandler->setErrorHandlerModule("frontend");
$layout = Zend_Layout::getMvcInstance();
$view = $layout->getView();
switch($request->getModuleName()){
case "admin":
$session = new Zend_Session_Namespace("Crcms_Admin");
$locale = Zend_Registry::get("Zend_Locale");
$view->doctype("HTML5");
$view->headTitle(Zend_Registry::get("Zend_Config")->system->about->software);
$view->headTitle()->setSeparator(" | ");
$view->headTitle(Crcms_Config::getConfig("site_name"));
$view->headLink()->headLink(array(
"rel" => "shortcut icon",
"href" => Zend_Registry::get("Zend_Config")->system->paths->http->publib."/images/favicon.ico"), "PREPEND");
break;
default:
$session = new Zend_Session_Namespace("Crcms_Frontend");
if(!$session->locale){
$session->locale = Crcms_Config::getConfig("locale_default");
}
$navigation = new Zend_Navigation(new Zend_Config(Crcms_Config::getConfig("navigation_".$session->locale)));
$view->navigation()->setContainer($navigation);
break;
}
}
}
所以基本上一切都很好。 LayoutLoader选择默认的布局路径和基于admin/frontend的布局。
反正。在我的前端布局中,我有这样的:
<div id="menu"><?= $this->navigation()->menu(); ?></div>
<div id="breadcrumb"><?= $this->navigation()->breadcrumbs(); ?></div>
<div id="content"><?= $this->layout()->content; ?></div>
菜单创建良好。所有级别都是超级(Y)。但是一切都是class="active"!!!并且readcrumb总是显示最深的元素。
页面选择效果很好!参数 pageId 被正确传递并且路由器工作。只是导航混乱了。
一些图片可以给您带来想法:
管理方面: - http://grab.by/6d67
前端:
从图片中可以看出,URL 发生了变化 - 内容也发生了变化。所以路由器必须工作。
一切都只是“活跃”: http://grab.by/6d6j
我知道我已经粘贴了很多这里有信息,但请帮助我。我在这个问题上花了 20 多个小时——没有解决方案的帮助。
有点修好了。我不认为这是“正确的方式”,但它仍然有效。我从导航中评论了控制器/操作/模块(路线中没有任何变化)。添加了“id”=> “页面-”。$页面[“id”]。
现在在我的 Global_Setup 中我做了这样的事情 ->
$navigation = new Zend_Navigation(new Zend_Config(Crcms_Config::getConfig("navigation_".$session->locale)));
$navigation->findBy("id", "page-".$request->getParam("pageId"))
->setActive(true);
Okay. I'm building a CMS with Zend. It isn't as simple as it looked but still — the best solution for me. I have a tree system with ID and PARENT, PARENT marks under which page the child resides. Anyway. Simple stuff.
Every time a page is created or sorted Nav & Routes are regenerated.
I'll copy the whole Admin_Pages_Model code for creating Navigation and Routes here.
Navigation is created here:
(I think that module/controller/action information isn't needed because it is loaded from router)
public function createNavigation($locale = false){
$root = $this->getRoot($locale);
$navigation = array();
$router = array();
foreach($root as $row){
$navigation[$row["id"]] = array(
"label" => $row["name"],
"module" => "frontend",
"controller" => "page",
"action" => "show",
"route" => "route_".$row["id"],
"visible" => (boolean) $row["active"],
"lastmod" => ($row["modified"] ? $row["modified"] : $row["created"])
);
$children = $this->getChildren($row["id"]);
if(count($children)){
foreach($children as $child){
$navigation[$row["id"]]["pages"][$child["id"]] = $this->_createNavigation($child["id"]);
}
}
}
$nav = new Zend_Navigation(new Zend_Config($navigation));
$this->createRoutes();
if(!$locale){
Crcms_Config::setConfig("navigation_sitemap", $nav->toArray());
} else {
Crcms_Config::setConfig("navigation_".$locale, $nav->toArray());
}
}
private function _createNavigation($id){
$page = $this->getPage($id);
$navigation = array(
"label" => $page["name"],
"module" => "frontend",
"controller" => "page",
"action" => "show",
"route" => "route_".$page["id"],
"visible" => (boolean) $page["active"],
"lastmod" => ($page["modified"] ? $page["modified"] : $page["created"])
);
$children = $this->getChildren($page["id"]);
if(count($children)){
foreach($children as $child){
$navigation["pages"][$child["id"]] = $this->_createNavigation($child["id"]);
}
}
return $navigation;
}
In the end - before saving navigation to database it calls $this->createRoutes(); So heres the code:
public function createRoutes(){
$root = $this->getRoot($locale);
foreach($root as $row){
$slugPath = "/".$row["slug"]."";
$router["route_".$row["id"]] = array(
"route" => $slugPath.".html",
"defaults" => array(
"pageId" => $row["id"],
"locale" => $row["locale"],
"module" => "frontend",
"controller" => "page",
"action" => "show"
)
);
$children = $this->getChildren($row["id"]);
if(count($children)){
foreach($children as $child){
$router = array_merge($router, $this->_createRoutes($child["id"], $slugPath."/".$child["slug"].""));
}
}
}
$routerConfig = new Zend_Config($router);
Crcms_Config::setConfig("frontend_router", $routerConfig->toArray());
}
private function _createRoutes($id, $slugPath){
$page = $this->getPage($id);
$router["route_".$page["id"]] = array(
"route" => $slugPath.".html",
"defaults" => array(
"pageId" => $page["id"],
"locale" => $page["locale"],
"module" => "frontend",
"controller" => "page",
"action" => "show"
)
);
$children = $this->getChildren($page["id"]);
if(count($children)){
foreach($children as $child){
$router = array_merge($router, $this->_createRoutes($child["id"], $slugPath."/".$child["slug"].""));
}
}
return $router;
}
So now everything is database.
In my boostrap I load:
protected function _initPostFrontController(){
$this->bootstrap('frontController');
$front = $this->getResource("FrontController");
$frontendRouterConfig = new Zend_Config(Crcms_Config::getConfig("frontend_router"));
$router = $front->getRouter();
$router->addConfig($frontendRouterConfig);
$front
->setParam("prefixDefaultModule", true)
->registerPlugin(new Global_Setup())
->registerPlugin(new Global_Auth())
->registerPlugin(new Global_Translation())
->registerPlugin(new Global_LayoutLoader());
}
This is my Global_Setup:
class Global_Setup extends Zend_Controller_Plugin_Abstract {
public function preDispatch (Zend_Controller_Request_Abstract $request){
$front = Zend_Controller_Front::getInstance();
$errorHandler = $front->getPlugin("Zend_Controller_Plugin_ErrorHandler");
$errorHandler->setErrorHandlerModule("frontend");
$layout = Zend_Layout::getMvcInstance();
$view = $layout->getView();
switch($request->getModuleName()){
case "admin":
$session = new Zend_Session_Namespace("Crcms_Admin");
$locale = Zend_Registry::get("Zend_Locale");
$view->doctype("HTML5");
$view->headTitle(Zend_Registry::get("Zend_Config")->system->about->software);
$view->headTitle()->setSeparator(" | ");
$view->headTitle(Crcms_Config::getConfig("site_name"));
$view->headLink()->headLink(array(
"rel" => "shortcut icon",
"href" => Zend_Registry::get("Zend_Config")->system->paths->http->publib."/images/favicon.ico"), "PREPEND");
break;
default:
$session = new Zend_Session_Namespace("Crcms_Frontend");
if(!$session->locale){
$session->locale = Crcms_Config::getConfig("locale_default");
}
$navigation = new Zend_Navigation(new Zend_Config(Crcms_Config::getConfig("navigation_".$session->locale)));
$view->navigation()->setContainer($navigation);
break;
}
}
}
So basically everything is Okay. The LayoutLoader selects the default layout path and the layout based on admin/frontend.
Anyway. In my frontend layout I have this :
<div id="menu"><?= $this->navigation()->menu(); ?></div>
<div id="breadcrumb"><?= $this->navigation()->breadcrumbs(); ?></div>
<div id="content"><?= $this->layout()->content; ?></div>
The menu creates fine. All levels are super (Y). but EVERYTHING is class="active"!!! and readcrumb always shows the most deepest element.
The page selection works fine! The param pageId is passed right and the router works. Navigation is messed up only.
Some pics to give you the idea:
The admin side:
- http://grab.by/6d67
The frontend side:
So as seen from the pictures URL changes - content changes also. So router must work.
Everything is just "active": http://grab.by/6d6j
I know that I've pasted alot of info here but please help me. I've like worked 20+ hours on this problem — no solution help.
Kinda fixed it. I don't think it's the "right way" but still - its now working. I commented controller/action/module out from the navigation thing (nothing has changed in Routes). Added a "id" => "page-".$page["id"].
Now in my Global_Setup I did something like this ->
$navigation = new Zend_Navigation(new Zend_Config(Crcms_Config::getConfig("navigation_".$session->locale)));
$navigation->findBy("id", "page-".$request->getParam("pageId"))
->setActive(true);
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这只是猜测,因为仅通过查看代码很难解决这个问题。
当您构建路由时,您正在设置 pageId:
大概这是您在控制器中使用的唯一标识符,用于确定请求了哪个页面?
Zend Navigation 在每个页面上调用 isActive() 方法来确定要突出显示哪一个页面。对于 Mvc 页面,它的作用是将您提供的路由参数(控制器、模块、操作和其他参数)与请求对象中的参数进行比较。在您的情况下,所有页面都指向同一个操作,并且您没有向 Zend Navigation 提供 pageId,因此它所做的只是将模块/控制器/操作与请求中的模块/控制器/操作进行比较,它们将始终匹配。
如果我是对的,您需要做的就是将 pageId 添加到您构建的导航对象中,因此在第一个代码示例的循环中:
如果这不起作用,我希望它至少会指向您正确的方向。我确实认为 isActive() 方法是问题所在,所以如果您不介意调试一些 Zend Framework 代码(暂时),请在 Zend/Navigation/Page/Mvc.php 中找到该方法,验证它是否被调用,看看你是否能找出哪里出了问题。
This is something of a guess, as it's hard to work this out just by looking at the code.
When you are building up your routes, you're setting a pageId:
Presumably this is the unique identifier you use in your controller to work out which page was requested?
Zend Navigation calls the isActive() method on each page to work out which one to highlight. For Mvc pages what this does is compare the route params you've supplied (controller, module, action and other params) to the params in the request object. In your case, all of the pages point at the same action, and you haven't given Zend Navigation the pageId so all it's doing is comparing module/controller/action to the module/controller/action in the request, which will always match.
If I'm right, all you need to do is add the pageId to the navigation object you build up, so in the loop in your first code sample:
If this doesn't work, I hope it will at least point you in the right direction. I do think the isActive() method is where the problem lies, so if you don't mind debugging some Zend Framework code (temporarily), find that method in Zend/Navigation/Page/Mvc.php, verify that it is being called, and see if you can figure out where it's going wrong.