# Tree - Nestedset behavior extension for Doctrine 2
**Tree** nested behavior will implement the standard Nested-Set behavior
on your Entity. Tree supports different strategies and currently the alternative
to **nested-set** can be **closure-table** tree. Also this behavior can be nested
with other extensions to translate or generated slugs of your tree nodes.
Features:
- Closure tree strategy, may be faster in some cases where ordering does not matter
- Support for multiple roots in nested-set
- No need for other managers, implementation is through event listener
- Synchronization of left, right values is automatic
- Can support concurrent flush with many objects being persisted and updated
- Can be nested with other extensions
- Annotation, Yaml and Xml mapping support for extensions
[blog_reference]: http://gediminasm.org/article/tree-nestedset-behavior-extension-for-doctrine-2 "Tree - Nestedset or Closure extension for Doctrine 2 makes tree implementation on entities"
[blog_test]: http://gediminasm.org/test "Test extensions on this blog"
Thanks for contributions to:
- **[comfortablynumb](http://github.com/comfortablynumb) Gustavo Adrian** for Closure strategy
- **[everzet](http://github.com/everzet) Kudryashov Konstantin** for TreeLevel implementation
- **[stof](http://github.com/stof) Christophe Coevoet** for getTreeLeafs function
Update **2011-05-07**
- Tree is now able to act as **closure** tree, this strategy was refactored
and now fully functional. It is much faster for file-folder trees for instance
where you do not care about tree ordering.
Update **2011-04-11**
- Made in memory node synchronization, this change does not require clearing the cached nodes after any updates
to nodes, except **recover, verify and removeFromTree** operations.
Update **2011-02-08**
- Refactored to support multiple roots
- Changed the repository name, relevant to strategy used
- New [annotations](#annotations) were added
Update **2011-02-02**
- Refactored the Tree to the ability on supporting diferent tree models
- Changed the repository location in order to support future updates
**Notice:**
- You can [test live][blog_test] on this blog
- After using a NestedTreeRepository functions: **verify, recover, removeFromTree** it is recommended to clear EntityManager cache
because nodes may have changed values in database but not in memory. Flushing dirty nodes can lead to unexpected behaviour.
- Closure tree implementation is experimental and not fully functional, so far not documented either
- Public [Tree repository](http://github.com/l3pp4rd/DoctrineExtensions "Tree extension on Github") is available on github
- Last update date: **2011-08-08**
**Portability:**
- **Tree** is now available as [Bundle](http://github.com/stof/StofDoctrineExtensionsBundle)
ported to **Symfony2** by **Christophe Coevoet**, together with all other extensions
This article will cover the basic installation and functionality of **Tree** behavior
Content:
- [Including](#including-extension) the extension
- [Attaching](#event-listener) the **Tree Listener**
- Entity [example](#entity)
- [Yaml](#yaml) mapping example
- [Xml](#xml) mapping example
- Basic usage [examples](#basic-examples)
- Build [html tree](#html-tree)
- Advanced usage [examples](#advanced-examples)
## Setup and autoloading {#including-extension}
If you using the source from github repository, initial directory structure for
the extension library should look like this:
...
/DoctrineExtensions
/lib
/Gedmo
/Exception
/Loggable
/Mapping
/Sluggable
/Timestampable
/Translatable
/Tree
/tests
...
...
First of all we need to setup the autoloading of extensions:
$classLoader = new \Doctrine\Common\ClassLoader('Gedmo', "/path/to/library/DoctrineExtensions/lib");
$classLoader->register();
### Attaching the Tree Listener to the event manager {#event-listener}
To attach the **Tree Listener** to your event system:
$evm = new \Doctrine\Common\EventManager();
$treeListener = new \Gedmo\Tree\TreeListener();
$evm->addEventSubscriber($treeListener);
// now this event manager should be passed to entity manager constructor
## Tree Entity example: {#entity}
**Notice:** that Node interface is not necessary, except in cases there
you need to identify entity as being Tree Node. The metadata is loaded only once then
cache is activated
namespace Entity;
use Gedmo\Mapping\Annotation as Gedmo;
use Doctrine\ORM\Mapping as ORM;
/**
* @Gedmo\Tree(type="nested")
* @ORM\Table(name="categories")
* use repository for handy tree functions
* @ORM\Entity(repositoryClass="Gedmo\Tree\Entity\Repository\NestedTreeRepository")
*/
class Category
{
/**
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue
*/
private $id;
/**
* @ORM\Column(name="title", type="string", length=64)
*/
private $title;
/**
* @Gedmo\TreeLeft
* @ORM\Column(name="lft", type="integer")
*/
private $lft;
/**
* @Gedmo\TreeLevel
* @ORM\Column(name="lvl", type="integer")
*/
private $lvl;
/**
* @Gedmo\TreeRight
* @ORM\Column(name="rgt", type="integer")
*/
private $rgt;
/**
* @Gedmo\TreeRoot
* @ORM\Column(name="root", type="integer", nullable=true)
*/
private $root;
/**
* @Gedmo\TreeParent
* @ORM\ManyToOne(targetEntity="Category", inversedBy="children")
* @ORM\JoinColumn(name="parent_id", referencedColumnName="id", onDelete="SET NULL")
*/
private $parent;
/**
* @ORM\OneToMany(targetEntity="Category", mappedBy="parent")
* @ORM\OrderBy({"lft" = "ASC"})
*/
private $children;
public function getId()
{
return $this->id;
}
public function setTitle($title)
{
$this->title = $title;
}
public function getTitle()
{
return $this->title;
}
public function setParent(Category $parent = null)
{
$this->parent = $parent;
}
public function getParent()
{
return $this->parent;
}
}
### Tree annotations: {#annotations}
- **@Gedmo\Mapping\Annotation\Tree(type="strategy")** this **class annotation** is used to set the tree strategy by **type** parameter.
Currently **nested** or **closure** strategy is supported
- **@Gedmo\Mapping\Annotation\TreeLeft** it will use this field to store tree **left** value
- **@Gedmo\Mapping\Annotation\TreeRight** it will use this field to store tree **right** value
- **@Gedmo\Mapping\Annotation\TreeParent** this will identify this column as the relation to **parent node**
- **@Gedmo\Mapping\Annotation\TreeLevel** it will use this field to store tree**level**
- **@Gedmo\Mapping\Annotation\TreeRoot** it will use this field to store tree**root** id value
## Yaml mapping example {#yaml}
Yaml mapped Category: **/mapping/yaml/Entity.Category.dcm.yml**
---
Entity\Category:
type: entity
repositoryClass: Gedmo\Tree\Entity\Repository\NestedTreeRepository
table: categories
gedmo:
tree:
type: nested
id:
id:
type: integer
generator:
strategy: AUTO
fields:
title:
type: string
length: 64
lft:
type: integer
gedmo:
- treeLeft
rgt:
type: integer
gedmo:
- treeRight
root:
type: integer
nullable: true
gedmo:
- treeRoot
lvl:
type: integer
gedmo:
- treeLevel
manyToOne:
parent:
targetEntity: Entity\Category
inversedBy: children
joinColumn:
name: parent_id
referencedColumnName: id
onDelete: SET NULL
gedmo:
- treeParent
oneToMany:
children:
targetEntity: Entity\Category
mappedBy: parent
## Xml mapping example {#xml}