A Symfony2 bundle to manage those tree structures!
This is a new version of the symfony 2.x bundle: CypressTreeBundle of Matteosister.
add this to the require section of your composer.json file
{
"require": {
"wd/tree-bundle": "dev-master"
}
}
Activate both the CypressTreeBundle and the FOSJsRoutingBundle in you AppKernel class
app/AppKernel.php
<?php
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Config\Loader\LoaderInterface;
class AppKernel extends Kernel
{
public function registerBundles()
{
// other bundles...
$bundles[] = new Wd\TreeBundle\CypressTreeBundle();
$bundles[] = new FOS\JsRoutingBundle\FOSJsRoutingBundle();
return $bundles;
}
}
You have a php class (an entity, a document, or anything else) and you want it to be a part of a tree structure. For this example let's consider a Doctrine ORM entity with the Tree extension enabled from the awesome gedmo repository. Here is a full configuration tutorial
- Add the TreeInterface to the class
<?php
namespace Wd\MyBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Wd\TreeBundle\Interfaces\TreeInterface;
/**
* MenuItem Document
*
* @ORM\Entity(repositoryClass="Vivacom\CmsBundle\Repositories\ORM\MenuItemRepository")
* @Gedmo\Tree(type="nested")
*/
class MenuItem implements TreeInterface {
/**
* @var MenuItem
*
* @ORM\ManyToOne(targetEntity="MenuItem", inversedBy="children")
* @ORM\JoinColumn(onDelete="CASCADE")
* @Gedmo\TreeParent
*/
private $parent;
/**
* var ArrayCollection
*
* @ORM\OneToMany(targetEntity="MenuItem", mappedBy="parent", cascade={"all"})
* @ORM\OrderBy({"lft" = "ASC"})
*/
private $children;
/**
* Constructor
*/
public function __construct()
{
$this->children = new ArrayCollection();
}
/**
* add a MenuItem as children
*
* @param MenuItem $menuItem the children page
*/
public function addChildren(MenuItem $menuItem)
{
$menuItem->setParent($this);
$this->children[] = $menuItem;
}
/**
* Children setter
*
* @param \Doctrine\Common\Collections\ArrayCollection $children la variabile children
*/
public function setChildren($children)
{
$this->children = $children;
}
/**
* Children getter
*
* @return \Doctrine\Common\Collections\ArrayCollection
*/
public function getChildren()
{
return $this->children;
}
/**
* Parent setter
*
* @param \Vivacom\CmsBundle\Document\MenuItem $parent the parent property
*/
public function setParent($parent)
{
$this->parent = $parent;
}
/**
* Parent getter
*
* @return \Vivacom\CmsBundle\Document\MenuItem
*/
public function getParent()
{
return $this->parent;
}
}
TreeInterface define one method that you MUST implement: getChildren()
<?php
namespace Cypress\TreeBundle\Interfaces;
/**
* Interface for trees
*/
interface TreeInterface
{
/**
* returns a in iteratable object of children
*
* @abstract
* @return mixed
*/
function getChildren();
}
We already have it in the class as a getter for the children property. You could use any class, as far as you implement TreeInterface, and define the getChildren method.
Now define your trees in the config.yml file. Here is a complete reference:
app/config/config.yml
cypress_tree:
trees:
my_tree:
label_template: "MyAwesomeBundle:Menu:item_label.html.twig"
controller: "MyAwesomeBundle:Menu"
editable_root: false
theme: default # or default-rl, classic, apple
root_icon: 'bundles/cypresstree/images/database.png'
node_icon: 'bundles/cypresstree/images/folder.png'
Under the trees section you define every tree that you need for your application. Pick a name that means something to you. For every tree you define:
- label_template: A twig template that gets a node variable with the object of the current tree
src/MyAwesomeBundle/Resources/views/Menu/item_label.html.twig
<a href="{{ path('admin_menuitems_edit_mongodb', { 'id': node.id }) }}">{{ node }}</a>
- controller: Use the short notation to define a Controller to handle the tree sorting actions. The controller should implements the TreeControllerSortableInterface which requires you to define the function sortNodeAction($node, $ref, $move); method Here is an example with Doctrine orm entities
<?php
namespace Cypress\MyAwesomeBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;
use Cypress\TreeBundle\Interfaces\TreeControllerSortableInterface;
class AdminController extends Controller implements TreeControllerSortableInterface
public function sortNodeAction($node, $ref, $move)
{
try {
$repo = $this->get('doctrine.orm.entity_manager')->getRepository('Cypress\MyAwesomeBundle\Entity\MenuItem');
$moved = $repo->findOneBy(array('id' => $node));
$reference = $repo->findOneBy(array('id' => $ref));
$moveAfter = $move == 1;
if (!$moveAfter) {
$repo->persistAsPrevSiblingOf($moved, $reference);
} else {
$repo->persistAsNextSiblingOf($moved, $reference);
}
$this->getEM()->flush();
return new Response('ok');
} catch (\Exception $e) {
return new Response('ko');
}
}
// other actions...
}