douxiong3245 2014-12-11 10:13
浏览 26

Kohana多个foreach ORM对象的循环提前终止

I'm using Kohana 3.3 and trying to output the pages to the menu, and all sub-menus. Sub-menus are stored in the same table as pages, called page. The only difference between a page an a sub-menu is a flag. This is the table structure of page and the example pages I've created to get this working.

|  id  |  title  |  layout    |  content    |  is_menu  |  parent  |  position  |
|  1   |  Home   |  home.php  |  Lipsum...  |     0     |    0     |     1      |
|  3   |  Menu1  |  none      |             |     1     |    0     |     2      |
|  2   |  Expl1  |  view.php  |  Lipsum...  |     0     |    0     |     3      |
|  5   |  MPge2  |  view.php  |  Lipsum...  |     0     |    3     |     1      |
|  4   |  MPge1  |  view.php  |  Lipsum...  |     0     |    3     |     2      |

I load all of the pages as ORM objects into an array, ordering by parent and then position. I've ordered the table above as the query fetches them. And this is my PHP method to generate the HTML menu that I then pass the array of ORM pages into:

class Controller_Page extends Controller_Table {

/**
 * Ourput the menu for editing purposes. Include add new page buttons.
 *
 * @return  body
 */
public function action_acp_menu()
{
    $view = View::factory('acp/layouts/pages/menu')
        ->bind('menu_pages', $menu_pages);
    $pages = ORM::factory('Page')
        ->order_by('parent')
        ->order_by('position')
        ->find_all();
    $menu_pages = $this->menu($pages);
    $this->response->body($view->render());
}

/**
 * Output the pages in a menu format, with optional add more buttons if 
 * we're in the ACP. This returns a string of LIs without a wrapping UL.
 *
 * @param   ORM     $pages    ORM object of pages.
 * @param   integer $parent   Output all children of this parent.
 * @return  string
 */
private function menu($pages, $parent = 0)
{
    $html = '';
    $is_acp = (strpos(Request::initial()->uri(), 'acp') !== FALSE);
    echo "<br>Testing pages against parent: $parent<br>";
    foreach ($pages as $page)
    {
        echo "Page: ".$page->id."; Parent: ".$page->parent."<br>";
        if ($page->parent == $parent)
        {
            echo "Page belongs to the parent.<br>";
            if ($page->is_menu)
            {
                echo "Page ".$page->id." is a menu. Loading children.<br>";
                $children = $this->menu($pages, $page->id);
                if ($children OR $is_acp)
                {
                    echo "Children found (or we're in the ACP). Adding pages to the menu.<br>";
                    $html .= '<li class="dropdown" data-id="'.$page->id.'">'.($is_acp ? '
                        <span class="handle">::</span>' : '').'
                        <a href="#" class="dropdown-toggle" data-toggle="dropdown">
                            '.$page->title.'
                            <b class="caret"></b>
                        </a>
                        <ul class="dropdown-menu'.($is_acp ? ' sortable-child' : '').'" data-id="'.$page->id.'">
                            '.$children.'
                        </ul>
                    </li>';
                }
            }
            else
            {
                echo "Page ".$page->id." is not a menu. Outputting normal.<br>";
                $html .= '<li data-id="'.$page->id.'">'.($is_acp ? '
                    <span class="handle">::</span>' : '').'
                    <a href="/acp/pages/edit'.$page->id.'">'.$page->title.'</a>
                </li>';
            }
        }
        echo "Finished processing page ".$page->id."<br>";
    }
    echo "Finished looping all pages<br>";
    if ($is_acp)
    {
        $html .= '<li class="add-page">
            <a href="/acp/pages/create?parent='.$page->id.'">+ Add page</a>
        </li>';
    }
    echo "Finished testing against parent: $parent<br>";
    return $html;
}

As you can see I've put a bunch of echo's in to try and figure out what's going on. This is the output from all the echo's:

Testing pages against parent: 0
Page: 1; Parent: 0
Page belongs to the parent.
Page 1 is not a menu. Outputting normal.
Finished processing page 1
Page: 3; Parent: 0
Page belongs to the parent.
Page 3 is a menu. Loading children.

Testing pages against parent: 3
Page: 1; Parent: 0
Finished processing page 1
Page: 3; Parent: 0
Finished processing page 3
Page: 2; Parent: 0
Finished processing page 2
Page: 5; Parent: 3
Page belongs to the parent.
Page 5 is not a menu. Outputting normal.
Finished processing page 5
Page: 4; Parent: 3
Page belongs to the parent.
Page 4 is not a menu. Outputting normal.
Finished processing page 4
Finished looping all pages
Finished testing against parent: 3
Children found (or we're in the ACP). Adding pages to the menu.
Finished processing page 3
Finished looping all pages
Finished testing against parent: 0

So after the second call to the menu method for the sub-menu (ID 3), the foreach loop completes ID 3 but doesn't continue on to the next page. I don't understand why? I've done foreach loops like this in the past that have worked, this is my first time doing it in Kohana though so think it's something Kohana related that I don't understand.

I've created an eval.in of this, showing the code works and that it must be something in Kohana doing this. This is the result of all the echo's from the eval.in:

Testing pages against parent: 0
Page: 1; Parent: 0
Page belongs to the parent.
Page 1 is not a menu. Outputting normal.
Finished processing page 1
Page: 3; Parent: 0
Page belongs to the parent.
Page 3 is a menu. Loading children.

Testing pages against parent: 3
Page: 1; Parent: 0
Finished processing page 1
Page: 3; Parent: 0
Finished processing page 3
Page: 2; Parent: 0
Finished processing page 2
Page: 5; Parent: 3
Page belongs to the parent.
Page 5 is not a menu. Outputting normal.
Finished processing page 5
Page: 4; Parent: 3
Page belongs to the parent.
Page 4 is not a menu. Outputting normal.
Finished processing page 4
Finished looping all pages
Finished testing against parent: 3
Children found (or we're in the ACP). Adding pages to the menu.<br>
Finished processing page 3
Page: 2; Parent: 0
Page belongs to the parent.
Page 2 is not a menu. Outputting normal.
Finished processing page 2
Page: 5; Parent: 3
Finished processing page 5
Page: 4; Parent: 3
Finished processing page 4
Finished looping all pages
Finished testing against parent: 0

As you can see unlike in Kohana, after page 3 finishes processing it continues on to page 2 as expected. Why doesn't Kohana do this?

  • 写回答

2条回答 默认 最新

  • doulv8162 2014-12-11 10:47
    关注

    I've found the problem and a solution. Kohana handles ORM objects by reference. I don't know why that stops my foreach loop completing, but it does.

    The solution was to loop through the ORM objects once, storing the details of each page in an array of stdClass' instead. That way they weren't a reference, and so when I passed the new array in to my method it worked.

    If anyone else can post a more complete answer explaining why an array of referenced objects has this issue I'd appreciate it.

    评论

报告相同问题?

悬赏问题

  • ¥15 51单片机中C语言怎么做到下面类似的功能的函数(相关搜索:c语言)
  • ¥15 seatunnel 怎么配置Elasticsearch
  • ¥15 PSCAD安装问题 ERROR: Visual Studio 2013, 2015, 2017 or 2019 is not found in the system.
  • ¥15 (标签-MATLAB|关键词-多址)
  • ¥15 关于#MATLAB#的问题,如何解决?(相关搜索:信噪比,系统容量)
  • ¥500 52810做蓝牙接受端
  • ¥15 基于PLC的三轴机械手程序
  • ¥15 多址通信方式的抗噪声性能和系统容量对比
  • ¥15 winform的chart曲线生成时有凸起
  • ¥15 msix packaging tool打包问题