Skip to content

Instantly share code, notes, and snippets.

@rybakit
Last active Dec 10, 2015
Embed
What would you like to do?
RybakitNavigationBundle full example
<?php
// Twig/AcmeExtension.php
namespace Acme\DemoBundle\Twig\Extension;
use Symfony\Component\DependencyInjection\ContainerInterface;
class AcmeExtension extends \Twig_Extension
{
private $container;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function getGlobals()
{
return array('nav' => $this->container->get('acme.navigation'));
}
}
<?php
// Navigation/BuildNavigationEvent.php
namespace Acme\DemoBundle\Navigation;
use Symfony\Component\EventDispatcher\Event;
class BuildNavigationEvent extends Event
{
/**
* @var array
*/
private $navigation = array();
/**
* @param string $key
* @param array $navigation
* @param int|null $index
*/
public function addNavigation($key, array $navigation, $index = null)
{
if (!isset($this->navigation[$key])) {
$this->navigation[$key] = array();
}
if (null === $index) {
$this->navigation[$key][] = $navigation;
return;
}
if (isset($this->navigation[$key][$index])) {
array_splice($this->navigation[$key], $index, 0, array($navigation));
} else {
$this->navigation[$key][$index] = $navigation;
}
}
/**
* @param string $key
*
* @return array
*/
public function getNavigation($key)
{
return isset($this->navigation[$key]) ? $this->navigation[$key] : array();
}
}
<?php
// Controller/FooController.php
namespace Acme\DemoBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
class FooController extends Controller
{
/**
* @Template()
*/
public function barAction()
{
// an alternative way to pass a navigation array to a tempate
return array('nav_sidebar' => $this->container->get('acme.navigation.sidebar'));
}
}
<?php
// Navigation/NavigationBuilder.php
namespace Acme\DemoBundle\Navigation;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Routing\RouterInterface;
use Rybakit\Bundle\NavigationBundle\Navigation\Item;
use Rybakit\Bundle\NavigationBundle\Navigation\ItemFactory;
use Rybakit\Bundle\NavigationBundle\Navigation\Filter\BindFilter;
use Rybakit\Bundle\NavigationBundle\Navigation\Filter\FilterChain;
use Rybakit\Bundle\NavigationBundle\Navigation\Filter\MatchFilter;
use Rybakit\Bundle\NavigationBundle\Navigation\Filter\Matcher\RoutesMatcher;
use Rybakit\Bundle\NavigationBundle\Navigation\Filter\UrlFilter;
use Acme\DemoBundle\Navigation\Event\BuildNavigationEvent;
class NavigationBuilder
{
/**
* @var RequestStack
*/
private $requestStack;
/**
* @var RouterInterface
*/
private $router;
/**
* @var EventDispatcherInterface
*/
private $dispatcher;
public function __construct(RequestStack $requestStack, RouterInterface $router, EventDispatcherInterface $dispatcher)
{
$this->requestStack = $requestStack;
$this->router = $router;
$this->dispatcher = $dispatcher;
}
public function buildNavigation()
{
$request = $this->requestStack->getMasterRequest();
$route = $request->attributes->get('_route');
$routeParams = $request->attributes->get('_route_params', array());
$filter = new FilterChain(array(
new UrlFilter($this->router),
$matchFilter = new MatchFilter(new RoutesMatcher($route, $routeParams)),
new BindFilter(),
));
$item = new Item();
$item->transDomain = 'AcmeDemoBundle';
$factory = new ItemFactory($filter, $item);
$nav = array(
'label' => 'home',
'route' => 'acme_home',
'children' => array(
array(
'label' => 'item1',
'route' => 'acme_item1',
),
array(
'label' => 'item2',
'route' => array('acme_item2', array('route_param' => 'value')),
'routes' => array(
'acme_item2_edit',
'acme_item2_update',
array('acme_item2_show', array('page' => 1)),
),
),
'item3' => array(
'label' => 'item3',
'route' => array('acme_item3', array('route_param' => 'value'), true), // generates absolute url
'children' => array(),
),
),
);
// or $nav = Yaml::parse('/path/to/navigation.yml');
$event = new BuildNavigationEvent();
$this->dispatcher->dispatch(NavigationEvents::BUILD, $event);
if ($item3Nav = $event->getNavigation('item3')) {
$nav['children']['item3']['children'] = array_merge(
$nav['children']['item3']['children'],
$item3Nav
);
}
$root = $factory->create($nav);
if (!$current = $matchFilter->getMatched()) {
$current = $root;
}
$current->setActive();
return array('root' => $root, 'current' => $current);
}
<?php
// Navigation/NavigationEvents.php
namespace Acme\DemoBundle\Navigation;
final class NavigationEvents
{
const BUILD = 'acme.navigation.build';
}
<?php
// Navigation/NavigationListener.php
namespace Acme\DemoBundle\Navigation;
use Acme\DemoBundle\Navigation\BuildNavigationEvent;
use Acme\DemoBundle\Navigation\NavigationEvents;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class NavigationListener implements EventSubscriberInterface
{
public function onBuild(BuildNavigationEvent $event)
{
$event->addNavigation('item3', array(
'label' => 'item3.1',
'route' => array('acme_item3_1'),
));
}
public static function getSubscribedEvents()
{
return array(NavigationEvents::BUILD => 'onBuild');
}
}
<!-- Resources/config/services.xml --->
...
<service id="acme.navigation_builder" class="Acme\DemoBundle\Navigation\NavigationBuilder">
<argument type="service" id="request_stack" />
<argument type="service" id="router" />
<argument type="service" id="event_dispatcher" />
</service>
<service id="acme.navigation" class="Rybakit\Bundle\NavigationBundle\Navigation\Item" factory-service="acme.navigation_builder" factory-method="buildNavigation" />
...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment