0

我正在将我的 CakePHP (v 2.44) 应用程序的一个运行良好的部分变成一个插件,当从我的插件的控制器中抛出异常时,我得到了最奇怪的行为:异常处理程序/渲染器开始使用我的app/View/Layouts/mylayout.ctp 中的主站点布局,然后使用 app/View/Layouts/error.ctp 中的默认布局中断它。这是一个摘录:

<div><ul><li class="jsdnavpopup blog-menu-categories">
<a href='/blog/categories'>All Categories</a><nav>
<!DOCTYPE html PUBLIC "{trimmed for space}">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>CakePHP: the rapid development php framework:Error Page</title>

如果您注意到在 Cake 组成布局的过程中,它看起来像一个新的标头。就在我的布局被中断的地方,我加载了一个元素,并且该元素使用了 requestAction(在我的开发环境中没有缓存)。如果我删除该元素,那么我的布局会呈现更多,直到遇到使用 requestAction 的下一个元素。这些 requestAction 调用不会向引发异常的插件请求操作。

我正在使用 app/Config/core.php 中的所有默认错误处理程序。唯一不同的是在错误视图中指定 $this->layout。

现在,如果我在插件的 View 文件夹中重新创建原始错误布局和视图,事情就会像我预期的那样工作。但出于实验目的,我将我的主站点布局的重命名副本放在那里,同样的事情。每当遇到使用 requestAction 的元素时,异常都会中断布局。

有任何想法吗?

我会重申,当从应用程序中不是插件的任何地方抛出异常时,一切都会完美运行。

4

1 回答 1

0

这是我的做法(按照对 OP 问题的评论中的要求)

在我的布局中,我将以下代码放在我希望顶部菜单出现的位置:

<?php echo $this->element('Menu.top_navigation'); ?>

这非常简单,并且允许我团队中的 HTML 设计人员将菜单放在他们想要的任何位置。
当然,幕后还有更多事情发生。以下是完成这项工作所需的其他文件:

插件/菜单/视图/元素/top_navigation.ctp:

    $thisMenu = ClassRegistry::init('Menu.Menu');
    $menus = $thisMenu->display_menu_widget(array('position'=> 'top'));

    echo $this->element('Menu.display_ul', array('menus' => $menus));

请注意,这只是一个包装器——您可以为页脚导航制作更多这些内容,甚至可以制作一个允许您将位置作为参数传递的元素。

插件/菜单/视图/元素/display_ul.ctp:

<?php
    if(empty($depth)){
        $depth = 0;
    }

    switch($depth){
        case 0:
            $classes = "dropdown";
        break;
        default:
            $classes = "";
        break;
    }
?>
<ul class="<?php echo $classes ?> depth_<?php echo $depth ?>">
    <?php foreach ($menus as $menu): ?>
        <li>
            <a href="<?php echo $menu['MenuItem']['url']; ?>">
                <?php echo $menu['MenuItem']['title']; ?>
            </a>
            <?php
                if(count($menu['children']) > 0){
                    echo $this->element(
                        'Menu.display_ul',
                        array(
                            'menus' => $menu['children'],
                            'depth' => $depth + 1
                        )
                    );
                }
            ?>
    </li>
<?php endforeach; ?>
</ul>

插件/菜单/模型/Menu.php:

/**
 * display_menu_widget method
 *
 * @param array $options
 * @return void
 */
public function display_menu_widget($options = array()) {

    $defaults = array(
        'position' => 'top'
    );

    $settings = array_merge($defaults, $options);

    $this->recursive = 0;

    $menuItems = array();

    $conditions = array(
        'Menu.position' => $settings['position']
    );

    $menuDetails = $this->find('first', array('recursive' => -1, 'conditions' => $conditions));


    $menuPosition = $menuDetails[$this->alias]['position'];
    $parentId = $menuDetails[$this->alias][$this->primaryKey];

    $conditions = array(
        $this->MenuItem->alias . '.menu_id' => $parentId
    );

    $this->MenuItem->recursive = 0;

    $cacheName = 'default' . 'ModelMenuItem';
    $cacheKey = $this->generateCacheName(array('type' => 'threaded', 'conditions' => $conditions));

    $menuItems = Cache::read($cacheKey, $cacheName);

    if(empty($menuItems) || PWFunctions::forceCacheFlush()){
        $menuItems = $this->MenuItem->find('threaded', array('conditions' => $conditions));

        Cache::write($cacheKey, $menuItems, $cacheName);
    }

    return $menuItems;
}

该菜单功能可能比您需要的更多,我正在使用一些积极的缓存例程来减少数据库负载,我建议在担心缓存之前只使用该功能的基本功能。

这个解决方案对我来说效果很好,我认为它是最不违反 MVC 概念的解决方案——当你作为设计师处于 HTML 模式并认为“嘿,我需要显示顶部菜单”时,它只是一个线在您的视图中,您不必担心修改控制器或模型。

我在我当前的 CakePHP 项目中一直使用这种模式,而且它似乎工作得很好。

于 2014-01-08T06:15:02.793 回答