Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony2 - How to implement nested records and recursive functions into Entity Field or Twig Layout?

I have a serious doubt about doing a combo box with nested records from an entity in Symfony2. I have read about nested tree extension for Doctrine 2 in http://gediminasm.org/article/tree-nestedset-behavior-extension-for-doctrine-2, it appears to be interesting but it does not refer how to implementing this nested tree into an entity field in a form.

Also, I have read more about recursive functions in PHP, and I have found an interesting blog where it is analyzed, here is the link http://www.sitepoint.com/hierarchical-data-database/, it explains specifically about this recursive function:

function display_children($parent, $level) {

    // Retrieve all children of $parent
    $result = mysql_query('SELECT title FROM tree WHERE parent="'.$parent.'"');

    // Display each child
    while ($row = mysql_fetch_array($result)) { 

        // Indent and display the title of this child
        echo str_repeat('  ',$level).$row['title']."\n";

        // Call this function again to display this child's children
        display_children($row['title'], $level+1);
    }
}

Somebody knows how to translate this code into Symfony2 and where it would be stored (Controller, Entity, etc.). If someone has other ideas about working nested records with Twig Extensions, It would be appreciate too.

Thanks a lot your help.

like image 723
chineeser Avatar asked Jan 18 '23 14:01

chineeser


2 Answers

This is how we implemented Nested tree for Categories (indented dropdown) for use in Product edit form:

  1. Define your Category entity class as shown in the documentation

  2. Add a method to the Category entity class that shows the name indented by nesting level

    /**
     * @ORM\Table()
     * @ORM\Entity(repositoryClass="CP\YourBundle\Entity\CategoryRepository")
     * @Gedmo\Tree(type="nested")
     */
    class Category
    {
        public function getOptionLabel()
        {
            return str_repeat(
                html_entity_decode(' ', ENT_QUOTES, 'UTF-8'),
                ($this->getLevel() + 1) * 3
            ) . $this->getName();
        }
    
  3. Define Product entity relations with the Category entities using Doctrine2 annotations (in our case we have multiple categories support for one product)

    class Product
    {
        /**
         * @var ArrayCollection
         * @ORM\ManyToMany(targetEntity="Category", cascade={"persist", "remove"})
         */
        private $categories;
        ...
    
  4. Now all you have to do is add the following to the ProductType form class

    class ProductType extends AbstractType
    {
        public function buildForm(FormBuilder $builder, array $options)
        {
            $builder
                ->add('categories', null, array('property' => 'optionLabel'));
        }
    

Now the form should show the dropdown with a correctly indented Category list

like image 164
darklow Avatar answered Jan 20 '23 03:01

darklow


You can have a look to this tree implementation that is not based on nested sets but on materialzed paths: https://github.com/KnpLabs/materialized-path .

You could imagine use its API to get a flat resultset of the tree, like in your code snippet:

$root = $repo->find($id);
$repo->buildTree($root);

$flatArray = $root->toFlatArray(function(NodeInterface $node) {
    $pre = $node->getLevel() > 1 ? implode('', array_fill(0, $node->getLevel(), '--')) : '';
    return $pre.(string)$node;
});

return $this->get('templating')->render('::tree.html.twig', $flatArray);
like image 44
Florian Klein Avatar answered Jan 20 '23 04:01

Florian Klein