Alex Foxleigh
Alex Foxleigh

Reputation: 1964

Nested dynamic menu with knpmenubundle

I've built a menu using knpmenubundle, it's working really well and pulling the navigation dynamically from the database. However the client now wants to add a submenu to it. I've written a controller which will find child pages, however I can't see how I can attach them to the subnavigation under the correct parent. At the moment all it does it attach a copy of the current element to itself as a child node.

Here is the menu builder:

 $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()
            ))
        );
    }

Here is the controller for the parent element:

 // 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
        )
    );
}

and here is the controller for the child element:

// 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
        )
    );
}

Both of these controllers pull information from the database using a custom repository class.

Here is the custom repository code:

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;
    }
}

It could be just a Monday morning issue, so I'll keep trying to work it out myself, if I do I will post it here as an answer.

Additional info

Updated builder // find all items with parents. Then attach the found item to its parent. $subNavItems = $this->getDoctrine() ->getRepository('acmeStyleGuideBundle:pageSector') ->findSubNav($sector, $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()
                        )
                    )
                );
            }
        }
    }

It's outputting:

<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>

Whereas I need it to output:

<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>

This is the schema for the PageContent table

<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>

Upvotes: 0

Views: 1053

Answers (1)

ferdynator
ferdynator

Reputation: 6410

You need to loop over all subElements and render a navigation link for each:

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()
            ))
        );
    }
}

Upvotes: 1

Related Questions