solidcloud/solid-menu-bundle
A menu bundle for SolidCloud applications that helps define, organize, and render navigational menus through a simple, configurable API. Useful for adding structured site navigation to PHP projects while keeping menu logic reusable and easy to maintain.
SolidMenuBundle is a thin Symfony bundle that ships Twig rendering themes for KnpMenuBundle. It does not replace KnpMenu — it layers presentation on top of it, so the day-to-day workflow is KnpMenu’s workflow plus a set of ready-made templates.
Minimum steps:
composer require solidcloud/solid-menu-bundle
composer require knplabs/knp-menu-bundle
config/bundles.php:
return [
Knp\Bundle\MenuBundle\KnpMenuBundle::class => ['all' => true],
Solid\MenuBundle\SolidMenuBundle::class => ['all' => true],
];
php bin/console debug:container --tag=twig.loader.namespaced_paths
php bin/console debug:twig | grep -i -A2 solid
You should see a Twig namespace (commonly @SolidMenu) registered by the bundle. That namespace is where every theme template lives.Where to look first: vendor/solidcloud/solid-menu-bundle/src/Resources/views/ (or templates/). This is your ground truth for theme names, block structure, and CSS class assumptions — there is no published API surface beyond these templates.
First use case — a top nav:
// src/Menu/MainMenuBuilder.php
namespace App\Menu;
use Knp\Menu\FactoryInterface;
use Knp\Menu\ItemInterface;
final class MainMenuBuilder
{
public function __construct(private FactoryInterface $factory) {}
public function build(): ItemInterface
{
$menu = $this->factory->createItem('root');
$menu->addChild('Home', ['route' => 'app_home']);
$menu->addChild('Admin', ['uri' => '/admin']);
return $menu;
}
}
# config/services.yaml
App\Menu\MainMenuBuilder:
tags: [{ name: knp_menu.menu_builder, method: build, alias: main }]
{# templates/base.html.twig #}
{{ knp_menu_render('main', {
'template': '@SolidMenu/theme/bootstrap.html.twig'
}) }}
If that renders nothing, the bundle is working but the template name is wrong — list the actual templates with find vendor/solidcloud/solid-menu-bundle -name '*.twig'.
Builder services, not config. Treat SolidMenu purely as the view layer. Keep menus in MenuBuilder services tagged knp_menu.menu_builder with an alias. This gives you DI (URL generators, security checks, request stack) and is far more testable than YAML menu definitions.
Theme selection three ways, pick one and stay consistent:
template in the options array (best for one-off pages).knp_menu.renderer.twig.options.template in config/packages/knp_menu.yaml — set this to a SolidMenu theme and every menu inherits it.Runtime theme switching for multi-tenant or admin/frontend split:
// a listener or controller concern
$theme = $this->isAdmin ? '@SolidMenu/theme/admin.html.twig'
: '@SolidMenu/theme/site.html.twig';
Pass it through Twig globals rather than hardcoding in every template — one config/packages/twig.yaml entry and done.
Extend, don’t copy. The SolidMenu theme files are built on KnpMenu’s knp_menu.html.twig block structure (root, list, item, label, linkElement, children, attributes, compressed, spanElement). Override only the blocks you need:
{% extends '@SolidMenu/theme/bootstrap.html.twig' %}
{% block item %}
{# add a badge or icon before delegating to the parent #}
{{ parent() }}
{% endblock %}
This keeps you upgrade-safe. Copying the whole theme into templates/ is the single most common way teams get stuck when KnpMenu bumps block names.
Bootstrap/markup integration. SolidMenu themes typically emit Bootstrap-style <ul class="nav"> structures with active/current classes driven by KnpMenu’s currentClass, ancestorClass, and firstClass/lastClass options. Set these on the root item ($menu->setChildrenAttribute('class', 'nav flex-column')) rather than in the theme, so the menu remains reusable across skins.
Testing — render the menu builder in isolation:
$menu = $builder->build();
$this->assertSame('Home', $menu->getChild('Home')->getLabel());
Then a single functional test hitting a page that renders a theme catches template breakage from upgrades.
composer.json ("solidcloud/solid-menu-bundle": "1.*") and be prepared to fork — it’s MIT and small, so forking is often cheaper than waiting on a fix.knplabs/knp-menu-bundle and menus render bare or throw Block "X" not defined, the SolidMenu theme is stale against the new block names. Fix by extending and overriding, or by pinning KnpMenu until you fork.@SolidMenu namespace not found almost always means the bundle wasn’t registered (or was registered after Twig in a misconfigured bundles.php). bin/console debug:twig | grep -i solid is the 5-second diagnostic.php bin/console cache:clear (and cache:pool:clear cache.app in prod-like environments) before you start debugging a change that “didn’t apply”.route lazily at render time; a typo in route: app_home produces neither an exception nor an item. Cross-check with bin/console debug:router | grep app_home.uri vs route matters for the current class. uri-based items often don’t get currentClass applied the way route-based items do, because KnpMenu matches on the matched route name. Prefer route wherever possible.AuthorizationCheckerInterface and calling $menu->removeChild(...), not with Twig {% if %} around knp_menu_render — otherwise you get empty <ul> wrappers and broken first/last classes.$menu->addChild('menu.home', ['route' => ...]) works out of the box because the theme passes labels through the trans filter by default in most KnpMenu themes — verify in vendor/.../theme/*.twig before relying on it.config/packages/twig.yaml → paths:) with a project-local themes/ directory and extend SolidMenu’s theme from there. That isolates all your presentation tweaks to one folder and makes the eventual fork/replacement a one-line config change.depth, matchingDepth, leaf_class) aren’t documented, read the template — it’s 30 lines and tells you exactly which KnpMenu render options it consumes.How can I help you explore Laravel packages today?