dongyou2635 2010-09-02 21:50
浏览 42
已采纳

Zend Navigation和Zend Router问题 - 找不到正确的活动页面

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);
  • 写回答

1条回答 默认 最新

  • doumi1852 2010-09-02 23:15
    关注

    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:

    $router["route_".$row["id"]] = array(
        "route" => $slugPath.".html",
        "defaults" => array(
            "pageId" => $row["id"],
            "locale" => $row["locale"],
            "module" => "frontend",
            "controller" => "page",
            "action" => "show"
        )
    );
    

    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:

    $navigation[$row["id"]] = array(
        "label" => $row["name"],
        "module" => "frontend",
        "controller" => "page",
        "action" => "show",
        "route" => "route_".$row["id"],
        "params" => array("pageId" => $row["id"]), // this line is new!
        "visible" => (boolean) $row["active"],
        "lastmod" => ($row["modified"] ? $row["modified"] : $row["created"])
    );
    

    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.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥17 pro*C预编译“闪回查询”报错SCN不能识别
  • ¥15 微信会员卡接入微信支付商户号收款
  • ¥15 如何获取烟草零售终端数据
  • ¥15 数学建模招标中位数问题
  • ¥15 phython路径名过长报错 不知道什么问题
  • ¥15 深度学习中模型转换该怎么实现
  • ¥15 Stata外部命令安装问题求帮助!
  • ¥15 从键盘随机输入A-H中的一串字符串,用七段数码管方法进行绘制。提交代码及运行截图。
  • ¥15 TYPCE母转母,插入认方向
  • ¥15 如何用python向钉钉机器人发送可以放大的图片?