No description, website, or topics provided.
JavaScript PHP
Switch branches/tags
Nothing to show
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.


WORK IN PROGRESS!!! No tests, no hopes.

A Symfony2 bundle to manage those f***ing tree structures!

Depends on



add this to the require section of your composer.json file

    "require": {
        "cypresslab/tree-bundle": "dev-master"

Activate both the CypressTreeBundle and the FOSJsRoutingBundle in you AppKernel class



use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\Config\Loader\LoaderInterface;

class AppKernel extends Kernel
    public function registerBundles()
        // other bundles...

        $bundles[] = new Cypress\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
namespace Cypress\MyBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Cypress\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)
        $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()

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:


            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


<a href="{{ path('admin_menuitems_edit_mongodb', { '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
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);
            return new Response('ok');
        } catch (\Exception $e) {
            return new Response('ko');

    // other actions...

As you can see the controller receive 3 parameters. The id of the moved node ($node), the id of the reference ($ref), and $move: 0 to move before and 1 to move after the reference The controller should returns a Reponse object with 'ok' if everything worked well, or 'ko' for an error.

  • editable_root (boolean) define if the root node of the tree should be editable or not

  • theme the tree theme

  • root_icon and node_icon are the icons to use to represente the root, and the branches of the tree


Now you are ready to display your trees on your twig templates.

  • add the FOSJsRouting js call for sorting the tree. Remember to add it on every page that display a tree.
<script type="text/javascript" src="{{ asset('bundles/fosjsrouting/js/router.js') }}"></script>
<script type="text/javascript" src="{{ path('fos_js_routing_js', {"callback": "fos.Router.setData"}) }}"></script>
  • in the javascript section of your template call the function cypress_tree_javascripts with the name of the tree that you have defined in you config.yml file
{{ cypress_tree_javascripts('my_tree') }}

and in the body of your page call the cypress_tree() function, with the tree name as first argument, and the root node of your tree as the second.

{{ cypress_tree('my_tree', root) }}

And you should see it!

CypressTreeBundle screenshot


If you want to contribute to this bundle (you are my hero) please send the PRs to develop branch!

About recursion

Remember that if you want to learn recursion, you must first learn recursion

The R in RMS stands for RMS