Updated: Comment #33
This issue is to solicit feedback and have discussion on the proposed architecture and the overall implementation proposal (including the interfaces, and code organization). Patches posted here are for that and checking tests, not final review.
Once this the architecture is sufficiently reviewed and discussed, let's mark this fixed and polish the implementation in the following issue: #2256521: [META] New plan, Phase 2: Implement menu links as plugins, including static admin links and views, and custom links with menu_link_content entity, all managed via menu_ui module
see: #2256497: [meta] Menu Links - New Plan for the Homestretch for the big picture
Problem/Motivation
We want both the best site builder experience and best DX.
The menu links in the administrative section and the hierarchy pages built from them serve a different role than most of the user-defined menu link.
We want the admin section to be localized (using t()) so that the administrative section is localized and the localization values can be updated as the .po files are improved on localize.drupal.org
There is a mandate to define the admin links with YAML in parallel with local tasks & local actions, would be consistent DX, and would allow them to be localized.
The menu links created by users should be based on content entities so that we can add fields and use field translation.
The user-created links can be mixed in with the administrative links, so we need a common framework that can manage an optimized hierarchy storage that include both of these. In addition we expect Views and other modules will define additional menu links, so the framework needs to cover those use cases as well.
Proposed resolution
Use a plugin type as the common framework that glues together links defined in YAML, links with an associated content entity, link defined by Views, etc.
Once we have a faux plugin manager from issue #2 giving you the menu hierarchy, convert the links to actual plugins and get all the hierarchy code out of the entity code.
The plugin ID will be the machine name of each link, so all links will now have a machine name.
Need to figure out how to have the custom menu link plugins delegate the edit form, etc to a entity form and then extract out the values needed to hand to the manager to maintain the hierarchy.
This patch is to review the basic machinery of that plugin system. It excludes the changes from phase 2 to existing forms and function to use these plugins, but they are working already with a mix of static plugins, views-backed plugins, and content entity backed plugins.
Remaining tasks
Patch is currently being developed in a sandbox - look there if you want to see the very latest or try out the whole system as per phase 2.
http://drupalcode.org/sandbox/dereine/2031809.git/tree/refs/heads/2227441
git clone --branch 2227441 http://git.drupal.org/sandbox/dereine/2031809.git menutree
User interface changes
Link titles and path will no longer be editable for static menu links.
API changes
Major shift from all content entities to a framework based on Plugins. Custom menu links would represent the combination of a content entity and a plugin instance, in analogy to the custom block module.
Since the static menu link titles and description are define in YAML and not editable, they can be discovered just like local task titles and localized using t() to achieve OOTB localization of the admin interface.
The content entity backing each custom link can be translated using entity translation, so they would have full multilingual support.
Related
#2227179: Step 2: Move the menu tree storage to a separate service.
Follow-up from #2227179: Step 2: Move the menu tree storage to a separate service..
Comment | File | Size | Author |
---|---|---|---|
#97 | 2227441-snapshot-96.patch | 557.93 KB | pwolanin |
#89 | interdiff.txt | 1.44 KB | dawehner |
#82 | Welcome to 2031809.local | 2031809.local 2014-05-22 17-29-36 2014-05-22 17-30-53.png | 171.81 KB | Gábor Hojtsy |
#73 | 2227441-snapshot-73.patch | 558.19 KB | pwolanin |
#60 | 2227441-snapshot-60.patch | 554.94 KB | pwolanin |
Comments
Comment #1
pwolanin CreditAttribution: pwolanin commentedComment #2
jessebeach CreditAttribution: jessebeach commentedComment #3
xjmComment #4
amateescu CreditAttribution: amateescu commentedComment #5
Crell CreditAttribution: Crell commentedWait... what's the justification for this? Didn't we just put a crapton of work into making links entities? Can we please stop confusing plugins and entities? :-)
Comment #6
dawehner@crell
The better place is #2178723-47: [meta-2] Finalize module-facing API of declaring menu links and followed.
Comment #7
pwolanin CreditAttribution: pwolanin commentedComment #8
Gábor HojtsySo would the suggested YML files be hardcoded like local tasks, routes, etc? Ie. not in the config system but as their own YML files?
Also, what would people do if they have a view that has an admin path that they want to ship with? Is it shipping the view with the module? Shipping the view and the YML file manually created somehow? In other words: how do you turn a UI created admin view to an exported view shipped with a module?
Comment #9
Gábor HojtsyAs per @pwolanin the response is the following:
- yes, admin menu items would be static one-off plugin YML like local tasks, routing, etc.
- yes, UI created views would be shippable in modules because Views would have a derivative plugin handler that would expose the views configured admin items, so these would be translatable as part of the View with config translation
These work for translation.
Comment #10
pwolanin CreditAttribution: pwolanin commentedFor views, the data for creating the link will be in the views config entity
Comment #11
Gábor HojtsyThat sounds good to me. @pwolanin and I talked about this yesterday. I think this model matches how blocks are implemented and would be fine for translatability as well as far as I understand. It may not be the nicest solution but it applies a pattern established elsewhere even if that pattern is not the work of perfection.
Comment #12
pwolanin CreditAttribution: pwolanin commentedComment #13
pwolanin CreditAttribution: pwolanin commenteda PoC patch for the 1st part of this is currently being developed in a sandbox:
http://drupalcode.org/sandbox/dereine/2031809.git/tree/refs/heads/2227441
git clone --branch 2227441 http://git.drupal.org/sandbox/dereine/2031809.git menutree
I started on this with dawehner, since it seemed like step #2 would be a really huge effort - equal in size to doing this PoC implementation. At that point, since I'm convinced we want to end up here, it seemed much more effective (and fun) to just start on this step rather than step #2 code that might be thrown away in the end.
Comment #14
pwolanin CreditAttribution: pwolanin commentedComment #15
xjmIf this includes changes to the storage (and I believe it does) then it'd be beta-blocking.
Comment #16
effulgentsia CreditAttribution: effulgentsia commentedJust a patch representation of the current sandbox for people who like that sort of thing. CNR for bot, not humans.
Comment #18
Gábor Hojtsypwolanin asked me to try out their current sandbox user experience. I DID NOT review the code or the approach. Comments:
- That you cannto edit the built-in item title/path is confusing, it shows "Path: Administration" linking to the right place though; adding "This is a module provided link. Label and path cannot be changed." or something along those lines would be good and fixing so the display of it makes more sense.
- Custom menu links have the path field way too down in the form, should be up like in D7, that and title are the primary 2 things about the menu item.
- If you translate a built-in menu item the toolbar regressed that it looses the icon of the item. That is not the case in D8.
- Menu items don't yet have a #language_select element on their form; so although you can configure new entity defaults and language selector visibility for them in language module, it does not actually appear; see admin/config/regional/content-language with language module enabled and other entity types for #language_select use
- Menu link fields title and description appear for translation settings (revisit admin/config/regional/content-language with content translation also enabled) BUT the translation settings cannot be saved on them; other entity types, eg. basic page works
- Then I wanted to go and see how does the menu item show, on trying to manage my menu (ie. not even edit the menu item just displaying the list of menu items on the admin page). I got Fatal error: Call to a member function isTranslatable() on a non-object in /Users/gabor/Web/2031809/core/modules/content_translation/lib/Drupal/content_translation/ContentTranslationManager.php on line 39
- Since now I cannot edit any menu, I went and disabled content translation again. Then I tried moving around the translated menu item to a different place and then different tree position and it still all worked. And it was still translated.
That concluded my quick review. Again I DID NOT review the code or the approach.
Comment #19
Gábor HojtsyThe fatal can be reproduced by just enabling content translation module and then visiting any admin/structure/menu/manage/* no special configuration needed.
Comment #20
pwolanin CreditAttribution: pwolanin commentedThe fatal was due to the use of the '#type' => 'language_configuration' element in the overview form. This is a no-op in HEAD, and not relevant to the patch, so it's removed now in the sandbox which fixes the fatal.
I am having a weird issue on /admin/config/regional/content-language where I can check the checkboxes to enable the menu link translation of title and description, but the setting is not saved. Something funny about the form structure for default fields?
Comment #21
effulgentsia CreditAttribution: effulgentsia commentedJust another patch snapshot for visibility + simplytest.me.
Comment #23
effulgentsia CreditAttribution: effulgentsia commentedTrivial merge fix just to get bot to run.
Comment #25
pwolanin CreditAttribution: pwolanin commentedHere's another patch to see how the tests are doing.
Comment #27
pwolanin CreditAttribution: pwolanin commentedoops, that had setUp() 2x in one changed test.
Comment #29
xjmLooks like #2256497-28: [meta] Menu Links - New Plan for the Homestretch has this as a major.
Comment #30
pwolanin CreditAttribution: pwolanin commentedThis is still critical. In any case, I need to update the summary. We actually far along and will just skip this step unless the committers want to add the new API pieces to core without using them in an initial patch.
Comment #31
pwolanin CreditAttribution: pwolanin commentedAnother snapshot of progress to see test results.
Comment #33
pwolanin CreditAttribution: pwolanin commentedHere's what actually needs review. This is a patch limited to the added classes for the menu link plugin, manager, and storage. Of particular note is the clean separation of concerns between the plugin manager and the tree storage. The latter hides all the details of the hierarchy implementation such as the pN columns or the fact that it's using SQL at all.
The test coverage in the patch is limited to 2 new test since it omits all the exiting tests that are in the process of being converted for phase 2.
Such patch *could* be committed after review, since it doesn't actually change core behavior, however it would as well make sense to commit with all of phase 2.
Here's the diff stat of the patch:
Comment #34
jibranHere is little help to move it fwd.
desc line missing.
$this->menuTree
is not defined in this class.Are we missing something here?
Isn't it "Enable" currently in core instead of "Enable menu link"?
not needed
wrong indentation
is it still pending?
Why are we not using injection here?
desc line missing.
Updates and saves
Can we just reorder them? vendor last and etc.
There are still some missing public functions in this class not defined in interface.
Can we use some better name here?
doc block missing.
Can we move it to the end or start of the function? and Maybe add a comment.
I can't find it on interface.
Can we make it array and then implode?
@todo.
doc blocks missing.
more then 80 chars.
desc missing.
more then 80 chars.
Space missing.
desc missing and space missing.
I think it also returns noting if id in not there.
Gets
doc block missing.
class doc missing.
Executes
@param block missing.
more then 80 chars.
more then 80 chars.
@param block missing.
Loads and @param block missing.
Sets
have we finalized yet?
loads and @param block missing.
doc block missing.
@param block missing.
more then 80 chars.
Checks
desc line missing.
Loads
An array.
desc missing.
saves
Loads
desc line missing.
doc block missing.
doc block missing.
Adds, moves, tests
typehint missng.
desc line missing.
doc block missing.
Comment #35
pwolanin CreditAttribution: pwolanin commentedThanks for the review - I know there is still doc cleanup needed and appreciate having a punch list.
re: making $cid and array and doing implode - this $cid as direct sting concatenation seems to be the norm in core, e.g. in ContentEntityStorageBase
Plus that $cid is basically carried forward from existing HEAD, so I think it's less error-prone to leave it as-is.
Comment #36
victor-shelepen CreditAttribution: victor-shelepen commentedTake my patch to add a link "translate" on the page - admin/structure/menu/manage/main
Comment #37
victor-shelepen CreditAttribution: victor-shelepen commentedComment #38
pwolanin CreditAttribution: pwolanin commented@likin - thanks, looks good on a quick review. I guess you talked to dawehner about this, since he an I discussed this approached yesterday?
Adding that patch to the sandbox too.
Comment #39
dawehnerNope, this is the standard for plugin managers.
PluginManagerInterface => MapperInterface
We just do it like HEAD does it.
Hope, exactly 80
Sorry but the review does not offer enough context. Sadly I can't find which one you need.
Pushed a non-small doc cleanup.
Comment #40
jibranThank you very much for the fixes @dawehner.
I blame dreditor for this. :)
Comment #41
pwolanin CreditAttribution: pwolanin commentedHere's another patch of just the APi additions for review
Comment #42
pwolanin CreditAttribution: pwolanin commentedHere's a snapshot patch of all the work in the branch - let's see how the tests are doing.
Comment #44
pwolanin CreditAttribution: pwolanin commentedoops - a mismatched type hint added during the last bit of cleanup.
Comment #46
pwolanin CreditAttribution: pwolanin commentednote, an earlier version of this fix is included in the patch: #2267753: ContentEntityDatabaseStorage::mapToStorageRecord hard-codes $entity->$name->value
One of several other bugs we've turned up and worked on and fixed. So at least that bit will come out as soon as that patch is committed.
Comment #47
pwolanin CreditAttribution: pwolanin commentedAnd after some cleanup for recent minor refactorings that broke a couple tests.
Comment #49
victor-shelepen CreditAttribution: victor-shelepen commentedIt should fix some tests:
Drupal\shortcut\Tests\ShortcutLinksTest
Drupal\simpletest\Tests\DrupalUnitTestBaseTest
Drupal\toolbar\Tests\ToolbarAdminMenuTest
Comment #50
victor-shelepen CreditAttribution: victor-shelepen commentedComment #54
pwolanin CreditAttribution: pwolanin commented@likin - I don't think the changes to MenuLinkDefault are correct, but the rest looks good and I'll add to the branch.
Comment #55
victor-shelepen CreditAttribution: victor-shelepen commented@pwolanin The main idea MenuLinkDefaut is that we need notify anothers when link is updated. At this case we need notify the module toolbar to pass the test AdminToolbarMenuTest. It needs invokeAll. I tried To implement it according to DIC. So it looks weird.
Comment #56
dawehner@jibran
Fixed some of yours
@likin
I think we should do that in a generic place.
Also merged in some of your fixes.
Comment #58
victor-shelepen CreditAttribution: victor-shelepen commented@dawehner Could you give a git access for the repository?
Comment #59
dawehner@likin
Granted ...
Comment #60
pwolanin CreditAttribution: pwolanin commentedAnother snapshot for tests
Renamed MenuLinkTreeStorage to MenuTreeStorage since it's not specific to links (we could possibly re-factor book manager to use it and kill a bunch of duplicate code)
Still need to add back the language selector to the Menu entity form and figure out why that was causing an error when content_translation was enabled.
In discussion with Wim, it seems we have no test coverage of the $only_active_trail parameter for buildPagedata, so it would be good to add at least a basic check for that.
The get/set active menu names functionality should be moved into the MenuLinkTree class since right now it's calling out to a function in menu.inc.
Comment #62
dawehnerThis time it should be green.
Comment #64
dawehnerSo.
Comment #66
pwolanin CreditAttribution: pwolanin commentedok, clean-up for the work-around for Shortcut while we wait for this to be committed: #2267753: ContentEntityDatabaseStorage::mapToStorageRecord hard-codes $entity->$name->value
Comment #67
catchThat's in now.
Comment #68
pwolanin CreditAttribution: pwolanin commentedActually no - rolled back due conflict with #2190313: Add $EntityType::load() and loadMultiple() to simplify loading entities, but I'm hoping catch will committ again and we'll have to account for that change too
Comment #69
pwolanin CreditAttribution: pwolanin commentedOk, rebased against the fixes and changes.
Comment #70
dawehnerOkay, we need to come up with 40 kb more documentation in order to get a sane size.
@everyone_else
Talk to us so we can help you to help us to review the patch.
Comment #71
victor-shelepen CreditAttribution: victor-shelepen commented@dawehner Describe what help is realy needed.
Comment #72
pwolanin CreditAttribution: pwolanin commented@likin - we ned to go through the new interfaces and classes and make sure all the doxyen is complete and correct, and check e.g. system.api.php to see if there are outdated examples that need to be changed or removed.
Comment #73
pwolanin CreditAttribution: pwolanin commentedHere's another snapshot after accounting for changes to Discoveryinterface and ConfirmFormBase I ran some tests, but let's see if I got them all.
Comment #74
bforchhammer CreditAttribution: bforchhammer commentedI have started looking at the patch. Below are a few things I noticed, and questions of someone who hasn't spent too much time with D8 core yet.
Note, that I have only managed to get through the first 30-40% of the patch; I haven't looked at stuff related to the menu content entity nor any of the tests.
docblock description doesn't seem to match the Interface?
Missing scope ("public").
This interface/service seems to cover quite a few different functionalities:
I'm wondering if some of these could be separated into more interfaces/classes, to make it easier to understand. Not sure about multiple services, but maybe at least separate, single-purpose interfaces (+use of inheritance)?
Seems incomplete. Also missing a dot at the end.
Maybe "rediscover" instead of "rebuild"? In my opinion renaming is not necessary, as long as the docblock is descriptive enough. :)
Missing docblock.
From what I understand, the purpose of the "MenuTreeStorage" is currently two-fold: a) to store information on discovered menu link plugins, and some of their parameters/configuration etc.; and b), to store the hierarchical organization of menu items and to make it easy to quickly query information from that hierarchy.
Reading the class name "MenuTreeStorage", I primarily think of the second part, i.e. the storage of hierarchical info.
I understand that these two "tasks" are currently implemented with one database table for performance reasons, but I think that DX could profit from splitting the interface (and class) into two parts for a) CRUD on "plugin definitions", and b) managing hierarchical information (getParentPath, getParent, getChildren, etc.).
Maybe the CRUD part could be moved to an (abstract?) base class
MenuLinkPluginStorage
, which is extended byMenuTreeStorage
(adding hierarchical things). This would make it easier to replace the materialized path implementation with something else.Incomplete docblock.
I think this method could make things difficult for alternative tree storage implementations because it seems fairly generic; it's not clear which properties are valid and commonly used for querying via this function (to me anyway), so optimising an implementation will likely also be difficult. From what I saw in the patch, this method is only called from the outside with the 'menu_name' property, so maybe it can be removed (or made protected) with the addition of a new "loadByMenuName" method?
There's a "to" missing in the first sentence.
The keyword "internal" somewhat contradicts the fact that it's exposed on a public interface. ;-)
Also, as far as I know the "materialized path" describes a very specific way of storing hierarchical information; so in order to decouple the interface from a specific storage implementation, I think this could be renamed to something like
getParentPath()
, which is more neutral imo.Incomplete docblock.
According to Wikipedia: The depth of a node is the length of the path to its root (i.e., its root path).
Therefore, I think this could just be named
getDepth($id)
.Using
get*
instead offind*
might also be more consistent with other method names; on the other hand, there seems to be quite a few different patterns (load*
,get*
,find*
,count*
, and others), so not sure.newline.
Comment #75
pwolanin CreditAttribution: pwolanin commented@bforchhammer - thanks for the constructive feedback, especially in terms of architecture. There are almost certainly a pile of doxygen to be fixed I know.
So, yes, I'd agree that MenuLinkTreeInterface covers a lot, though splitting the storage out the tree storage actually a good step forward compared to past versions.
One argument for keeping the MenuLinkTree monolithic is that it allows the tree storage to be private to it. If we split it up the tree storage is positioned as more of a public service, which isn't really my intent. Also, much more importantly, there is a subtle optimization that makes splitting it up problematic. In function checkAccess the code does:
That allows us to use each definition loaded with the tree when we later call
The way the plugin factory works, we'd otherwise be making another database query to re-load the individual plugin definition to instantiate it. I suppose we could have this in-memory cache in the tree storage instead, though I was happy to be able to write is as a totally stateless service and leave all the caching to the manager
For the storage I think of it as "tree storage", not just "storage" so I expect it to store data in a way that can be retrieved as a tree. I can't really see the value in in a service that just stories the data and another that stores the tree. Yes, that might be one way to implement this internally, but why embed that in the interfaces? The separation between that and the other code in the manger that manipulates the tree is (I think) already a big step forward in that it's behind an interface, and tries not to leak the details of the tree storage algorithm by only taking in or returns the plugins definition.
Good point about loadByProperties() - at the very least it should be clearly documented to only accept properties that are part of the plugin definition (and enforce that internally). Maybe having specific methods would be better and make it easier to alter the tree storage implementation.
The materialized path value that's return is not implementation specific except, perhaps, in its naming. Happy for better naming suggestions. It's just the list of ancestor IDs leading to the root of the tree. What do you generically call the leaf to root path?
findChildrenRelativeDepth() Is not the actual depth, it's the difference in depth between the link of the given ID and its deepest child. Happy for naming suggestions to clarify that too.
Comment #76
pwolanin CreditAttribution: pwolanin commentedQuick 1st pass at using xhprof for this patch as compared to HEAD (df710a893bef9b60c600b68925edcc49470635b8) both a clean install with drush 7.
Loading /admin/config with a warm cache
HEAD:
Overall Summary
Total Incl. Wall Time (microsec): 726,987 microsecs
Total Incl. CPU (microsecs): 661,783 microsecs
Total Incl. MemUse (bytes): 10,217,828 bytes
Total Incl. PeakMemUse (bytes): 10,284,236 bytes
Number of Function Calls: 62,333
patch:
Overall Summary
Total Incl. Wall Time (microsec): 661,677 microsecs
Total Incl. CPU (microsecs): 615,320 microsecs
Total Incl. MemUse (bytes): 10,126,568 bytes
Total Incl. PeakMemUse (bytes): 10,193,088 bytes
Number of Function Calls: 56,436
Is it useful to post the actual xhprof files?
Comment #77
bforchhammer CreditAttribution: bforchhammer commentedI definitely agree that the separation of storage and "other things" is already a big step forward! :)
Can you elaborate on why it should not be made public? What's the benefit of keeping it private?
(Personally, I wish we had a more generic concept for storing hierarchical content; I do understand that that's out of scope for this issue, but wouldn't making the tree storage public help us go more into that direction?)
Also, I have to admit I don't completely understand how that
checkAccess
optimization works at the moment; I do understand that it helps prevent database queries, but could that not be formalized somehow, i.e. extracted into a separate method? it does not seem to have much to do with "checking access", nor is it mentioned as a side-effect in the docblock at the moment.I think that would be called the "root path" of a given node/leaf.
Sorry, I must have misread the description. I think what you're describing is actually called the "height" of a (sub-)tree.
Wikipedia: "The height of a node is the length of the longest downward path to a leaf from that node. The height of the root is the height of the tree."
---------------
I have read the patch partially from the perspective of a contrib developer, i.e. trying to figure out how to override certain functionality or pieces of code with custom versions. One example of something which contrib developers have wanted to adjust in D7, is the code surrounding the active trail/preferred menu item; I'm wondering how I would override the logic of
getActiveTrailIds()
andmenuLinkGetPreferred()
with the patch in D8?Comment #78
pwolanin CreditAttribution: pwolanin commentedSo, since getActiveTrailIds() is just the path to root of the preferred link, there is nothing to override there. Rather, menuLinkGetPreferred() is a possible place to override.
Note, however, that compared to D7, none of this affects the breadcrumb, which was a major motivation before for overriding the active trail.
Comment #79
Bojhan CreditAttribution: Bojhan commentedThis sounds like a good idea, we already have similar concepts in core - and this kind of stuff creates a lot of WTF's when you are translating. As long as its easy to overwrite in the code, when you do want to change it - it should all be fine.
Let me know when there is a UI issue, I'd like to make sure we provide a very understandable help text.
Comment #80
pwolanin CreditAttribution: pwolanin commentedI was just discussing with Bojhan in IRC. For for context for others: In terms of UX, we want to preserve the ability to localize module-provided links
There can be many variants of link plugin present in the same menu: http://screencast.com/t/tBggPZkoe
In this patch, we have a mix of content and static-module provided ones (and ones provided by views, but those are rare)
for some links you can edit anything since they are content: http://screencast.com/t/Uxaj7il3o2
others are partially locked since they are statically defined with localized strings: http://screencast.com/t/AYftCPIy
Discussing with actual site-builders and others, I think editing the module-provided admin links is a rare use case. You can replace it with a content link if needed.
Also, site builders are used to different edit forms having different fields (e.g. 2 different node types), so this is unsurprising.
Comment #81
Gábor HojtsyYeah there are 3 ways to translate those menu items and in fact 3 UIs. I don't think that is a show-stopper, we also advocated introducing the basic functionality at least for translation and then contrib can ease the flow. Eg. blocks have the same problem, module provided blocks are translated as UI strings (eg. who is online block) while content blocks are translated as content entities BUT both of their titles are on the config entity and translated as configuration. So that is also a 3-way translation intersection for blocks. This is not really different for menus. That is where contribs like TMGMT will shine. If we'd consider this a showstopper, then even low level translation support would not be there which affects contribs very negatively because they will not assume translatable things and not interoperate with them.
I think we should probably a look a bit at how views provided items will be translated. I should in fact try that. :) Because you can translate the menu title as config translation on the view but does that end up in the menu display?
Comment #82
Gábor HojtsyThis translation test turned out to be a bit different in result than what I was expecting.
1. So the default main nav menu has a module provided Home link that is not editable. That is translatable with the locale UI. That works.
2. I created a custom menu item (content entity). Configured it to be translatable and translated the title. It shows up translated in the admin summary translation table of the entity. NOT in the menu though.
3. I created a menu item via the views UI with a page display. Then enabled config translation and translated the menu item there. This worked flawlessly showing the translated menu item as I expected.
When I switched back to my original English, it worked fine also. So the content translation translated menu item does not end up in the rendered menu:
It is of course confusing to translate these, only the content one has a direct translate tab in the menu UI. I don't think this is anywhere more complex than blocks which even combine different methods of translation in one object's different properties. Here it is "just" different object per object. So I don't think this is a desired UI overall but it is how the technology works and we accepted similar confusion for blocks and pushed that to contrib to improve the UI. Would be similar here. Solving the translation itself in core is crucial for contrib collaboration though.
Comment #83
pwolanin CreditAttribution: pwolanin commented@Gabor. Thanks for the review.
I'm pretty sure the same code is running in the admin overview and for the link rendering in the menu. We are asking the loaded entity for the label. Any idea where this could be going wrong?
@bforchammer- when I say I want the tree storage to be private I only mean this instance. If another module wanted to use it, it should define a different service that stored data in a different table. Probably the default for the table same should be removed.
Comment #84
effulgentsia CreditAttribution: effulgentsia commentedI read (some parts less thoroughly than others) through the patch, and overall, like it a lot, and think it's a huge improvement in terms of architecture and code relative to HEAD. While per #74.3, MenuLinkTree is ridiculously monolithic, I don't think it's any more monolithic than HEAD's MenuTree and menu.inc functions that it's replacing.
My biggest concern with the patch is this:
Not just 'title', but the plugin instance to entity proxy in general. Can we get xhprof and db query comparison of patch vs HEAD for rendering a menu with many content links?
Comment #85
dawehner@effulgentsia
Previously $menu_link['title'] caused a __get call so I can't really imagine how the new code could be much slower than the old one. It is one call to this function per rendered menu link.
Comment #86
Gábor Hojtsy@pwolanin: ok, well, so a fundamental difference between content entities and config entities is config entities are always loaded with overrides in the page's language and you need to work to NOT load them translated. For content entities, it is the other way around. For some reason. If you would know the language you would use getTranslation($langcode) on the entity. But since you don't know and want to use the language negotiation/fallback system, you would use the entity manager, so
$this->entityManager->getTranslationFromContext($entity);
(I see you already have the entity manager injected). More docs on Drupal 8 entity translation API at https://drupal.org/node/2040721Comment #87
effulgentsia CreditAttribution: effulgentsia commentedRe #85: but at what point is the entity loaded? Does it benefit from a loadMultiple()?
Comment #88
pwolanin CreditAttribution: pwolanin commentedIt does not try to multiload now. We were more focused on the first step of maki nine none of
Hue links on admin pages use an entity.
The menu link content entity is loaded when you first need the title or something else from the actual entity.
Comment #89
dawehner@effulgentsia
Really good point. Previousyl MenuTree::doBuildTree() had that multi oading. I do agree 100% that this would be a critical regression,
much like #2250315: Regression: Bring back node access optimization to menu trees is at the point, but noone reviewed it yet.
I wonder how to best provide this functionality. Technically this certainly does not belong into the storage but in the rendering kind of code. We could throw some event
so other modules can work on the tree. An alternative could be to collect the plugin IDs per plugin class and call some static method. Any oppinions?
@gabor
Pushed a new version, see the interdiff. Is it just me or should cache_context.language be added to pretty much everything? Output most always have either a t() or some entity translation involved.
Comment #90
Gábor Hojtsy@dawehner: yeah in your case the menu item is possibly translated with one of these methods: (1) content entity translation for custom menu items (2) t() for static module shipped items (3) config translation for views provided items. So all items may be language dependent somehow.
Comment #91
dawehner@Gábor
Well, I talk about all possible blocks. Basically all of them should have some sort of translation involved in some step, when they generate the content.
Comment #92
Gábor Hojtsy@dawehner #91: yup!
Comment #93
pwolanin CreditAttribution: pwolanin commented@dawehner - since core won't be shipping any entity-backed links, I guess we could debate how critical a problem it would be for the initial patch.
In particular, it might mean re- organizing the code that does the access check, since I think we get the title there to make a new array key so the links are ordered by the localized or translated title.
I'd prefer to do that in a follow-up, but probably depends how catch feels about it.
Comment #94
pwolanin CreditAttribution: pwolanin commentedDiscussed multi-load of MenuLinkContent entities with catch and alexpott in IRC today. Both agreed we could do that in a follow-up since it should not involve any API changes, just internal reorganization of the code flow in the manager potentially.
quoted with permission from IRC:
Comment #95
pwolanin CreditAttribution: pwolanin commentedComment #96
effulgentsia CreditAttribution: effulgentsia commentedI'll be bold here and mark this issue fixed, and suggest that the next patch should be posted to #2256521: [META] New plan, Phase 2: Implement menu links as plugins, including static admin links and views, and custom links with menu_link_content entity, all managed via menu_ui module, where detailed reviews can proceed. If anyone has remaining concerns about the architecture in general, please reopen this issue so we can discuss them, but IMO, we're ready to move on to detailed reviews in that issue.
Also, resetting priority to match the parent issue.
Comment #97
pwolanin CreditAttribution: pwolanin commentedThere were some minor conflicts in HEAD, here's a re-rolled snapshot patch including dawehner's change to make the links properly translated.
Moving any further patches to the #2 issue