lazyants/dynatree-bundle
A PHP bundle that integrates the Dynatree jQuery tree widget, letting you render hierarchical, checkbox-enabled trees with minimal setup.
First, a reality check on fit. lazyants/dynatree-bundle is a Symfony 2 bundle, not a Laravel package — there is no service provider, no facade, no config/dynatree.php. It wraps the long-abandoned jquery.dynatree.js plugin (itself superseded by Fancytree around 2014). With 1 star and 0 dependents, treat it as reference source code, not a dependency. Concretely: a Laravel developer should read this repo to understand the integration shape (asset wiring + AJAX node endpoint + JSON contract), then reimplement ~100 lines of it against Fancytree in Laravel. Do not composer require this into an application you intend to maintain.
If you are nonetheless working inside a legacy Symfony 2 app that already uses it:
composer require lazyants/dynatree-bundle (expect to pin to old Symfony 2.x constraints and possibly add "minimum-stability": "dev").app/AppKernel.php: new LazyAnts\DynatreeBundle\LazyAntsDynatreeBundle().jquery.dynatree.js, its CSS, and the icon sprites land in web/bundles/: php app/console assets:install web --symlink.DependencyInjection/Configuration.php — the only real API surface (default tree options, asset toggles).Resources/views/ — the Twig template(s) and how the container <div> plus init <script> are emitted.Resources/public/js/ — whether it ships the plugin itself or expects you to provide it.First use case: a checkbox tree for category/permission selection. Render the container, initialize with checkbox: true, selectMode: 3, let the user tick nodes, serialize selected keys into a hidden input on submit, and read the array server-side.
Asset inclusion. Symfony 2 bundles of this vintage typically assume Assetic or a raw <script src="{{ asset('bundles/lazyantsdynatree/js/jquery.dynatree.js') }}">. Verify the exact bundle alias (lowercased, no underscores) by listing web/bundles/ after install rather than guessing.
AJAX lazy loading (the pattern worth stealing). The valuable part of any dynatree integration is the node JSON contract. Dynatree expects an array of objects like:
[{ "title": "Root", "key": "1", "isFolder": true, "isLazy": true, "children": [] }]
In Laravel, the equivalent of the bundle's controller action is a route that accepts ?key=<parentId|root> and returns that shape:
Route::get('/tree/nodes', function (Request $request) {
$parentId = $request->query('key') === 'root' ? null : $request->query('key');
return Category::where('parent_id', $parentId)
->get()
->map(fn ($c) => [
'title' => $c->name,
'key' => (string) $c->id,
'isFolder' => $c->children()->exists(),
'isLazy' => $c->children()->exists(),
]);
});
Then $("#tree").dynatree({ initAjax: { url: "/tree/nodes", data: { key: "root" } } }); — or the Fancytree equivalent (source:).
Form round-trip. Dynatree has no native form input. The reliable pattern is a hidden <input type="hidden" name="categories[]" id="category-ids"> updated on onSelect/onDeselect by walking tree.getSelectedNodes() and mapping .data.key. In Laravel, validate it as 'categories' => ['array'], 'categories.*' => ['integer', 'exists:categories,id'] — always re-validate server-side, since the keys are client-supplied strings.
Persisting state on reload. On page load, pass back previously saved keys via select: [...] in the init options (dynatree accepts an array of keys) — but only for nodes already loaded; with lazy loading you must expand ancestors first or use visit() after onPostInit.
Twig/Balde integration. The bundle's template is a thin wrapper; in Blade the equivalent is @include('partials.dynatree', ['id' => 'category-tree', 'options' => $options]) with a @push('scripts') block for init. Keep the init script out of the partial so page-specific options can be injected.
Configuration.php tree semantics, and the app/console CLI all predate Symfony 3/4 Flex. It will not drop into a modern Symfony app, let alone Laravel, without rewriting the DI layer.selectMode: 3, checkbox, initAjax → source).'10' == '010' style surprises in loose comparisons). Cast explicitly on both sides and compare with === in JS.selectMode semantics. 1 = single, 2 = multi, 3 = multi + hierarchical (selecting a parent selects descendants). Mode 3 is what most people actually want for permission trees, and it's also what makes server-side persistence tricky — decide whether you store only leaf selections and derive parents, or store everything.assets:install, hard-refresh; Symfony 2's Assetic can serve stale combined files. If icons render as blank boxes, the CSS is referencing sprite paths relative to the bundle's public/ directory — check the network tab for 404s on icons.gif/skin-*.png.$.ui.dynatree.debug(...); enable with debugLevel: 2 in the init options. Most "tree doesn't render" issues are an empty children: [] combined with isLazy: true — dynatree interprets that as "loaded, no children" and never fires the AJAX request.app/Resources/LazyAntsDynatreeBundle/views/, and adjust defaults through the bundle's config.yml key. There are no events, no DI tags, no plugin hooks of its own — do not plan around extensibility.How can I help you explore Laravel packages today?