KnpMenu - JSON Renderer to support Dojo Dijit/Tree
I wrote some code that parsed through the default KNP menu HTML and created a Dijit menu. It worked, but it was slow and awkward.
I couldn't find an easy way to get the KNP menu in the JSON form that would work well with Dijit/Tree, so I wrote my own.
JsonRenderer.php
<?php
namespace AppBundle\Menu;
use Knp\Menu\ItemInterface;
use Knp\Menu\Matcher\MatcherInterface;
use Knp\Menu\Renderer\RendererInterface;
use Translator;
class JsonRenderer implements RendererInterface
{
/**
* @var \Twig_Environment
*/
private $environment;
private $matcher;
private $defaultOptions;
/**
* @param \Twig_Environment $environment
* @param string $template
* @param MatcherInterface $matcher
* @param array $defaultOptions
*/
public function __construct( \Twig_Environment $environment, $template, MatcherInterface $matcher, array $defaultOptions = array() )
{
$this->environment = $environment;
$this->matcher = $matcher;
$this->defaultOptions = array_merge( array(
'depth' => null,
'matchingDepth' => null,
'currentAsLink' => true,
'currentClass' => 'current',
'ancestorClass' => 'current_ancestor',
'firstClass' => 'first',
'lastClass' => 'last',
'template' => $template,
'compressed' => false,
'allow_safe_labels' => false,
'clear_matcher' => true,
'leaf_class' => null,
'branch_class' => null
), $defaultOptions );
}
public function render( ItemInterface $item, array $options = array() )
{
$options = array_merge( $this->defaultOptions, $options );
$translator = $options['translator'];
$itemIterator = new \Knp\Menu\Iterator\RecursiveItemIterator( $item );
$iterator = new \RecursiveIteratorIterator( $itemIterator, \RecursiveIteratorIterator::SELF_FIRST );
$items = [];
foreach( $iterator as $item )
{
$translatedLabel = $translator->trans($item->getLabel());
$id = $item->getName();
$parentId = $item->getParent()->getName();
$itemData = [ 'id' => strtolower( $item->getName() ), 'name' => $translatedLabel, 'uri' => $item->getUri()];
if ($parentId !== $id) {
$itemData['parent'] =strtolower($parentId);
}
$itemData['has_children'] = $item->hasChildren();
$items[] = $itemData;
}
$lastItem = count( $items ) - 1;
$items[$lastItem]['lastItem'] = true;
$html = $this->environment->render( $options['template'], array('items' => $items, 'options' => $options, 'matcher' => $this->matcher) );
if( $options['clear_matcher'] )
{
$this->matcher->clear();
}
return $html;
}
}
Added JsonRenderer as a service in services.yml
app.menu_renderer:
# The class implements Knp\Menu\Renderer\RendererInterface
class: AppBundle\Menu\JsonRenderer
arguments: [ "@twig", "knp_menu.html.twig", "@knp_menu.matcher", {"translator": "@translator" }]
tags:
# The alias is what is used to retrieve the menu
- { name: knp_menu.renderer, alias: json }
I used a twig template (knp_menu.html.twig) to output the JSON, perhaps in the future I will update it to deliver it as a .js file.
var menuTreeStoreData = [{% for item in items%}{{item|json_encode()|raw}}{% if item.lastItem is not defined %},{%endif%}{% endfor %}];
The layout template calls the renderer with this line:
{{ knp_menu_render('admin',{'template': 'admin/parts/knp_menu.html.twig'}, 'json') }}
Finally, this is menu.js which uses the menu data produced by JsonRenderer to create a nice tree for a menu. You could use a different menu approach. I kind of like the tree for now.
define([
"dojo/dom",
"dojo/store/Memory",
"dijit/tree/ObjectStoreModel",
"dijit/Tree",
"dojo/domReady!"
], function (dom,
Memory, ObjectStoreModel, Tree) {
//"use strict";
function run() {
var store = new Memory({data: menuTreeStoreData
,
getChildren: function (object) {
return this.query({parent: object.id});
}});
var model = new ObjectStoreModel({
store: store,
query: {id: 'admin'}
});
// Create the Tree.
var tree = new Tree({
id: "admin-menu",
model: model,
persist: true,
onClick: function (item) {
if( typeof item.uri !== "undefined" && item.uri !== null ) {
location.href = item.uri;
}
},
getIconClass: function (item, opened) {
return (item && item.has_children) ? (opened ? "dijitFolderOpened" : "dijitFolderClosed") : "dijitLeaf"
}
});
tree.placeAt(dom.byId("admin-left-menu"));
tree.startup();
}
return {
run: run
};
});
Print article | This entry was posted by elvis on 10/04/16 at 08:18:00 pm . Follow any responses to this post through RSS 2.0. |