vendor/kunstmaan/node-bundle/Helper/NodeMenu.php line 15

Open in your IDE?
  1. <?php
  2. namespace Kunstmaan\NodeBundle\Helper;
  3. use Doctrine\ORM\EntityManagerInterface;
  4. use Kunstmaan\AdminBundle\Helper\DomainConfigurationInterface;
  5. use Kunstmaan\AdminBundle\Helper\Security\Acl\AclHelper;
  6. use Kunstmaan\AdminBundle\Helper\Security\Acl\Permission\PermissionMap;
  7. use Kunstmaan\NodeBundle\Entity\HasNodeInterface;
  8. use Kunstmaan\NodeBundle\Entity\Node;
  9. use Kunstmaan\NodeBundle\Entity\NodeTranslation;
  10. use Kunstmaan\NodeBundle\Repository\NodeRepository;
  11. use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
  12. class NodeMenu
  13. {
  14.     /**
  15.      * @var EntityManagerInterface
  16.      */
  17.     private $em;
  18.     /**
  19.      * @var TokenStorageInterface
  20.      */
  21.     private $tokenStorage;
  22.     /**
  23.      * @var AclHelper
  24.      */
  25.     private $aclHelper;
  26.     /**
  27.      * @var string
  28.      */
  29.     private $locale;
  30.     /**
  31.      * @var Node
  32.      */
  33.     private $currentNode;
  34.     /**
  35.      * @var string
  36.      */
  37.     private $permission PermissionMap::PERMISSION_VIEW;
  38.     /**
  39.      * @var bool
  40.      */
  41.     private $includeOffline false;
  42.     /**
  43.      * @var bool
  44.      */
  45.     private $includeHiddenFromNav false;
  46.     /**
  47.      * @var NodeMenuItem[]
  48.      */
  49.     private $topNodeMenuItems;
  50.     /**
  51.      * @var NodeMenuItem[]
  52.      */
  53.     private $breadCrumb;
  54.     /**
  55.      * @var Node[]
  56.      */
  57.     private $allNodes = array();
  58.     /**
  59.      * @var Node[]
  60.      */
  61.     private $childNodes = array();
  62.     /**
  63.      * @var Node[]
  64.      */
  65.     private $nodesByInternalName = array();
  66.     /**
  67.      * @var bool
  68.      */
  69.     private $initialized false;
  70.     /**
  71.      * @var NodeMenuItem
  72.      */
  73.     private $rootNodeMenuItem;
  74.     /**
  75.      * @var DomainConfigurationInterface
  76.      */
  77.     private $domainConfiguration;
  78.     /**
  79.      * @param EntityManagerInterface       $em                  The entity manager
  80.      * @param TokenStorageInterface        $tokenStorage        The security token storage
  81.      * @param AclHelper                    $aclHelper           The ACL helper pages
  82.      * @param DomainConfigurationInterface $domainConfiguration The current domain configuration
  83.      */
  84.     public function __construct(
  85.         EntityManagerInterface $em,
  86.         TokenStorageInterface $tokenStorage,
  87.         AclHelper $aclHelper,
  88.         DomainConfigurationInterface $domainConfiguration
  89.     ) {
  90.         $this->em $em;
  91.         $this->tokenStorage $tokenStorage;
  92.         $this->aclHelper $aclHelper;
  93.         $this->domainConfiguration $domainConfiguration;
  94.     }
  95.     /**
  96.      * @param string $locale
  97.      */
  98.     public function setLocale($locale)
  99.     {
  100.         $this->locale $locale;
  101.     }
  102.     /**
  103.      * @param Node $currentNode
  104.      */
  105.     public function setCurrentNode(Node $currentNode null)
  106.     {
  107.         $this->currentNode $currentNode;
  108.     }
  109.     /**
  110.      * @param string $permission
  111.      */
  112.     public function setPermission($permission)
  113.     {
  114.         if ($this->permission !== $permission) {
  115.             // For now reset initialized flag when cached data has to be reset ...
  116.             $this->initialized false;
  117.         }
  118.         $this->permission $permission;
  119.     }
  120.     /**
  121.      * @param bool $includeOffline
  122.      */
  123.     public function setIncludeOffline($includeOffline)
  124.     {
  125.         $this->includeOffline $includeOffline;
  126.     }
  127.     /**
  128.      * @param bool $includeHiddenFromNav
  129.      */
  130.     public function setIncludeHiddenFromNav($includeHiddenFromNav)
  131.     {
  132.         if ($this->includeHiddenFromNav !== $includeHiddenFromNav) {
  133.             // For now reset initialized flag when cached data has to be reset ...
  134.             $this->initialized false;
  135.         }
  136.         $this->includeHiddenFromNav $includeHiddenFromNav;
  137.     }
  138.     /**
  139.      * This method initializes the nodemenu only once, the method may be
  140.      * executed multiple times
  141.      */
  142.     private function init()
  143.     {
  144.         if ($this->initialized) {
  145.             return;
  146.         }
  147.         $this->allNodes = array();
  148.         $this->breadCrumb null;
  149.         $this->childNodes = array();
  150.         $this->topNodeMenuItems null;
  151.         $this->nodesByInternalName = array();
  152.         /* @var NodeRepository $repo */
  153.         $repo $this->em->getRepository('KunstmaanNodeBundle:Node');
  154.         // Get all possible menu items in one query (also fetch offline nodes)
  155.         $nodes $repo->getChildNodes(
  156.             false,
  157.             $this->locale,
  158.             $this->permission,
  159.             $this->aclHelper,
  160.             $this->includeHiddenFromNav,
  161.             true,
  162.             $this->domainConfiguration->getRootNode()
  163.         );
  164.         foreach ($nodes as $node) {
  165.             $this->allNodes[$node->getId()] = $node;
  166.             if ($node->getParent()) {
  167.                 $this->childNodes[$node->getParent()->getId()][] = $node;
  168.             } else {
  169.                 $this->childNodes[0][] = $node;
  170.             }
  171.             $internalName $node->getInternalName();
  172.             if ($internalName) {
  173.                 $this->nodesByInternalName[$internalName][] = $node;
  174.             }
  175.         }
  176.         $this->initialized true;
  177.     }
  178.     /**
  179.      * @return NodeMenuItem[]
  180.      */
  181.     public function getTopNodes()
  182.     {
  183.         $this->init();
  184.         if (!\is_array($this->topNodeMenuItems)) {
  185.             $this->topNodeMenuItems = array();
  186.             // To be backwards compatible we need to create the top node MenuItems
  187.             if (\array_key_exists(0$this->childNodes)) {
  188.                 $topNodeMenuItems $this->getTopNodeMenuItems();
  189.                 $includeHiddenFromNav $this->includeHiddenFromNav;
  190.                 $this->topNodeMenuItems array_filter(
  191.                     $topNodeMenuItems,
  192.                     function (NodeMenuItem $entry) use ($includeHiddenFromNav) {
  193.                         if ($entry->getNode()->isHiddenFromNav() && !$includeHiddenFromNav) {
  194.                             return false;
  195.                         }
  196.                         return true;
  197.                     }
  198.                 );
  199.             }
  200.         }
  201.         return $this->topNodeMenuItems;
  202.     }
  203.     /**
  204.      * @return NodeMenuItem[]
  205.      */
  206.     public function getBreadCrumb()
  207.     {
  208.         $this->init();
  209.         if (!\is_array($this->breadCrumb)) {
  210.             $this->breadCrumb = array();
  211.             /* @var NodeRepository $repo */
  212.             $repo $this->em->getRepository('KunstmaanNodeBundle:Node');
  213.             // Generate breadcrumb MenuItems - fetch *all* languages so you can link translations if needed
  214.             $parentNodes $repo->getAllParents($this->currentNode);
  215.             $parentNodeMenuItem null;
  216.             /* @var Node $parentNode */
  217.             foreach ($parentNodes as $parentNode) {
  218.                 $nodeTranslation $parentNode->getNodeTranslation(
  219.                     $this->locale,
  220.                     $this->includeOffline
  221.                 );
  222.                 if (!\is_null($nodeTranslation)) {
  223.                     $nodeMenuItem = new NodeMenuItem(
  224.                         $parentNode,
  225.                         $nodeTranslation,
  226.                         $parentNodeMenuItem,
  227.                         $this
  228.                     );
  229.                     $this->breadCrumb[] = $nodeMenuItem;
  230.                     $parentNodeMenuItem $nodeMenuItem;
  231.                 }
  232.             }
  233.         }
  234.         return $this->breadCrumb;
  235.     }
  236.     /**
  237.      * @return NodeMenuItem|null
  238.      */
  239.     public function getCurrent()
  240.     {
  241.         $this->init();
  242.         $breadCrumb $this->getBreadCrumb();
  243.         if (\count($breadCrumb) > 0) {
  244.             return $breadCrumb[\count($breadCrumb) - 1];
  245.         }
  246.         return null;
  247.     }
  248.     /**
  249.      * @param int $depth
  250.      *
  251.      * @return NodeMenuItem|null
  252.      */
  253.     public function getActiveForDepth($depth)
  254.     {
  255.         $breadCrumb $this->getBreadCrumb();
  256.         if (\count($breadCrumb) >= $depth) {
  257.             return $breadCrumb[$depth 1];
  258.         }
  259.         return null;
  260.     }
  261.     /**
  262.      * @param Node $node
  263.      * @param bool $includeHiddenFromNav
  264.      *
  265.      * @return NodeMenuItem[]
  266.      */
  267.     public function getChildren(Node $node$includeHiddenFromNav true)
  268.     {
  269.         $this->init();
  270.         $children = array();
  271.         if (\array_key_exists($node->getId(), $this->childNodes)) {
  272.             $nodes $this->childNodes[$node->getId()];
  273.             /* @var Node $childNode */
  274.             foreach ($nodes as $childNode) {
  275.                 $nodeTranslation $childNode->getNodeTranslation(
  276.                     $this->locale,
  277.                     $this->includeOffline
  278.                 );
  279.                 if (!\is_null($nodeTranslation)) {
  280.                     $children[] = new NodeMenuItem(
  281.                         $childNode,
  282.                         $nodeTranslation,
  283.                         false,
  284.                         $this
  285.                     );
  286.                 }
  287.             }
  288.             $children array_filter(
  289.                 $children,
  290.                 function (NodeMenuItem $entry) use ($includeHiddenFromNav) {
  291.                     if ($entry->getNode()->isHiddenFromNav() && !$includeHiddenFromNav) {
  292.                         return false;
  293.                     }
  294.                     return true;
  295.                 }
  296.             );
  297.         }
  298.         return $children;
  299.     }
  300.     /**
  301.      * @param \Kunstmaan\NodeBundle\Entity\Node $node
  302.      * @param bool                              $includeHiddenFromNav
  303.      *
  304.      * @return array|\Kunstmaan\NodeBundle\Helper\NodeMenuItem[]
  305.      */
  306.     public function getSiblings(Node $node$includeHiddenFromNav true)
  307.     {
  308.         $this->init();
  309.         $siblings = array();
  310.         if (false !== $parent $this->getParent($node)) {
  311.             $siblings $this->getChildren($parent$includeHiddenFromNav);
  312.             foreach ($siblings as $index => $child) {
  313.                 if ($child === $node) {
  314.                     unset($siblings[$index]);
  315.                 }
  316.             }
  317.         }
  318.         return $siblings;
  319.     }
  320.     /**
  321.      * @param \Kunstmaan\NodeBundle\Entity\Node $node
  322.      * @param bool                              $includeHiddenFromNav
  323.      *
  324.      * @return bool|\Kunstmaan\NodeBundle\Helper\NodeMenuItem
  325.      */
  326.     public function getPreviousSibling(Node $node$includeHiddenFromNav true)
  327.     {
  328.         $this->init();
  329.         if (false !== $parent $this->getParent($node)) {
  330.             $siblings $this->getChildren($parent$includeHiddenFromNav);
  331.             foreach ($siblings as $index => $child) {
  332.                 if ($child->getNode() === $node && ($index >= 0)) {
  333.                     return $siblings[$index 1];
  334.                 }
  335.             }
  336.         }
  337.         return false;
  338.     }
  339.     /**
  340.      * @param \Kunstmaan\NodeBundle\Entity\Node $node
  341.      * @param bool                              $includeHiddenFromNav
  342.      *
  343.      * @return bool|\Kunstmaan\NodeBundle\Helper\NodeMenuItem
  344.      */
  345.     public function getNextSibling(Node $node$includeHiddenFromNav true)
  346.     {
  347.         $this->init();
  348.         if (false !== $parent $this->getParent($node)) {
  349.             $siblings $this->getChildren($parent$includeHiddenFromNav);
  350.             foreach ($siblings as $index => $child) {
  351.                 if ($child->getNode() === $node && (($index 1) < \count(
  352.                             $siblings
  353.                         ))
  354.                 ) {
  355.                     return $siblings[$index 1];
  356.                 }
  357.             }
  358.         }
  359.         return false;
  360.     }
  361.     /**
  362.      * @param Node $node
  363.      *
  364.      * @return NodeMenuItem
  365.      */
  366.     public function getParent(Node $node)
  367.     {
  368.         $this->init();
  369.         if ($node->getParent() && \array_key_exists(
  370.                 $node->getParent()->getId(),
  371.                 $this->allNodes
  372.             )
  373.         ) {
  374.             return $this->allNodes[$node->getParent()->getId()];
  375.         }
  376.         return false;
  377.     }
  378.     /**
  379.      * @param NodeTranslation $parentNode The parent node
  380.      * @param string          $slug       The slug
  381.      *
  382.      * @return NodeTranslation
  383.      */
  384.     public function getNodeBySlug(NodeTranslation $parentNode$slug)
  385.     {
  386.         return $this->em->getRepository('KunstmaanNodeBundle:NodeTranslation')
  387.             ->getNodeTranslationForSlug($slug$parentNode);
  388.     }
  389.     /**
  390.      * @param string                                        $internalName   The
  391.      *                                                                      internal
  392.      *                                                                      name
  393.      * @param NodeTranslation|NodeMenuItem|HasNodeInterface $parent         The
  394.      *                                                                      parent
  395.      * @param bool                                          $includeOffline
  396.      *
  397.      * @return NodeMenuItem|null
  398.      */
  399.     public function getNodeByInternalName(
  400.         $internalName,
  401.         $parent null,
  402.         $includeOffline null
  403.     ) {
  404.         $this->init();
  405.         $resultNode null;
  406.         if (\is_null($includeOffline)) {
  407.             $includeOffline $this->includeOffline;
  408.         }
  409.         if (\array_key_exists($internalName$this->nodesByInternalName)) {
  410.             $nodes $this->nodesByInternalName[$internalName];
  411.             $nodes array_filter(
  412.                 $nodes,
  413.                 function (Node $entry) use ($includeOffline) {
  414.                     if ($entry->isDeleted() && !$includeOffline) {
  415.                         return false;
  416.                     }
  417.                     return true;
  418.                 }
  419.             );
  420.             if (!\is_null($parent)) {
  421.                 /** @var Node $parentNode */
  422.                 if ($parent instanceof NodeTranslation) {
  423.                     $parentNode $parent->getNode();
  424.                 } elseif ($parent instanceof NodeMenuItem) {
  425.                     $parentNode $parent->getNode();
  426.                 } elseif ($parent instanceof HasNodeInterface) {
  427.                     $repo $this->em->getRepository(
  428.                         'KunstmaanNodeBundle:Node'
  429.                     );
  430.                     $parentNode $repo->getNodeFor($parent);
  431.                 }
  432.                 // Look for a node with the same parent id
  433.                 /** @var Node $node */
  434.                 foreach ($nodes as $node) {
  435.                     if ($node->getParent()->getId() == $parentNode->getId()) {
  436.                         $resultNode $node;
  437.                         break;
  438.                     }
  439.                 }
  440.                 // Look for a node that has an ancestor with the same parent id
  441.                 if (\is_null($resultNode)) {
  442.                     /* @var Node $n */
  443.                     foreach ($nodes as $node) {
  444.                         $tempNode $node;
  445.                         while (\is_null($resultNode) && !\is_null(
  446.                                 $tempNode->getParent()
  447.                             )) {
  448.                             $tempParent $tempNode->getParent();
  449.                             if ($tempParent->getId() == $parentNode->getId()) {
  450.                                 $resultNode $node;
  451.                                 break;
  452.                             }
  453.                             $tempNode $tempParent;
  454.                         }
  455.                     }
  456.                 }
  457.             } elseif (\count($nodes) > 0) {
  458.                 $resultNode $nodes[0];
  459.             }
  460.         }
  461.         if ($resultNode) {
  462.             $nodeTranslation $resultNode->getNodeTranslation(
  463.                 $this->locale,
  464.                 $includeOffline
  465.             );
  466.             if (!\is_null($nodeTranslation)) {
  467.                 return new NodeMenuItem(
  468.                     $resultNode,
  469.                     $nodeTranslation,
  470.                     false,
  471.                     $this
  472.                 );
  473.             }
  474.         }
  475.         return null;
  476.     }
  477.     /**
  478.      * Returns the current root node menu item
  479.      */
  480.     public function getRootNodeMenuItem()
  481.     {
  482.         if (\is_null($this->rootNodeMenuItem)) {
  483.             $rootNode $this->domainConfiguration->getRootNode();
  484.             if (!\is_null($rootNode)) {
  485.                 $nodeTranslation $rootNode->getNodeTranslation(
  486.                     $this->locale,
  487.                     $this->includeOffline
  488.                 );
  489.                 $this->rootNodeMenuItem = new NodeMenuItem(
  490.                     $rootNode,
  491.                     $nodeTranslation,
  492.                     false,
  493.                     $this
  494.                 );
  495.             } else {
  496.                 $this->rootNodeMenuItem $this->breadCrumb[0];
  497.             }
  498.         }
  499.         return $this->rootNodeMenuItem;
  500.     }
  501.     /**
  502.      * @return bool
  503.      */
  504.     public function isIncludeOffline()
  505.     {
  506.         return $this->includeOffline;
  507.     }
  508.     /**
  509.      * @return string
  510.      */
  511.     public function getPermission()
  512.     {
  513.         return $this->permission;
  514.     }
  515.     /**
  516.      * @return BaseUser
  517.      */
  518.     public function getUser()
  519.     {
  520.         return $this->tokenStorage->getToken()->getUser();
  521.     }
  522.     /**
  523.      * @return EntityManagerInterface
  524.      */
  525.     public function getEntityManager()
  526.     {
  527.         return $this->em;
  528.     }
  529.     /**
  530.      * @return TokenStorageInterface
  531.      */
  532.     public function getTokenStorage()
  533.     {
  534.         return $this->tokenStorage;
  535.     }
  536.     /**
  537.      * @return AclHelper
  538.      */
  539.     public function getAclHelper()
  540.     {
  541.         return $this->aclHelper;
  542.     }
  543.     /**
  544.      * @return string
  545.      */
  546.     public function getLocale()
  547.     {
  548.         return $this->locale;
  549.     }
  550.     /**
  551.      * @return bool
  552.      */
  553.     public function isIncludeHiddenFromNav()
  554.     {
  555.         return $this->includeHiddenFromNav;
  556.     }
  557.     /**
  558.      * Check if provided slug is in active path
  559.      *
  560.      * @param string $slug
  561.      *
  562.      * @return bool
  563.      */
  564.     public function getActive($slug)
  565.     {
  566.         $bc $this->getBreadCrumb();
  567.         foreach ($bc as $bcItem) {
  568.             if ($bcItem->getSlug() == $slug) {
  569.                 return true;
  570.             }
  571.         }
  572.         return false;
  573.     }
  574.     /**
  575.      * @return bool
  576.      */
  577.     public function isInitialized()
  578.     {
  579.         return $this->initialized;
  580.     }
  581.     /**
  582.      * @return array
  583.      */
  584.     private function getTopNodeMenuItems()
  585.     {
  586.         $topNodeMenuItems = array();
  587.         $topNodes $this->childNodes[0];
  588.         /* @var Node $topNode */
  589.         foreach ($topNodes as $topNode) {
  590.             $nodeTranslation $topNode->getNodeTranslation(
  591.                 $this->locale,
  592.                 $this->includeOffline
  593.             );
  594.             if (!\is_null($nodeTranslation)) {
  595.                 $topNodeMenuItems[] = new NodeMenuItem(
  596.                     $topNode,
  597.                     $nodeTranslation,
  598.                     null,
  599.                     $this
  600.                 );
  601.             }
  602.         }
  603.         return $topNodeMenuItems;
  604.     }
  605. }