code (e.g. sidebar) can have many Menu database rows. Each row carries an optional context — a JSON key-value map (e.g. {"partnerId": 1, "operatorId": 1}) stored in the attributes column. At render time you pass an ordered list of context objects; the bundle tries each one in turn and returns the first row whose (code, context) matches.
How context sets work
You pass a context set: an ordered list of context objects, from most specific to least specific. The bundle iterates through the list and returns the firstMenu row that matches code + context. The final element is usually {} or null to catch the fallback row.
An empty context (
{}) or null matches the fallback row — the Menu row created with no context. This is the default menu for that code when no more-specific variant exists.Canonical context key
The uniqueness of each row is enforced by theattributes_key column, which stores the result of Menu::canonicalContextKey():
{"b":1,"a":2} and {"a":2,"b":1} produce the same key and are treated as the same context.
Twig
PasscontextSets as the third argument to dashboard_menu_tree() and dashboard_menu_config():
contextSets, the bundle defaults to [null, []] — it tries the no-context row first (effectively: no tenant filtering).
JSON API
Send the context sets as the_context_sets query parameter — a JSON-encoded array of objects:
_context_sets is:
_locale parameter overrides the request locale independently of context resolution.
Resolution walkthrough
Receive the context sets
The tree loader receives
contextSets (or defaults to [null, []]). It passes the list to the MenuRepository.Query for matching menu
The repository iterates through the context sets and issues a query for each one:
SELECT ... FROM dashboard_menu WHERE code = :code AND attributes_key = :key. The first query that returns a row wins.Fall back to no-context
If none of the specific contexts match, passing
{} or null as the last entry matches the row with attributes_key = '' (the fallback menu).Load items and build tree
Once the correct
Menu row is found, the items are loaded for that menu ID and assembled into the tree. See Tree structure.Setting context on a Menu row
When you create or update aMenu entity in code, use setContext() — this automatically updates the contextKey:
Common patterns
- Single-tenant (no context)
- Partner-level variation
- Operator + partner variation
When you have one menu per code and no tenant variation, you do not need context sets at all. The bundle defaults to the fallback row: