为KnpLabs / KnpMenu创建排序数组

时间:2017-10-19 15:26:11

标签: arrays symfony sorting knpmenubundle

我想在PHP中创建一个排序菜单,Symfony可能非常深。 因此我在db(parent_id,sort)类别中添加了2个字段

我的问题是得到像

这样的排序数组
array(
//MAIN CATEGORY 1
array(
    'id' => 1,
    'name' => 'Main',
    'child'=> false
),
//MAIN CATEGORY 2
array(
    'id' => 2,
    'name' => 'Main2',
    'child'=> false
),
//MAIN CATEGORY 3
array(
    'id' => 6,
    'name' => 'Main3',
    'child'=> array(
        array(
            'id' => 4,
            'name' => 'Sub of Main3',
            'child'=> array(
                        'id' => 4,
                        'name' => 'Sub Sub og Main3',
                        'child'=> false
            )
        ),
        array(
            'id' => 7,
            'name' => '2. Sub og Main3',
            'child'=> false
        )
    )
)

);

所以我可以用它来创建KnpMenu Bundle的菜单。 我找不到另一种方式,性能经济实惠,并且可以使用这个包。

任何人都可以帮助我,如何从数据库中创建数组?

我测试了一些东西并找到了一个像knpMenuBundle这样的解决方案:



namespace AppBundle\Menu;

use Knp\Menu\FactoryInterface;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;

class Builder implements ContainerAwareInterface
{



    use ContainerAwareTrait;

    public function mainMenu(FactoryInterface $factory, array $options)
    {
        $em         =   $this->container->get('doctrine')->getManager();
        $mandant    =   $this->container->get('session')->get('mandantId');
        $nodes      =   $em->getRepository('AppBundle:Categories')->findSorted($mandant);

        $menu = $factory->createItem('root');
        $menu->addChild('Startseite', array('route' => 'homepage'));


        foreach($nodes as $node)
        {
            $childMenu = $menu->addChild($node['name'],array('route' => $node['route']));
            $this->loadChild($childMenu,$node);
        }

        return $menu;
    }



    private function loadChild($childMenu,array $node)
    {
        if(isset($node['child']))
        {
            foreach ($node['child'] as $child)
            {
                $childMenu = $childMenu->addChild($child['name'],array('route' => $child['route']));
                $this->loadChild($childMenu,$child);
            }
        }
        return;

    }




1 个答案:

答案 0 :(得分:0)

我有一个非常类似的问题,这就是我如何解决它。

所以我的页面实体看起来像这样:

<?php

namespace AppBundle\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use Knp\Menu\NodeInterface;

/**
 * Page
 *
 * @ORM\Table(name="PAGE")
 * @ORM\Entity()
 */
class Page implements NodeInterface
{
    /**
     * @var int
     *
     * @ORM\Column(name="ID", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="TITLE", type="string", length=255)
     */
    private $title;

    /**
     * page | link | pdf
     * @var string
     *
     * @ORM\Column(name="CONTENT_TYPE", type="string", length=255)
     */
    private $contentType;

    /**
     * A page can have one parent
     *
     * @var FacetPage
     *
     * @ORM\ManyToOne(targetEntity="Page", inversedBy="childrenPages")
     * @ORM\JoinColumn(name="PARENT_PAGE_ID", referencedColumnName="ID")
     */
    private $parentPage;


    /**
     * A parent can have multiple children
     *
     * @var arrayCollection
     *
     * @ORM\OneToMany(targetEntity="Page", mappedBy="parentPage")
     *
     */
    private $childrenPages;

    /**
     * @var resource
     *
     * @ORM\Column(name="CONTENT", type="text", length=200000)
     */
    private $content;

    /**
     * Many pages could have many allowed roles
     *
     * @var arrayCollection
     *
     * @ORM\ManyToMany(targetEntity="Role")
     * @ORM\JoinTable(name="PAGE_ALLOWED_ROLES",
     *      joinColumns={@ORM\JoinColumn(name="page_id", referencedColumnName="ID")},
     *      inverseJoinColumns={@ORM\JoinColumn(name="role_id", referencedColumnName="ID")}
     *      )
     */
    private $allowedRoles;

    /**
     * @var string
     *
     * @ORM\Column(name="SLUG", type="string", nullable=true)
     */
    private $slug;

    /**
     * @var string
     *
     * @ORM\Column(name="PERMALINK", type="string", nullable=true)
     */
    private $permalink;

    /**
     * @var User
     *
     * @ORM\ManyToOne(targetEntity="User")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="CREATED_BY", referencedColumnName="ID", nullable=false)
     * })
     *
     */
    private $author;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="CREATED_ON", type="datetime", nullable=false)
     */
    private $createdOn;

    /**
     * The default status of new pages is published
     *
     * @var string
     *
     * @ORM\Column(name="STATUS", type="string", nullable=false, )
     */
    private $status = 'published';

    /**
     * Page constructor.
     */
    public function __construct(  ) {
        //https://knpuniversity.com/screencast/collections/many-to-many-setup#doctrine-arraycollection
        $this->allowedRoles = new ArrayCollection();
        $this->childrenPages = new ArrayCollection();

    }

    /**
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @param int $id
     */
    public function setId( int $id )
    {
        $this->id = $id;
    }

    /**
     * @return string
     */
    public function getTitle()
    {
        return $this->title;
    }

    /**
     * @param string $title
     */
    public function setTitle( string $title )
    {
        $this->title = $title;
    }

    /**
     * @return string
     */
    public function getContentType()
    {
        return $this->contentType;
    }

    /**
     * @param string $contentType
     */
    public function setContentType( string $contentType )
    {
        $this->contentType = $contentType;
    }

    /**
     * @return Page
     */
    public function getParentPage()
    {
        return $this->parentPage;
    }

    /**
     * @param Page $parentPage
     */
    public function setParentPage( Page $parentPage )
    {
        $this->parentPage = $parentPage;
    }

    /**
     * @return string
     */
    public function getContent()
    {
        return $this->content;
    }

    /**
     * @param string $content
     */
    public function setContent( string $content )
    {
        $this->content = $content;
    }

    /**
     * @return ArrayCollection|Role[]
     */
    public function getAllowedRoles()
    {
        return $this->allowedRoles;
    }

    /**
     * @param arrayCollection $allowedRoles
     */
    public function setAllowedRoles( $allowedRoles )
    {
        $this->allowedRoles = $allowedRoles;
    }

    /**
     * @return string
     */
    public function getSlug()
    {
        return $this->slug;
    }

    /**
     * @param string $slug
     */
    public function setSlug( string $slug )
    {
        $this->slug = $slug;
    }

    /**
     * @return string
     */
    public function getPermalink()
    {
        return $this->permalink;
    }

    /**
     * @param string $permalink
     */
    public function setPermalink( string $permalink )
    {
        $this->permalink = $permalink;
    }

    /**
     * @return User
     */
    public function getAuthor()
    {
        return $this->author;
    }

    /**
     * @param FacetUser $author
     */
    public function setAuthor( User $author )
    {
        $this->author = $author;
    }

    /**
     * @return \DateTime
     */
    public function getCreatedOn()
    {
        return $this->createdOn;
    }

    /**
     * @param \DateTime $createdOn
     */
    public function setCreatedOn( \DateTime $createdOn )
    {
        $this->createdOn = $createdOn;
    }

    /**
     * @return string
     */
    public function getStatus()
    {
        return $this->status;
    }

    /**
     * @param string $status
     */
    public function setStatus( string $status )
    {
        $this->status = $status;
    }

    /**
     * @return ArrayCollection
     */
    public function getChildrenPages()
    {
        return $this->childrenPages;
    }

    /**
     * @param ArrayCollection $childrenPages
     */
    public function setChildrenPages( $childrenPages )
    {
        $this->childrenPages = $childrenPages;
    }

    /**
     * Get the name of the node
     *
     * Each child of a node must have a unique name
     *
     * @return string
     */
    public function getName() {
        return $this->title;
    }

    /**
     * Get the options for the factory to create the item for this node
     *
     * @return array
     * @throws \Exception
     */
    public function getOptions() {
        if($this->contentType == 'page'){
            return [
                'route' => 'core_page_id',
                'routeParameters' => ['id'=>$this->id]
            ];
        }

        if($this->contentType == 'doc'){
            return [
                'uri'=>'/'.$this->getContent()
            ];
        }

        if($this->contentType == 'link'){
            return [
                'uri'=>$this->content
            ];
        }

        throw new \Exception('No valid options found for page type',500);
    }

    /**
     * Get the child nodes implementing NodeInterface
     *
     * @return \Traversable
     */
    public function getChildren() {
        return $this->getChildren();
    }
}

这里的主要区别在于它实现了Knp的NodeInterface及其在实体末尾定义的函数,getName(),getOptions()和getChildren()。

现在进入我的构建器,它基本上和你的递归函数做同样的事情。

<?php

namespace AppBundle\Menu;

use AppBundle\Entity\Page;
use Knp\Menu\FactoryInterface;
use Knp\Menu\ItemInterface;
use Knp\Menu\MenuItem;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;

class Builder implements ContainerAwareInterface
{

    use ContainerAwareTrait;

    /** @var ItemInterface */
    private $menu;

    /**
     * @param FactoryInterface $factory
     * @param array $options
     *
     * @return ItemInterface
     */
    public function mainMenu(FactoryInterface $factory, array $options)
    {
        $this->menu = $factory->createItem('root');

        $this->menu->addChild('Home', array('route' => 'core_homepage'));

        $em = $this->container->get('doctrine')->getManager();

        // get all published pages
        $pages = $em->getRepository(Page::class)->findBy(['status'=>'published']);

        // build pages
        try {
            $this->buildPageTree( $pages );
        } catch ( \Exception $e ) {
            error_log($e->getMessage());
        }

        return $this->menu;
    }

    /**
     *
     * @param array $pages
     * @param Page $parent
     * @param MenuItem $menuItem
     *
     * @throws \Exception
     */
    private function buildPageTree(array $pages, $parent = null, $menuItem = null)
    {
        /** @var Page $page */
        foreach ($pages as $page) {

            // If page doesn't have a parent, and no menuItem was passed then this is a top level add.
            if(empty($page->getParentPage()) && empty($menuItem) )
                $parentMenu = $this->menu->addChild($page->getTitle(), $page->getOptions());

            // if the current page's parent is === supplied parent, go deeper
            if ($page->getParentPage() === $parent) {

                // if a menuItem was given, then this page is a child so added it to the provided menu.
                if(!empty($menuItem))
                    $parentMenu = $menuItem->addChild($page->getTitle(), $page->getOptions());

                // go deeper
                $this->buildPageTree($pages, $page, $parentMenu);
            }
        }
    }

}

我希望这在某种程度上有所帮助!