Problem/Motivation
#1757452: Support config entities in entity reference fields added config entities back into the selection here, after this was deliberately taken out in #1801304: Add Entity reference field taken out of the UI since the initial ER pach didn't support config entities. This leads to completely silly lists of possible things to reference like this:

Here you have your "90% case" stuff (Content, Users, Files, etc.) buried hopelessly in amongst a bunch of "1% or less case" stuff like "Editor" and "Text format" and "Breakpoint group." This needs to be fixed, because it makes what's already a challenging field to use about 600x more difficult.
Proposed resolution
Introduce a mechanism for grouping entity type labels (and, generally, plugins) and use it to provide a better UI experience through <optgroup> elements.
Remaining tasks
None.
User interface changes
The proposed change can be seen in comment #45.
API changes
A GroupablePlugin trait is introduced and implemented by the entity type plugins. It can also be used by all plugins which require some sort of grouping capability.
Original report by @webchick
A few parts from the OP have been moved to the updated issue summary.
Here are some possible directions:
1) Get those options out of the UI once again. Leave referencing config entities something only code can do.
2) If that's deemed too limiting, then at the very least, let's add some <optgroups> to separate content from config, so the "90% case" stuff is grouped together and at the top, and the others can be safely ignored unless there are advanced use cases.
3) Other?
And, in any event, that list desperately needs to be alphabetized. Makes no sense that Content is 7/8 of the way down the list, after "Menu link."
| Comment | File | Size | Author |
|---|---|---|---|
| #68 | Screen Shot 2014-05-11 at 12.04.40 PM.png | 34.59 KB | webchick |
| #66 | interdiff.txt | 643 bytes | amateescu |
| #66 | 2116551-66.patch | 9.11 KB | amateescu |
| Screen Shot 2013-10-20 at 11.47.39 PM.png | 120.07 KB | webchick |
Comments
Comment #1
jibranWe need an issue for breadcrumbs too.
Comment #2
xanoAt the very least, this will take care of the sorting.
I have a solid use case for keeping configuration entities in the UI, or at least partly. Payment's payment content entities contain a reference to payment method configuration entities. At the moment this is still an integer field as I haven't had the time to convert it to an entity reference yet, but when I convert this, configuration through the UI would allow people to easily change the widget or the formatter.
Comment #3
webchickJibran: Dang, I didn't even see that breadcrumb bug, good call. :\
Xano: Thanks for the patch. That sounds like a use case for exposing widget/field configuration on locked fields, if they're not already (but afaik they are?). But that's not a use case to expose all config entities as possible reference type choices in the UI for user-constructed fields.
Comment #4
Bojhan commentedI would go for 2). Do we have any sensible groupings we can get from elsewhere? For example our top level "Structure", "Content", "People", "Configuration" ?
Comment #5
berdirWe only have two groups, Content and Configuration.
Comment #6
renat commentedAgree with Xano and Bojhan, it would be very nice to have all types of items to reference in the UI. But probably it will not be that difficult to make it's visibility configurable somewhere in Configuration window? By default all that "1% or less case" stuff will be hidden, but those guys who need it - and, hence understand what it is - will be able to to make it visible.
Comment #7
shameemkm commentedHow about having a more option which would lead to additional options with in the list?
Comment #8
swentel commentedHere's using optgroups, works fine for me.
Comment #9
xanoEverywhere else we check whether the class implements ConfigEntityInterface/ContentEntityInterface.
Also, this patch does not sort the labels.
Comment #10
xanoComment #11
swentel commentedWhat a horrible way of checking that :/
Comment #12
xanoAFAIK we require entities to either implement ContentEntityInterface or ConfigEntityInterface. It's not very pretty, but it's consistent with the rest of core. Besides that, the config prefix is a storage controller setting, so we cannot use that outside the ConfigStorageController scope.
Comment #14
amateescu commentedThis will conflict with the translation of the node entity label, which is also 'Content'. We need to specify a context here, and preferably the same for Configuration.
Comment #15
amateescu commentedAnother option would be to introduce a new entity info key and group on that. Something like
group_label_that_makes_sense_for_humans = @Translation("You don't need to worry about these").We are already introducing this pattern for block categories.
Edit: An alternative name for the new key would be 'category' :)
Comment #16
berdirYes, I was thinking about introducing groups/types too. Because there will be more than just those two in Contrib, I have e.g. modules that expose remote data as entities, those won't be config nor content, so it would be great if I could put them in my own group.
Another thing I briefly discussed with @dawehner was to support multiple annotation classes, that don't do anything else other than provide sane defaults for a given type/group of entity types. e.g. @ConfigEntityType and @ContentEntityType. wouldn't really be extendable to my custom group, though. If it works at all...
Comment #17
Bojhan commented@Berdir Could you expand on that a little. What other groups should we support by default? (Media, Product?)
Comment #18
berdirThere are no other groups to support by default. But using an extensible group system instead of a config/content flag makes it easy for contrib to group themself by whatever they want.
Comment #19
webchickLet's maybe do that as a follow-up cos it sounds like a can of worms... it would introduce yet another categorization system in addition to blocks and modules.
For the purposes of closing this one (or at least reducing it from major to normal), the screenshot in #8, coupled with some alphabetization would work for me.
Thanks a lot for jumping on this!
Comment #20
yched commentedI think there is an issue somewhere that intends to do the same for field types - e.g structure the list of available field types with optgroups (Text, Number, List, File...). This seems like a common (if not generic) and very reasonable need : structure an otherwise flat list of available plugin implementations for a given plugin type.
Not saying this should necessarily be moved up to the plugin system, but at least we should try to unify implementations for the plugin types where we add this.
Comment #21
fagoAgreed. In Rules 7.x I've been doing a 'group' key with arbitrary label, seems to me as good fit here as well.
I've another use-case, when integrating with remote systems and exposing their data as entities and makes a lot of sense to group them. E.g. we've been using remote entities to integrate with twitter (see fluxtwitter), grouping the different twitter entities (tweets, users, lists,..) below a "Twitter" or similar category would be helpful here.
Comment #22
jibranAdded #2147685: Fields settings page breadcrumb is not correct for issue reported in #1.
Comment #23
webchickThat's now committed, but the main issue here, which is that site builders are visually assaulted with tons of options that are completely meaningless in 90+% of cases is not.
Comment #24
webchickSorry, that was probably snarkier than I should've said it.
I'm just frustrated, because removing config entities from the list was one of the commit blockers for the initial ER patch due to this UX issue, and then somehow they sneaked back in again without this ever being addressed. :(
Comment #25
webchickComment #26
amateescu commentedSince I'm "they"..
Comment #27
xanoAs far as I know config entities were never part of the list, because they were not technically supported. @amateescu and I added support for them a few months ago.
Comment #28
amateescu commentedHere's a new approach which adds a generic a
GroupablePlugintrait and uses it for entity types.Comment #30
amateescu commentedThis should fix it.
Comment #31
cameron tod commentedThis looks really good.
Comment #32
swentel commentedSo, should we also introduce 'Other' - or something a like a put Menulink under that one ? It seems so lonely there at the top :)
Comment #33
aspilicious commentedI agree with swentel :)
That also would move menu link to the bottom. Makes more sense anyway...
Comment #34
aspilicious commentedHmmm the list is not alphabetically...
I would love to see this order:
- Content
- Config
- Other
Comment #35
cameron tod commentedAdd an "Other" category, and sorted alphabetically by group label. The popup looks a little weird due to their being a lot of options above the default...I think its an improvement though.
Comment #37
berdirI wouldn't worry too much about menu link specifically, converting it to a content entity is a beta blocker. Contrib could have entities that are other, so having a general group is useful.
And IMHO, Content is way more important in that last. Not sure what to do there. It would IMHO be more important to sort the actual labels alphabetically, not the groups. You might think they are at first, but if you look closer, you can see that the only sorting there is the module/provider those entity types are in. Action for example is one the last config entities, because it's in system.module.
Content > Content is also pretty stupid, but I really have no idea to solve that, there are multiple issues already about the naming problems with Node/Entity/Content. Using Content made sense in Drupal 7 core, but it's becoming weirder and weirder, with node.module being optional and a lot of things now being Content (entities).
The only idea that I have there, and that would also eliminate the need for an Other group is to special case the Content group and add them (and possibly entities that are not Content like MenuLink right now too) without a group, before any of the groups.
Yes, this would require more code within ER, but it's something that might be worth it for better DX?
This issue might also provide a solution for #2194783: Rename EntityTypeInterface::isSubclassOf() to ::entityClassImplements() then, so that we could check for a specific group instead of an interface. I'm not sure if that is a better API than the current two suggestions there (isContent()/isConfig() or check the entity type class/interface) though. But it would be extensible, which both of those two aren't (contrib can't add a isMyGroup() or a MyGroupEntityType).
Edit: Also, re order, quoting from the issue summary: "so the "90% case" stuff is grouped together and at the top". So that agrees with my opinion above. I would argue that not grouping the 90% case at all and keeping them at the top still kind of qualifies as "grouped together" :)
Comment #38
cameron tod commentedUpdated to sort labels as well as group labels. I am not so sure on using ksort - I suspect this will not sort internationalized strings (UTF-8) correctly.
I could look at special casing the Content group but it maybe feels a little hacky.
We probably need a test for group labels in addition to EntityManagerTest::testGetEntityTypeLabels(). While fixing the test fail, I noticed that $this->entityManager->getEntityTypeLabels() returns nothing on a second or subsequent calls - is this a mocking thing?
Comment #39
webchickWe definitely need to special-case the content category in some way. That is the 90% case, so it needs to be at the top. Un-grouping sounds fine.
Comment #40
cameron tod commentedComment #41
cameron tod commentedNot so sure on this...but it's something.
Comment #43
cameron tod commentedWoops
Comment #44
Bojhan commentedThat looks afwul, why can't we just special case that group to be on top?
Comment #45
cameron tod commentedOK.
This will only float Content types to the top if grouping is specified. It does look much nicer :)
Comment #46
webchickLovely. :)
Comment #47
yched commentedkeeps the problem of "Content > Content", though.
Comment #48
berdirThis doesn't sort the labels, it sorts the keys?
Should probably sort on the label, using a callback function? So that the order also makes sense if labels are translated.
Should we set Other somewhere else, for example in the EntityType parent annotation class, or the EntityManger, when processing found plugins? Otherwise, Other would just exist for this list...
What exactly is the point of the trait, it doesn't seem to be used as we define it manually here?
@yched: Discussed with @Bojhan, he is apparently not worried about that.
Comment #49
amateescu commentedComment #50
tim.plunkettI thought we couldn't use the translate method like this, and needed to have t()/$this->t()
Comment #51
amateescu commentedLike this?
Comment #52
moshe weitzman commented51: 2116551-entity_reference_ux-51.patch queued for re-testing.
Comment #53
moshe weitzman commentedStill green . Could someone update issue summary? I think we can go to RTBC after that.
Comment #54
amateescu commentedRerolled and updated the issue summary
Comment #55
moshe weitzman commentedI reviewed the code and and issue summary and both look good. Bot is happy so lets do this.
Comment #56
yoroy commentedGood stuff, so yes, lets do this
Comment #57
webchickSorry, no longer applies. Also, using traits for this seemed a bit overblown so I talked to Tim and he had some thoughts.
Comment #58
tim.plunkettFirst, I think we decided to suffix these with "Trait".
That said, we have attempted to decouple "Plugins" from "Annotations", at least where possible. There are annotation classes with Plugin in the name, and EntityType currently extends one, but that might not be true for long.
So I'm not too keen on the naming here. And I don't necessarily think a trait is even a big help here. I appreciate the push for something generic, but I think this could be better served as a part of EntityType directly.
Isn't this supposed to be an error?
http://3v4l.org/t3aS0
Comment #59
amateescu commentedOk, removed the trait. No interdiff because the patch didn't apply.
Comment #60
tim.plunkettWhat's the reason for doing this here and not on the actual EntityType subclass?
This could just be $this->t('Other') and let the subclasses fight it out. Same goes for group I guess.
Comment #61
amateescu commented1. Isn't this how we provide defaults?
2. That would force a new WhateverEntityType to override this method for no reason, when it could use this code from the parent. Why would we do that?
Comment #62
amateescu commentedAny other concerns? :)
Comment #63
wim leersI can only find one nitpicky thing to complain about. Manually tested and works correctly.
Shouldn't this use the recently added
StringTranslationTraitinstead?See #2079797: Provide a trait for $this->t() and $this->formatPlural().
Same here.
And here.
Comment #64
amateescu commentedHere we go :) Thanks for the review!
Comment #66
amateescu commentedMissed one.
Comment #67
wim leersComment #68
webchickAhhhh! Much better! :) Thanks so much, all!!
Committed and pushed to 8.x. W00t!
Comment #70
moshe weitzman commentedNice!. What are the best follow-ups here? Shall we change the taxonomy reference to an entity reference. What about the User field on nodes? Or the roles field on user entity.
Comment #71
xanoThe UID field on nodes uses entity reference already. Term references are preconfigured entity references. For roles there is #2044859: Convert user roles to entity_reference_field.
Comment #73
Chris Charlton+1
Comment #74
tim.plunkettThis added getGroup() and getGroupLabel() to EntityType with no docs and no interface backing them. Opened a follow-up.
#2549017: Add getGroup() and getGroupLabel() to an interface and add docs