-
Notifications
You must be signed in to change notification settings - Fork 48
prevent KnpMenu from loading the entire menu/route/content tree #19
Comments
Basically the menu item needs the content item and the route item to generate the proper link for the menu. The content actually ties together the menu and the routes, so as long as the whole menu tree is created as KnpMenu does currently everything is pulled from the repository. In my small application I have only little content (actually only two menus with 5 and 4 nodes) and I use ESI caching. While at first I thought having hundreds of menu items is nothing that makes sense I remembered an application we did (not with the cmf) which had about 200 to 300 items ... But with that many items I guess your only chance is really caching the complete menu - if you use some sort of highlighting the current item you end up with 200 - 300 cache entries but this is still much better than handling so many objects on each request and generating the routes for the object - not tested but I think even with a menu in code you burn some cycles just generating the urls ... KnpMenu first builds the menu and then renders the menu. Building the menu involves generating the url and therefore loading content objects and route objects (look at Knp\Menu\MenuFactory::createFromNode and Symfony\Cmf\MenuBundle\ContentAwareFactory::createItem). So even with optimizations in KnpMenu you can easily have use cases with lots of menu items and you need to cache the menu. |
Ah ok I get it now. So as part of building the menu graph, KnpMenu will need to generate the uri etc of all nodes that could possibly appear in the tree. So it seems the only solution would be a totally rewrite of KnpMenu, where it explicitly would only build those parts of the menu graph that will actually be displayed. Obviously when building a sitemap it would then still touch everything, but that is ok in that case since everything is going to be displayed. @stof: so the gist of this is I guess is that if you have a large menu graph (especially one that isnt hardcoded), its imperative to also support a mode that only loads the parts of the tree that will be displayed. hopefully its not too late to handle this approach in 2.0. @petesiss: so i fear for now the only solution is ESI caching. @uwej711: for ESI caching I guess it would also be helpful if one could generate a version of the menu for each depth level without any active tab and then simple make the given tab active from outside of the ESI block. |
@lsmith77 I'm want to work on it, indeed. I will look at it tomorrow (I spent today on symfony itself as you noticed) |
@petesiss: couldn't you create another menu with less entries for the regular pages and one with all for the site map? |
@uwej711 I can see that would help, but not sure how practical it is given it would need to be managed seamlessly still by clients with the CMS. Will have a think... In general, does it make sense to continue with a data structure where the content nodes are required to build the menu? Surely it should be possible to have all required properties in the menu and route nodes? That alone would potentially reduce lookups by 30%. |
The idea in the first place is to have menu, routes and content separated to make things flexible. I think it would be possible to have the menu items reference the routes directly but not sure what change that means for the routing stuff (currently the router can create an url for content, if we change this structure, i.e. have menu reference routes, the router will also have to be able to generate routes from route items, which should be possible). But caching would be your best bet anyway I guess ... |
@uwej711 how do you deal with setting current in your cached menu fragments? |
I created a controller with a parameter currentUri, Now in the template I generate the currentUri with the twig path function and pass it to the render call:
|
yep, the idea of generating the route from content was to avoid redundancy. we have 3 things that are together, and if we had them all cross-reference storing updates would become very tricky. simplecms bundle stuffs everything together, for single lang pages with simple menu structures, its probably the best (aka most efficient) solution. that said, menu items can also store the route but i think they currently prefer the content if they have it. |
I have previously solved this type of problem by caching the dynamic application routes in a flat array, just like symfony does (or has done). So that when the menu is rendered it doesn't need to do any DB lookups for generating the menu item routes. Would something like that fix this problem? |
I have 2 questions related to this issue:
|
well i think there will be cases where its needed. however 1) it should be an option 2) it should stop reading once it has found something .. right now it just reads the entire tree .. always. |
@lsmith77 Yeah. I have an idea to avoid loading all the tree (unless you actually need to render it of course). but these are the 2 cases I see where the optimization would break. For the second case, even if it stops reading the tree when it founds something, it could still need to load everything in case the curent item is the last one found when traversing the tree. Of course, this second case is not relevant in case you don't display a breadcrumb, but I think it is a common need for the CMF. |
@lsmith77 I imagine you're thinking about the https://github.com/KnpLabs/KnpMenu/blob/master/doc/01-Basic-Menus.markdown#other-rendering-options |
@Nek- no, though this might help. with KnpMenu 1.x even if you specified a depth, it still read the entire tree to render. ie.
this would still end up reading the entire menu tree into memory, which is fine if the tree is defined in a yaml file maybe but not if it comes from the database. |
The builder is defined by you (the user of KnpMenuBundle) and you can pass some options as third parameter by using the Why not using an option of depth ? |
Another solution could be to create a MenuProxyItem that will be activated only when the item need theses children. But IMO the best solution is to create a big query to retrieve all the menu. In facts all this solutions are not KnpMenu related. But choose one and I will try to help or make a PR. |
see https://groups.google.com/forum/?fromgroups=#!topic/symfony-cmf-devs/ikJ9jpomzaQ and https://groups.google.com/forum/?fromgroups=#!topic/symfony-cmf-devs/otAht7VS04Y
i have classified this as a bug as it makes it impossible to use our menu bundle in larger setups.
i was able to reproduce this issue. it doesnt really cause a lot of problems with a few nodes, but obviously if you start having a large tree, then its a big issue.
we need to investigate this .. i am not yet sure if it just loads content/routes that are referenced in the menu or if it just flat out loads everything. i would doubt that.
potentially its impossible to prevent loading all the menu items with KnpMenu 1.x, but can hopefully ensure that at least route/content nodes are lazy loaded. i dont know the menu system that well yet.
@uwej711 you havent run into this issue yet?
@petesiss's app is suffering severely because of this, even with node caching enabled
@dbu i could come by fribourg the second half of next week if necessary.
The text was updated successfully, but these errors were encountered: