Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Tree Bundle Laravel Package

antoinemineau/tree-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install Dependencies:

    composer require stof/doctrine-extensions-bundle sonata-project/admin-bundle redcode/tree-bundle
    

    Ensure StofDoctrineExtensionsBundle and SonataAdminBundle are properly configured.

  2. Enable Nested Set Behavior: Add Gedmo\Tree\TreeableTrait to your entity and configure the TreeExtension in config.yml:

    stof_doctrine_extensions:
        orm:
            default:
                tree: true
    
  3. Create a Tree Entity:

    use Gedmo\Mapping\Annotation as Gedmo;
    
    class Category
    {
        use TreeableTrait;
    
        // Your fields...
    }
    
  4. Extend Admin Class:

    use RedCode\TreeBundle\Admin\AbstractTreeAdmin;
    
    class CategoryAdmin extends AbstractTreeAdmin
    {
        protected $baseRouteName = 'category';
        protected $baseRoutePattern = 'category';
    }
    
  5. Register Admin as Service:

    app.admin.category:
        class: AppBundle\Admin\CategoryAdmin
        arguments: [~, AppBundle\Entity\Category, AppBundle:CategoryAdmin, 'name']
        tags:
            - {name: sonata.admin, manager_type: orm, group: Content, label: Category}
    
  6. Clear Cache:

    php bin/console cache:clear
    

First Use Case

Display a hierarchical category tree in Sonata Admin with drag-and-drop functionality. The tree loads asynchronously, making it suitable for large datasets.


Implementation Patterns

Workflow Integration

  1. Tree Configuration:

    • Use AbstractTreeAdmin to inherit tree-specific behaviors (e.g., configureTree(), configureFormFields()).
    • Override getTreeField() to specify the field displayed in the tree (e.g., 'name').
  2. Customizing Tree Behavior:

    • Extend TreeAdminController to modify tree actions (e.g., moveNodeAction, deleteNodeAction).
    • Example:
      class CategoryAdminController extends TreeAdminController
      {
          public function moveNodeAction(Request $request, $id, $leftId, $position)
          {
              // Custom logic before moving nodes
              return parent::moveNodeAction($request, $id, $leftId, $position);
          }
      }
      
  3. Form Field Customization:

    • Use configureFormFields() to add/remove fields or customize their behavior:
      protected function configureFormFields(FormMapper $formMapper)
      {
          $formMapper
              ->add('name', 'text')
              ->add('parent', 'sonata_type_model', [
                  'required' => false,
                  'by_reference' => false,
                  'class' => 'AppBundle\Entity\Category',
              ]);
      }
      
  4. Tree-Specific Actions:

    • Leverage built-in actions like move, delete, or create via Sonata’s CRUD interface.
    • Add custom actions in configureListFields() or configureTabMenu():
      protected function configureListFields(ListMapper $listMapper)
      {
          $listMapper
              ->add('name')
              ->add('_action', 'actions', [
                  'actions' => [
                      'move' => [],
                      'delete' => [],
                  ],
              ]);
      }
      
  5. Asynchronous Loading:

    • The bundle automatically handles lazy-loading of tree nodes via jsTree’s AJAX capabilities.
    • Customize the data provider in getTreeData() if needed:
      protected function getTreeData($id = null)
      {
          $queryBuilder = $this->getModelManager()->createQueryBuilder('o');
          return $queryBuilder->getQuery()->getResult();
      }
      

Gotchas and Tips

Pitfalls

  1. Nested Set Behavior Conflicts:

    • Ensure your entity only uses Gedmo\Tree\TreeableTrait for hierarchical data. Mixing with other tree behaviors (e.g., MaterializedPath) may cause inconsistencies.
    • Fix: Remove conflicting traits or extensions.
  2. Parent-Child Relationships:

    • The parent field in your entity must be of type Category (or your entity class) and annotated with @Gedmo\TreeParent.
    • Fix: Add the annotation and ensure the field is properly typed:
      /**
       * @Gedmo\TreeParent
       */
      protected $parent;
      
  3. Routing Conflicts:

    • The bundle adds routes under /admin. Ensure no other bundles or custom routes conflict with:
      • redcode_tree_move_node
      • redcode_tree_delete_node
    • Fix: Adjust route prefixes or clear cache if issues arise.
  4. Tree Field Misconfiguration:

    • The arguments array in the admin service must include the tree field name (4th argument). Omitting it breaks the tree display.
    • Fix: Always specify the field (e.g., 'name'):
      arguments: [~, AppBundle\Entity\Category, AppBundle:CategoryAdmin, 'name']
      
  5. Asynchronous Loading Issues:

    • If nodes fail to load, verify:
      • The getTreeData() method returns valid data.
      • The TreeExtension is enabled in config.yml.
    • Fix: Debug with dd($this->getTreeData()) or check Symfony logs.

Debugging Tips

  1. Enable Doctrine Debugging: Add to config.yml to log tree queries:

    doctrine:
        orm:
            logging: true
    
  2. Check jsTree Console Errors: Open browser dev tools (F12) and inspect the Network tab for failed AJAX requests to /admin/redcode_tree/....

  3. Validate Entity Metadata: Run:

    php bin/console doctrine:schema:validate
    

    Ensure the TreeableTrait is recognized.

  4. Clear Cache Aggressively: After changes, run:

    php bin/console cache:clear --env=prod
    php bin/console cache:pool:clear cache.apcu
    

Extension Points

  1. Custom Tree Templates: Override the default jsTree template by extending the bundle’s Resources/views/CRUD/tree.html.twig:

    {% extends 'RedCodeTreeBundle:CRUD:tree.html.twig' %}
    {% block tree_js %}
        {{ parent() }}
        <script>
            // Custom jsTree initialization
        </script>
    {% endblock %}
    
  2. Add Custom Node Metadata: Extend getTreeData() to include additional fields in the tree response:

    protected function getTreeData($id = null)
    {
        $queryBuilder = $this->getModelManager()->createQueryBuilder('o');
        $queryBuilder->select('o', 'partial o.{id, name, lft, rgt, level}');
        return $queryBuilder->getQuery()->getResult();
    }
    
  3. Integrate with Sonata Blocks: Use the tree in a Sonata block by extending Sonata\BlockBundle\Block\BlockContextInterface and embedding the tree via:

    {{ render(url('redcode_tree_tree', {'id': node.id})) }}
    
  4. Add Bulk Actions: Extend the configureListFields() to include bulk tree operations:

    $listMapper->add('_action', 'actions', [
        'actions' => [
            'bulk_move' => ['template' => 'RedCodeTreeBundle:CRUD:bulk_move.html.twig'],
        ],
    ]);
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
comsave/common
alecsammon/php-raml-parser
chrome-php/wrench
lendable/composer-license-checker
typhoon/reflection
mesilov/moneyphp-percentage
mike42/gfx-php
bookdown/themes
aura/view
aura/html
aura/cli
povils/phpmnd
nayjest/manipulator
omnipay/tests
psr-mock/http-message-implementation
psr-mock/http-factory-implementation
psr-mock/http-client-implementation
voku/email-check
voku/urlify
rtheunissen/guzzle-log-middleware