Вложенное динамическое меню с knpmenubundle

Я создал меню с помощью knpmenubundle, оно работает очень хорошо и динамически извлекает навигацию из базы данных. Однако теперь клиент хочет добавить к нему подменю. Я написал контроллер, который будет находить дочерние страницы, однако я не вижу, как я могу прикрепить их к субнавигации под правильным родителем. На данный момент все, что он делает, это прикрепляет копию текущего элемента к себе как к дочернему узлу.

Вот конструктор меню:

 $sector = $options['sector'];
    $em = $this->getDoctrine()->getManager();
    $navItems = $this->getDoctrine()
    ->getRepository('acmeStyleGuideBundle:pageSector')
    ->findBySectorJoinedToUrl($sector);
    if (!$navItems) throw $this->createNotFoundException('Unable to find any matching pages');
    $menu = $factory->createItem('root');
    foreach ($navItems as $nav)
    {
        // Doesn't have any parents, This is a top level
        $parent = $menu->addChild($nav->getPageName(), array(
            'route' => 'acme_style_guide_pages_show',
            'routeParameters' => array(
                'sector' => $sector,
                'pageUrl' => $nav->getPageUrl()
            )
        ));
        $parent->addChild($nav->getPageName(), array(
            'route' => 'acme_style_guide_pages_show_sub',
            'routeParameters' => array(
                'sector' => $sector,
                'pageParent' => $nav->getPageName(),
                'pageUrl' => $nav->getPageUrl()
            ))
        );
    }

Вот контроллер родительского элемента:

 // Render pages from database
public function showAction($sector, $pageUrl)
{
    $em = $this->getDoctrine()->getManager();
    $pages = $this->getDoctrine()
    ->getRepository('acmeStyleGuideBundle:PageContent')
    ->findByUrlJoinedToSector($sector, $pageUrl);

    if (!$pages) throw $this->createNotFoundException('Unable to find any matching pages');
    return $this->render(
        'acmeStyleGuideBundle:Page:pages.html.twig', 
        array(
            'Pages' => $pages,
            'sector' => $sector
        )
    );
}

а вот контроллер дочернего элемента:

// Render sub pages from database
public function showSubAction($sector, $pageParent, $pageUrl)
{
    $em = $this->getDoctrine()->getManager();
    $pages = $this->getDoctrine()
    ->getRepository('acmeStyleGuideBundle:PageContent')
    ->findByUrlJoinedToSectorAndParent($sector, $pageParent, $pageUrl);

    if (!$pages) throw $this->createNotFoundException('Unable to find any matching pages');
    return $this->render(
        'acmeStyleGuideBundle:Page:pages.html.twig', 
        array(
            'Pages' => $pages,
            'sector' => $sector
        )
    );
}

Оба этих контроллера извлекают информацию из базы данных с помощью специального класса репозитория.

Вот код настраиваемого репозитория:

public function findByUrlJoinedToSector($sector, $pageUrl)
{
    $query = $this->getEntityManager()
        ->createQuery('
            SELECT p, s FROM acmeStyleGuideBundle:PageContent p
            JOIN p.pageSector s
            LEFT JOIN p.pageTypes t
            WHERE p.pageUrl = :url
            AND s.sectorName = :sector
            AND t.typeName != :type'
        )
        ->setParameter('url', $pageUrl)
        ->setParameter('sector', $sector)
        ->setParameter('type', 'Section Headers');

    try {
        return $query->getResult();
    } catch (\Doctrine\ORM\NoResultException $e) {
        return null;
    }
}

public function findByUrlJoinedToSectorAndParent($sector, $pageParent, $pageUrl)
{
    $query = $this->getEntityManager()
        ->createQuery('
            SELECT p, s, c FROM acmeStyleGuideBundle:PageContent p
            JOIN p.pageSector s
            LEFT JOIN p.pageTypes t
            LEFT JOIN p.PageParent c
            WHERE p.pageUrl = :url
            AND s.sectorName = :sector
            AND c.pageUrl = :parent
            AND t.typeName != :type'
        )
        ->setParameter('url', $pageUrl)
        ->setParameter('sector', $sector)
        ->setParameter('parent', $pageParent)
        ->setParameter('type', 'Section Headers');

    try {
        return $query->getResult();
    } catch (\Doctrine\ORM\NoResultException $e) {
        return null;
    }
}

Это может быть просто проблема в понедельник утром, поэтому я буду продолжать пытаться решить ее сам, если я это сделаю, я отправлю ее здесь в качестве ответа.

Дополнительная информация

Обновлен конструктор // найти все предметы вместе с родителями. Затем прикрепите найденный элемент к его родительскому элементу. $ subNavItems = $ this-> getDoctrine () -> getRepository ('acmeStyleGuideBundle: pageSector') -> findSubNav ($ сектор, $ nav-> getPageParent ());

        // loop over them and add a link for each one:
        foreach ($subNavItems as $child) {
            if ($child->getPageParent() != NULL) {
                $parent->addChild($child->getPageName(), array(
                    'route' => 'acme_style_guide_pages_show_sub',
                    'routeParameters' => array(
                        'sector' => $sector,
                        'pageParent' => $child->getPageName(),
                        'pageUrl' => $child->getPageUrl()
                        )
                    )
                );
            }
        }
    }

Выводится:

<ul>
    <li><a href="link">Target Item</a></li>
    <li><a href="link">Item</a></li>
    <li><a href="link">Item</a></li>
    <li><a href="link">Child</a>
        <ul>
            <li><a href="link">Child</a></li>
        </ul>
    </li>
</ul>

В то время как мне это нужно для вывода:

<ul>
    <li><a href="link">Target Item</a>
        <ul>
            <li><a href="link">Child</a></li>
        </ul>
    </li>
    <li><a href="link">Item</a></li>
    <li><a href="link">Item</a></li>
    <li><a href="link">Child</a></li>
</ul>

Это схема таблицы PageContent

<database name="styleguide">
        <!-- Table PageContent -->
        <table name="PageContent">
            <column name="id">1</column>
            <column name="pageTypesId">2</column>
            <column name="pageName">Text Elements</column>
            <column name="pageUrl">text-elements</column>
            <column name="richText">&lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.&lt;/p&gt;&lt;p&gt;Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.&lt;/p&gt;</column>
            <column name="PageParent">NULL</column>
        </table>
        <table name="PageContent">
            <column name="id">2</column>
            <column name="pageTypesId">2</column>
            <column name="pageName">Buttons</column>
            <column name="pageUrl">buttons</column>
            <column name="richText">&lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.&lt;/p&gt;&lt;p&gt;Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.&lt;/p&gt;</column>
            <column name="PageParent">NULL</column>
        </table>
        <table name="PageContent">
            <column name="id">3</column>
            <column name="pageTypesId">2</column>
            <column name="pageName">Forms</column>
            <column name="pageUrl">forms</column>
            <column name="richText">&lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.&lt;/p&gt;&lt;p&gt;Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.&lt;/p&gt;</column>
            <column name="PageParent">NULL</column>
        </table>
        <table name="PageContent">
            <column name="id">4</column>
            <column name="pageTypesId">2</column>
            <column name="pageName">Lists</column>
            <column name="pageUrl">lists</column>
            <column name="richText">&lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.&lt;/p&gt;&lt;p&gt;Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.&lt;/p&gt;</column>
            <column name="PageParent">NULL</column>
        </table>
        <table name="PageContent">
            <column name="id">5</column>
            <column name="pageTypesId">2</column>
            <column name="pageName">Tables</column>
            <column name="pageUrl">tables</column>
            <column name="richText">&lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.&lt;/p&gt;&lt;p&gt;Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.&lt;/p&gt;</column>
            <column name="PageParent">NULL</column>
        </table>
        <table name="PageContent">
            <column name="id">6</column>
            <column name="pageTypesId">2</column>
            <column name="pageName">Search Box</column>
            <column name="pageUrl">search-box</column>
            <column name="richText">&lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.&lt;/p&gt;&lt;p&gt;Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.&lt;/p&gt;</column>
            <column name="PageParent">NULL</column>
        </table>
        <table name="PageContent">
            <column name="id">7</column>
            <column name="pageTypesId">2</column>
            <column name="pageName">Pods</column>
            <column name="pageUrl">pods</column>
            <column name="richText">&lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.&lt;/p&gt;&lt;p&gt;Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.&lt;/p&gt;</column>
            <column name="PageParent">NULL</column>
        </table>
        <table name="PageContent">
            <column name="id">8</column>
            <column name="pageTypesId">3</column>
            <column name="pageName">Business</column>
            <column name="pageUrl">business</column>
            <column name="richText">&lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.&lt;/p&gt;&lt;p&gt;Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.&lt;/p&gt;</column>
            <column name="PageParent">NULL</column>
        </table>
        <table name="PageContent">
            <column name="id">9</column>
            <column name="pageTypesId">3</column>
            <column name="pageName">Residential</column>
            <column name="pageUrl">residential</column>
            <column name="richText">&lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.&lt;/p&gt;&lt;p&gt;Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.&lt;/p&gt;</column>
            <column name="PageParent">NULL</column>
        </table>
        <table name="PageContent">
            <column name="id">10</column>
            <column name="pageTypesId">1</column>
            <column name="pageName">Paragraphs</column>
            <column name="pageUrl">paragraphs</column>
            <column name="richText">&lt;p&gt;Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.&lt;/p&gt;&lt;p&gt;Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.&lt;/p&gt;</column>
            <column name="PageParent">1</column>
        </table>
    </database>

person Alex Foxleigh    schedule 23.09.2013    source источник
comment
Либо в вашем query, либо в вашей базе данных есть ошибка. Ваш код правильный. Я предполагаю, что элемент child связан с неправильным родителем в базе данных.   -  person ferdynator    schedule 23.09.2013
comment
Я думаю, это может быть из-за того, как мои данные выложены (добавлен XML схемы таблицы для вопроса). Вместо родителей, содержащих массив детей в отношениях «один ко многим». Я попытался сделать это с дочерним элементом, содержащим ссылку на своего родителя во взаимно однозначных отношениях. Это казалось наиболее разумным способом сделать это, но похоже, что это могло вызвать проблемы. Как вы думаете, было бы легко исправить это или мне следует изменить структуру базы данных?   -  person Alex Foxleigh    schedule 23.09.2013
comment
Вы найдете множество примеры в официальной доктрине   -  person ferdynator    schedule 23.09.2013


Ответы (1)


Вам нужно перебрать все subElements и отобразить ссылку навигации для каждого:

foreach ($navItems as $nav)
{
    // Doesn't have any parents, This is a top level
    $parent = $menu->addChild($nav->getPageName(), array(
        'route' => 'acme_style_guide_pages_show',
        'routeParameters' => array(
            'sector' => $sector,
            'pageUrl' => $nav->getPageUrl()
        )
    ));

    // find all sub-items:
    $subNavItems = $this->getDoctrine()
    ->getRepository('acmeStyleGuideBundle:pageSector')
    ->findByUrlJoinedToSectorAndParent($sector, $parent, /* $pageUrl */);

    // loop over them and add a link for each one:
    foreach ($subNavItems as $child) {
        $parent->addChild($child->getPageName(), array(
            'route' => 'acme_style_guide_pages_show_sub',
            'routeParameters' => array(
                'sector' => $sector,
                'pageParent' => $child->getPageName(),
                'pageUrl' => $child->getPageUrl()
            ))
        );
    }
}
person ferdynator    schedule 23.09.2013
comment
Это действительно хорошо сработало. Мне пришлось создать для него собственный метод репозитория, поскольку метод findByUrlJoinedToSectorAndParent () на самом деле не подходил. Спасибо! :) - person Alex Foxleigh; 23.09.2013
comment
вам просто нужно помнить, что дочерние элементы ничем не отличаются от корневого элемента. Если помнить об этом, knpMenus действительно легко создать. - person ferdynator; 23.09.2013
comment
На самом деле. Я только что заметил, что он все еще не ВЕСЬМА работает так, как я ожидал. Он выводит только те элементы, у которых есть родители, но по-прежнему помещает копии элемента под себя. Я поставил новый результат в свой вопрос. - person Alex Foxleigh; 23.09.2013
comment
Можете ли вы обновить свой вопрос, чтобы добавить результат html и текущий menu builder? - person ferdynator; 23.09.2013
comment
Вам нужно добавить информацию к своему вопросу, а не к моему ответу. Также укажите код шаблона веточки. - person ferdynator; 23.09.2013
comment
Ой! Это был несчастный случай. Извините. Готово :) Не знаю, что добавить для кода ветки, все, что у меня есть в моих шаблонах, - это команда меню рендеринга. - person Alex Foxleigh; 23.09.2013