Problem/Motivation
The same way we have getPassword() and getEmail() which return the raw values, I would expect getUsername() to follow the same logic, and not return a formatted user name.
Simpletest for example is under the assumption that getUsername() return the value used to log in a user (the username) when it in fact returns the formatter user name (aka real name). See #1929420-22: $account->getDisplayName() should be used when outputing username in RDF module for an example where this fails.
Moreover, the user edit form uses getUsername() as default value for the username field, and getUsername() can potentially be altered (e.g. realname module)
Proposed resolution
Align getUsername() with getPassword() and getEmail() and return the raw username value (used to login for example). Use getDisplayName() to get the formatted user name.
Remaining tasks
change record
User interface changes
none
API changes
getUsername() returns the raw/db username. getDisplayName() returns the formatted user name.
Related Issues
Beta phase evaluation
| Issue category | Bug because the API is not consistent with other get*() methods. |
|---|---|
| Issue priority | Critical because if a module implements hook_user_format_name() and changes the display output of the user name the account edit form causes data loss and could break login |
| Unfrozen changes | Unfrozen because it a bug. |
| Disruption | Disruptive for core/contributed and custom modules/themes because it will require widespread changes. |
| Comment | File | Size | Author |
|---|---|---|---|
| #236 | 2112679-236.patch | 45.4 KB | dawehner |
| #236 | interdiff.txt | 1.76 KB | dawehner |
| #232 | getusername_should-2112679-232.patch | 589 bytes | nlisgo |
| #232 | interdiff-2112679-230-232.txt | 589 bytes | nlisgo |
| #230 | interdiff.txt | 5.61 KB | dawehner |
Comments
Comment #1
scor commentedComment #2
berdirNot sure. getUsername() *is* the replacement for user_format_name().
Most use cases in core use it like that. If we change it, then we need to provide an alternative. Or, provide a new method to get the raw name, where appropriate.
getUsername() is the same as label() (user specific vs. entity generic, like getTitle() and label() on nodes), which *always* returned the formatted username. This is the one to use in most cases, so I think it should be the default.
Comment #3
scor commentedThat might be the way you coded it, but all I'm saying is that from a DX perspective, the above is not intuitive, at least not for someone like me who didn't participate in the design of getUsername().
IMO something like getFormattedName() or getName() is more intuitive for a replacement of user_format_name(). getUsername() gives no hint that what you get back might not be the username, but something that a module might have made up. If you are looking to align it with node's getTitle(), then calling it getName() makes sense:
Comment #4
scor commenteduser_label() was removed, so this code should be moved to user_format_name() now. user_format_name() should not return $entity->getUsername() directly, but instead pass it throughthe module handler alter function.
Comment #5
krlucas commented@scor and I talked to @moshe weitzman and he agreed that getUsername should return the user's unique log in name and that another method should return the display name. Most of core and contrib should call getDisplayName but getting access to the value needed for log in seems legit.
This patch adds a getDisplayName method to the AccountInterface and updates the method to UserSession class and User entity class.
Comment #7
blueminds commentedFixed failed tests, added test coverage.
Comment #8
blueminds commentedforgot to update comment user name
Comment #9
berdirWeird wrapping, the last part shouldn't be on a separate line.
Patch looks good, but I think we need to review the current usage of getUsername() and change to getDisplayName() wherever we want to display the formatted username.
Some that I think need to be updated:
- comment_preview():
Can be simplified a lot with getDisplayName(). That said, comment author name is actually a bit tricky, see also preSave(). Not sure what to do there, as it is used as the form value in some cases... But not using the display name would mean that the alter wouldn't work?
- ContactController::contactPersonalPage()
- template_preprocess_forums()
- Rss::render()
- Not sure why rdf_preprocess_user() in the referenced issue did not want to use the display name?
- shortcut_set_switch_submit()
- A few in user.module I think and user.pages.inc I think
- RegisterForm
- UserAutocomplete::getMatches()
- UserSearch
Comment #10
blueminds commentedI addressed following:
- ContactController::contactPersonalPage()
- template_preprocess_forums()
- Rss::render() (only node)
- Not sure why rdf_preprocess_user() in the referenced issue did not want to use the display name?
- shortcut_set_switch_submit()
- A few in user.module I think and user.pages.inc I think
- UserAutocomplete::getMatches()
- UserSearch
lets see what test bot says.
Comments are more tricky. I think for the author field we should already store the displayName value. However there are two places where the author value is used to load the user - comment_preview() and CommentFormController::submit(). I suggest to rework these two places to load the user entity differently and then the preSave() can directly set as the author the displayName.
Comment #11
berdirSomething else that I noticed is the user:name token. We probably need a token there for the raw username and one for the formatted, if you look at things like the registration confirmation mails, they use user:name twice, when addressing the user, it should use the formatted version and when it's used for the login information, it should be the actual user name.
Comment #12
scor commentedComment #13
berdirpsr-4 re-roll.
Comment #15
berdirLooks like a random fail:
Drupal\system\Tests\Cache\ApcuBackendUnitTest
Created time is correct. Other GenericCacheBackendUnitTestBase.php 172 Drupal\system\Tests\Cache\GenericCacheBackendUnitTestBase->testSetGet()
Comment #16
berdir13: 2112679-get_username-13.patch queued for re-testing.
Comment #17
krlucas commentedI'll work on updating token support and the comment module related issues.
Comment #18
krlucas commentedUpdated the user token support and references to the [user:name] token that I could find.
Comment #20
scor commentedWe should probably keep the [user:name] to maintain backward compatibility with sites upgrading from D7, but what value should it get?
Comment #21
krlucas commented[user:name] should probably get $user->getUsername() since D7 doesn't use user_format_name() when it does the replacements for e-mails, filepaths.
Also, [comment:author:name] and [node:author:name] need to be updated. This is probably the trickiness @blueminds was referring to in #10 as the comment auth values are stored in the comment table, not pulled from an associated user. Further, some places (according to #10) might use the stored name in the comment table to retrieve the user object. If we started storing the altered username those things would break.
Comment #22
berdirActually, if you look at d7 user_tokens(), it *does* use format_username(), as does 8.x right now.
Dave Reid might be able to help here, he maintains realname.module, one of the main reasons for that hook to even exist and he maintains the token module and I think I've seen him mentioning this problem before I think.
Comment #23
scor commentedThat's easy then, [user:name] can just map to
$account->getDisplayName(), and there is no need to introduce [user:displayname]. We can also have [user:username] be getUserName().@berdir: are you in Austin?
Comment #24
krlucas commentedOk. New patch adds the [user:username] token. [user:name] is mapped to getDisplayName. I also found some other instances of user_format_name().
Still need to figure the node:author:name token and the comment->author (including the token).
Comment #25
blueminds commentedjust to have the testbot trigger
Comment #26
blueminds commentedAs far as I remember, to distinguish between processed and non-processed value the token module uses "raw" in the token name/description. Shouldn't this pattern be used here as well to clearly communicate if the username value is processed or comes directly from the database?
Comment #27
krlucas commented@blueminds good point. I'll check token module and re-roll the patch to keep it consistent.
Comment #28
krlucas commentedToken module itself doesn't define a "raw" token. Realname does, but it also has a different name for the "display name". I'm going to leave as is for now in case anyone else has an opinion on the token naming.
Diving into the Comment author related stuff mentioned in #24.
Comment #29
krlucas commentedThe comment stuff was weird, as @blueminds mentioned the form submit and preview were using the author name to load the user and set the comment owner.
Instead I followed the advice of the "todo" and set the uid for the comment in the form constructor. Then the parent form submit builds the comment entity and sets the owner properly.
Patch attached.
Comment #30
krlucas commentedUnassigning and setting to needs review.
Comment #31
blueminds commentedThanks, looks good!
A few comments:
This can be on one line, no need to create a new variable here. Same below in User::getUsername()
I still think this is not self explanatory enough. If you look into template_preprocess_username() there we have a variable 'name_raw'. The token however uses just 'name' and introduces 'username'. Moreover we have the API method getDisplayName(). So we have four namings and just two things. I suggest either the token to use name_raw for the DB value or let's introduce 'display_name'. I prefer the later as we already have getDisplayName(), so making it uniform makes sense (also in the templates). To justify: if you look at 'name' and 'username' none of them really says which one comes formatted.
Comment #32
blueminds commentedAlso this seems to be not right, as the raw value is expected to be as *is* from DB. getDisplayName() will get already processed value.
Comment #33
krlucas commented@blueminds I know what you mean. However, see @scor's comment in #20. He makes a good point that people moving from D7 to D8 will need to update all their [user:name] tokens. Perhaps we leave [user:name] as "deprecated" and map it and a new token [user:displayname] to getDisplayName().
RE: #32 it's definitely not intuitive but that's the functionality in D7: https://api.drupal.org/api/drupal/includes%21theme.inc/function/template...
Per the comments "name_raw" in template_preprocess_username() is still the formatted username--but unshortened and unsanitized. Do we want to change the meaning of "name_raw" in that context?
I'll roll a patch with fixes for 1. in #31.
Comment #34
krlucas commentedHere's the patch re-rolled to now reduce the size of the getUsername methods per first part of #31.
Comment #35
blueminds commentedYup, I see. Other than that, I think it can be RTBC. Me coded part of it, so someone else please :)
Comment #36
berdirThe views user name field doesn't work correctly yet I think, create a list of users as table with fields, the display formatted user name (which is checked by default) has no effect.
Comment #37
scor commentedComment #38
berdir#734878: [user:name] tokens should be using format_username() and use [user:name-raw] in email templates is related, whatever we do should probably follow that...
Comment #39
lokapujya34: user_getusername-2112679-34.patch queued for re-testing.
Comment #40
lokapujyaReroll, will test.
Comment #41
lokapujyaTested: The "Use formatted username" in views doesn't change anything.
How do you get a formatted name that is different form the raw name?
I created a user_format_name_alter() and that changes the name (Is that what a formatted name is?), but the views setting doesn't affect the altered name; It always uses the altered name. Tried username_alter() but that didn't change the name at all.
Comment #43
damiankloip commentedI guess you still had the link to user option checked too? This will then use theme_username regardless, which means you will always get the display name if you check to use a link. I will open a separate issue for that.
Comment #44
damiankloip commentedActually, might as well roll it in here. It's dependent on this anyway.
@lokapujya, these changes should work as expected. If you could test again, that would be great. This is a quick patch - I don't have much time. Should work though :)
Comment #46
lokapujya#44 fixes the problem mentioned in #41, however it seems like renderLink() needs an authenticated user. I'm not sure how to fix it, but here is some code that is passing tests for me.
Comment #47
damiankloip commentedThat's a revert of what I changed in #44. It works but it is not right IMO - It's ugly and hacky. That's an artefact of D7 views.
We now have the entity attached to a row. Hence the call to getEntity() instead. So we need to get it working using that.
Comment #48
damiankloip commentedThinking about it, what exactly is not working for you with the patch in #44?
getEntity() will return an entity which is what we want - just without the hackery. The tests just need adapting to reflect doing this properly IMO.
Comment #50
lokapujyaNothing, I didn't mean so suggest that the code should be reverted; Just showing the exact part of the change that broke tests as they existed.
The remaining test failure is passing on my local environment.
EDIT: Well it was, until I did a git clean, and reapplied.
Comment #51
lokapujyaChanged test to use the views result from the new user. Removed an unused variable.
Edit: Left in a debug that is not highlighted in the interdiff.
Comment #52
damiankloip commentedOK. Looks pretty good to me. I didn't actually test the patch, just converted the test. It was using the same Jacky approach that the code was before :) do you want to remove that debug? We are prod looking pretty good then I think.
Comment #53
lokapujyaComment #54
damiankloip commentedLooks like the actual patch is correct (with debug() removed) but just the wrong interdiff attached?
Also, if possible, could you use the name of the issue-comment in the interdiff too? d.o will hate you for calling another file interdiff.txt :)
Comment #55
lokapujyainterdiff do-over. :)
Comment #56
damiankloip commentedYep :) looks good.
Comment #57
berdirRe-roll.
Comment #58
berdirAnother re-roll. Setting to a major bug because if you save the user edit form with a module that alters usernames, you end up with a different username and crazy bugs like that...
Comment #60
berdirUps, had some junk in that patch file.
Comment #62
undertext commentedAgrh. Just started this issue https://www.drupal.org/node/2311219 and then saw this topic.
Maybe we should only add getDisplayName() and change logic of getUserName() in this issue, and do not replace user_format_name occurrences, or just close that issue ?
Anyway with the latest path 'label_callback' from core/modules/user/src/Entity/User model is till using user_format_name() function.
Need to deal with it.
Comment #63
damiankloip commentedLet's see how this gets on. Amended the deprecated message to make it correct too.
I think we should not tackle that in this issue, as the callback will need to pass the callable from the annotation which we currently cannot do.
Comment #65
berdirI lost the test module along the way. Also added an explicit sort on that test view, the order of users was not reliable, not sure how that is related to this issue, though.
Comment #66
damiankloip commentedAh ha! I assumed they were still in there :)
Comment #67
dawehnerIt would be great if we could mention that the best way would be to use this just in templates.
I wonder whether we could avoid confusing if there would be user:displayname and user:username instead.
I guess we can drop the user bit of the documentation.
nice!
looks perfect! Much simpler logic actually at the end of the day.
Same as with just user:
quick note: this view does not have a sort handler, at least we should add it on a followup due to given potential random failures.
Nice, someone read my mind!
Comment #68
damiankloip commentedHere we go. Made those changes and discussed on irc - Let's go back to
user:namelike we had before anduser:display-namefor the display name?Comment #69
berdirTokens are fine with me.
Is this something that the migration of those settings should care about? Possibly in a follow-up?
Comment #70
damiankloip commentedYes, that's a good point indeed. And yes, I think that should be a follow up. This patch is big enough for this "simple" change :)
Comment #71
dawehnerIt would be great to fill a change notice or rather update an existing one, given how otherwise the mass of change notices would grow.
Comment #72
chx commentedI am very confused. One source of the confusion is the issue summary suggesting ->label() but the patch adding a new ->getDisplayName() . That, I guess is a simple change to the issue summary.
Then getUsername is return $this->name ?: ''; when just return $this->name should be fine. Isn't that so? The default is '' after all.
But the biggest confusion is the issue itself. So getUsername doesn't return the raw username? In what circumstances? That's not in the IS either. I mean, yeah, anonymous and that alter probably doesn't belong there but my problem is that getDisplayName is not the result of user_format_name() as one would expect but ... what? The name of method is decidedly odd and the distinction between getUsername and getDisplayName is not clear to me -- one wonders whether that's a case "listen to the code, it's trying to tell you something" or "chx is dumb and the doxygen is not helping". Is really the distinction only in anonymous + alter? If so then why are we adding a new method instead of moving those into user_format_name() ? I just don't get what and why happens here.
Tentatively setting to CNR.
Comment #73
berdirI only understand half of what you said @chx, but here's how it is:
Current situation:
- getUsername() == label() == user_format_name(), which is the possibly altered username. Most common use case is realname module.
This is a problem because getUsername() is used as if it *would* be the raw username, for example it is the default value for the username field when editing a user.
So this issue adds a getDisplayName(), which is the same as label() and user_format_name() (which is deprecated, that is why we are adding a new method). getUsername() now returns the actual username, unchanged.
Comment #74
chx commentedRemind me then why we are not using label() ?
But if we go with getDisplayName, the summaries are not helpful: "Returns the unique username of this account." vs "Returns the display name of this account." I think what you wanted to say is "Returns the username as it is stored" vs "Returns the user name as it should be displayed" but then again the second is not right because it's not how it should be displayed because it needs to be checkPlain'd first :/ see this is a case of "listen to the code, it's trying to tell you something" after all -- why don't we checkPlain the return value of getDisplayName, hrm?
Comment #75
scor commentedchx has a point regarding the label() method. Shouldn't we ensure that all entities have such method for consistency so one can always call ->label() on any entity?
Comment #76
berdirwhat method exactly? All entities have label() and label on users is user_format_name()/getDisplayName().
label() is however currently not check plain'ed, so we can't check_plain() getDisplayName(). Yes, maybe it would make sense, but that's a completely different discussion and would result in a number of other problems, because sometimes, you need the label unescaped and it is very common to use the label in @something placeholders, so those would have to be updated to use !. So I disagree that we should do this here.
Update the issue summary and the docblocks, sure, if anyone has ideas on how to improve that...
Comment #77
chx commentedAmend the doxygen of EntityInterface::label() to clearly state
once that's done, you can use label() freely for the formatted username. Next, why getUserName() ? Why not getName() since it returns $user->name->value ? What else would it be if not the name of the user? Node has getTitle and not getNodeTitle.
Comment #78
damiankloip commentedHere's the getUsername > getName change. That makes sense. Let's talk about chx's other point some more, as we ideally do not want to be keeping user_format_name. I would like to see us being able to support callbacks on the entity instance. So core could ship with a call to getDisplayName(), other people could then override easily if they wanted to by specifying their own label callback. thoughts?
Comment #80
damiankloip commentedActually, sorry, I am going mad.
getUsername() is the current name already. Let's not change that in this issue chx.
Comment #81
chx commentedCan be a followup, for sure. Also, we can simply override
User::labelonce we documentedlabelas described in #77. We can even remove the "label callback" capability because that's a really weird thing in an OOP world -- just overridelabel(), done.Comment #82
mgiffordWhat' up with the patch in #78?
Comment #85
krlucas commentedRe-rolled the patch from #68 (patch in 78 changed getUsername to getName which we're postponing for follow-up).
Comment #86
krlucas commentedI honestly don't really remember why we went with getDisplayName instead of just overriding label. If we do decide to use label() instead, can we get rid of all that get/set/hasLabelCallback business from entities in general?
Comment #87
lokapujya" If we do decide to use label() instead, can we get rid of all that get/set/hasLabelCallback business from entities in general?"
Are we doing that here or in a followup? Would be nice to move this along.
Comment #90
jeroentComment #91
nlisgo commentedThis issue is affected by this: #2434697: Remove UserAutocompleteController
The UserAutocompleteController is now gone. We are instead to use entity_autocomplete.
Comment #92
nlisgo commentedComment #93
piyuesh23 commentedComment #94
piyuesh23 commentedPatch re-rolled. Attaching the re-rolled patch below.
Comment #96
piyuesh23 commentedMissed out the test files. Attaching another patch with test files attached as well.
Comment #98
piyuesh23 commentedRe-rolled patch. Uploading the updated patch.
Comment #100
piyuesh23 commentedRemoved duplicate functions & uploading the fixed patch.
Comment #102
kerby70 commentedQuick reroll attached fixing patch failure after change in 8.0.x-dev.
Comment #103
jeroentComment #105
kerby70 commentedContinued patch changes.
Comment #107
m1r1k commentedComment #108
m1r1k commentedReroll and bunch of fixes.
Comment #110
m1r1k commentedReturn lost changes and fix test failures
Comment #112
m1r1k commentedOops, wrong one.
Comment #114
m1r1k commentedHas to be rerolled after this one
Comment #115
m1r1k commentedRerolled
Comment #116
m1r1k commentedComment #117
mile23Not sure about the rest of it, but
core/modules/user/src/Entities/User.phpsays this in the entity definition annotation:Note that the entity annotation docs don't tell you what to do for
label_callback: https://www.drupal.org/node/2207559This issue is a blocker for #2311219: Fix hook_user_format_name_alter() documentation and stop referring to user_format_name() which means we can't finish deprecating user_* functions until this is decided.
Comment #118
nlisgo commentedThis is a re-roll as getting rid of a change to hook_rebuild as list_themes() is no longer available since #2151469: Clean-up usage of deprecated list_themes() and _system_rebuild_theme_data() in favor of theme_handler service
Comment #119
nlisgo commentedoh, here's the patch :)
Comment #120
nlisgo commentedAll other lines in this patch seem related to this issue.
Comment #122
nlisgo commentedComment #125
mile23Thanks for sticking with it, @nlisgo.
Updated the issue summary, pretty sure this will need a change record.
Hopefully some of the folks from early in the comment thread can weigh in as well.
Comment #126
berdirDidn't verify that all places have been updated but the patch looks good to me.
I've been using an old version of the patch here for almost a year now, some places in Drupal are really broken in HEAD when you use hook_user_name_alter(), for example the user edit form that displays the altered username instead of the raw one as default value.
Yes, this needs needs a change record, or maybe some change record updates (if that, then that should be outlined in the issue summary) and a beta evaluation, explaining why the disruption (and is quite a disruption, I've had conflicts on my old patch on almost every update I did) is worth it and needed. Those things need to be done before it can be RTBC'd, so setting back to needs work for that.
Comment #127
mile23This is a bit of a blocker for #2311219: Fix hook_user_format_name_alter() documentation and stop referring to user_format_name(), which is removing a @deprecated function.
It's possible that we could deprecate
user_format_name()in some other way, and if that's the case then maybe we could work on that instead of this disruptive way.Comment #128
mile23Needs work here: #2450793: Properly deprecate support for entity type label callbacks
Almost a blocker.
Comment #129
lokapujyaAdded beta evaluation. Instead of new CR, can we update: #2017231?
Comment #130
mile23Edit: never mind.
Comment #133
berdirComment #134
subhojit777Comment #135
amitgoyal commentedRe-roll of #122.
Comment #136
amitgoyal commentedRemoving 'needs reroll' tag.
Comment #138
subhojit777I started working on this issue while I was at work and was unable to continue it. Looking into it now.
Comment #139
subhojit777Comment #140
subhojit777Comment #141
andypostthat's looks wrong because defaults for user uploads are not affected in patch otherwise you need to provide upgrade path and change migrations, so please remove this hunk
Comment #142
s_leu commentedHere's a re-roll that reverts the hunk in FileFieldPathTest.php as suggested in #141
Comment #146
dustinleblancRe-rolling again, previous patch didnt apply
Comment #147
dustinleblancChanging status
Comment #149
dustinleblancI missed some git conficts; had to clean up some tests that had changed in HEAD since original patch
Comment #151
jeroentFixed the last failing test.
Comment #153
lokapujyaSeems like the test is not looking at the right result. It should look at the new user, not anonymous.
Note: In a previous patch we used the hardcoded 3rd result. Somewhere along the line, the 3 changed to 0. My patch picks the result from the userID which is hopefully less fragile.
Comment #156
berdirReroll, fixed some tests.
Comment #157
borisson_I changed a couple of instances where we already had a changed hunk but still used the old style array syntax to use the new array syntax, I also changed one comment that was wider than 80 columns.
Comment #158
berdirAnother reroll.
Comment #160
nlisgo commentedComment #161
daffie commentedI did a quick review and I have two remarks:
This line does not look good to me.
I thought we were using name and display-name and not name and username.
@nlisgo: Thanks for the typo fix.
Comment #162
subhojit777I guess its an unrelated change.
Comment #163
subhojit777Items suggested in #161 are covered.
Comment #165
subhojit777Comment #166
subhojit777Seems like a random failure. Tests passed in my local.
Comment #168
subhojit777Added beta evauation as per #129. Are we going to edit 2017231 for change record?
Comment #169
daffie commentedUpdated the change record #2017231: Added AccountInterface as common interface for the global $user object and user entities.
The patch looks good to me.
Comment #170
catchThis needs updating to Html::escape() and is not quite right with Twig autoescape.
When is this the case?
Having both name and display name here is confusing.
Comment #171
berdir2. Yeah, looks like that doesn't make sense, we already initialize the property.
Confusing how? That's *exactly* where we need those two different tokens, see the updated default mails. You want to use the display name when addressing the user, but when telling him how to log in, you want to use the actual username.
I understand that this is quite an API change but it's also a serious bug when altering the username, since it will use the display name in the user edit form, just to name one example. I've been using a patch from this issue for more than I year but never found time to push it through. We can try to find a way to make the change smaller if needed, but in a way, the change is good since it forces you to think about which one you want to use. A possible alternative would be to keep user:name as it is and introduce a new token for the actual user name and stop using getUsername() where you want to actual username (yes, sounds weird).
Comment #172
nlisgo commentedAddressing points 1 and 2 in #170.
Comment #175
nlisgo commentedIgnore the bad patch in #172.
Comment #176
nlisgo commentedComment #177
subhojit777Comment #178
catch@berdir #171
I think it would be less confusing if we had getLoginName() or getAccountName() vs. getDisplayName(). We could possbly deprecate name() and add the extra method?
Comment #179
subhojit777#178++
Comment #180
subhojit777Patch using
getAccountName().Comment #182
scor commentedI agree with catch's point in #178, but the patch #180 does not implement that. The patch should keep getDisplayName(), but replace name() with getLoginName() or getAccountName() to be more explicit than something generic and ambiguous like "name".
EDIT: @catch: do you not like getUsername() which we already have? or maybe I'm misunderstanding your point.
Comment #184
catchYes scor's interpretation is what I meant. Either getLoginName() or getAccountName() would be much less ambiguous compared to name().
Comment #185
alexpottWe've never had a test implementation of
hook_user_format_name_alter(). Through work on #2559971: Make SafeMarkup::format() return a safe string object to remove reliance on a static, unpredictable safe list though which I found #2571909: CommentForm selects using the user formatted name it is clear this is a critical issue. Any implementation of the hook will break Drupal and if a user saves their user form we will have data loss.Comment #186
znerol commentedComment #187
alexpottThis is now all duplicate code - I added a test recently that adds a hook implementation -
user_hooks_test_user_format_name_alter()let's use it here.Comment #188
berdirWorking on this.
Comment #190
berdirUpdated to use the existing test module.
Want to discuss the method names tomorrow with @catch.
Comment #194
berdirGoing back DisplayName since that's not the method we want to rename.
We have 130 calls to getUsername(). I'm not sure if and how much of that we should really rename here. Maybe we should just add getAccoutName(), deprecate getUsername() for D9 and document that you should use getAccountName() or getDisplayName() ?
Comment #195
berdirHere's the interdiff.
Comment #196
dawehnerShould we document that autoescaping makes that not needed most of the time?
Comment #197
alexpottI think this is wrong... the D7 version of this code was:
Comment #198
dawehnerWorking on the change record now.
Comment #199
znerol commentedAttached is a little module which should help with manual testing.
Comment #200
berdirDid what I suggested in #194, did not address the reviews yet, want to discuss the @return documentation with @alexpott.
Comment #201
damiankloip commentedWon't we get a string casted value anyway here, from typed data?
Comment #202
mile23If the only use-case for
getDisplayName()is to return 'Anonymous' when there's no logged-in user, then we don't needgetDisplayName().Thus change
getUsername()toAccountInterface::getName()which reflects that its the name for the account. It then returns either the name or 'Anonymous' if there's no logged-in user.We already have
AccountInterface::isAnonymous()to check whether we should rely on the account name for anything.If we had a machine name plus human-readable feature for
User, it would make sense to have two name methods. But we don't.Contrib or site-builders can attach a field to give a display name.
Just my two cents. Don't want to trip up a critical.
Reviewing the patch in #194
Use
$this->isAnonymous().Comment #203
alexpott@Mile23 we have hook_user_format_name_alter() see the text module posted by @znerol in #199. If a module implements this hook they can cause data loss on the account edit form because when you edit your account form it will use the altered name.
Comment #204
alexpottComment #205
mile23It's like they say: If you see a gun in the first act of the play, someone will die before the third.
Sorry. Insomnia. I hope you're all enjoying Spain.
Comment #206
znerol commentedI think we should remove
hook_user_format_name_alter(). I understand that this will impact a couple of contrib modules. However, I argue that all of them could implement their use cases with different means. Even more so because they tend to be incompatible with each other due to their potentially conflicting uses of that alter hook.Another reason for ditching that hook is that this is virtually incompatible with autocomplete. I.e., if you implement the hook, then the modified part of the name will not be searched for on entity reference autocompletes.
As far as I can see (grep) this would affect the following D7 contrib projects:
Comment #207
berdirDiscussed the @return documentation with alexpott, this should be better.
Also updated the tokens as discussed. We deprecate name, just like getUsername() in favor of either account-name or display-name.
Comment #209
dawehnerWe should add some test coverage for that additional token
Comment #210
berdirUpdate and extend UserTokenReplaceTest
Comment #211
dawehner#2112679-206: getUsername() should return the username getDisplayName() for the formatted user name made a compelling argument why we need the feature in the first place.
Comment #212
alexpottLet's remove all usages of
[user:name]in core.No need to call
Html::escape()on the new account-name - it is not possible to put an escaped character in a user name anyway - plus we have autoescape.In Drupal 7 this was the account name and not the display name which I think makes sense.
Comment #213
berdir1. Makes sense, also the tokens were actually wrong.
2. As discussed, I added/kept it to be consistent with the token implementation which uses it too.
3. As discussed, I used the display name for the dsm() and account name for the log.
Comment #214
dawehnerGood catch!
Comment #215
berdirFollow-up: #2572821: Fix documentation on hook_user_format_name_alter()
Comment #217
mile23Just a nit. Could be changed on commit.
'Either is safe to be printed.'
Comment #218
catchgetDisplayName8 - fixable on commit.
So in general I agree with znerol's point in #206 - I'd much rather see things like this handled by formatters a 'name' user entity view mode or similar.'
However we do not use formatters on the user entity when we render user names - like 'submitted by, menu links etc., so that will require a lot of things put into place so that we're not retrieving the username from the account object directly in those places. Additionally either @alexpott or @Berdir pointed out that it's not possible to have two formatters for the same field on the same view mode - which we'll need if we want to show both user pictures and user names in different places on node/comment.
Should definitely aim for that, but this feels like a good fix for the comment autocomplete data loss that doesn't prevent us doing a broader fix when the other bits are in place. Would be good to have a follow-up for submitted by though, I'd open it but not sure if there's an existing issue out there.
Comment #221
stefan.r commentedOnly tiny nits in docs, so leaving RTBC per #214
Comment #222
alexpottSaying that is returns a username to display is confusing... primarily you use this when you are not displaying the username. In fact we should document that this should only be used to display the name to admins and the user themselves and only in the context of the name used to login.
Comment #223
stefan.r commentedI'll update the docs
Comment #224
stefan.r commented@alexpott it's not just confusing, it seems wrong... but that's what the docs used to say. I guess we should update getUsername() as well then (even if it's deprecated). Updating the patch accordingly.
Comment #225
dawehnerMorning nitpick:
Let's use @return string
Comment #226
stefan.r commentedComment #227
andypostWhy that calls deprecated method?
I think better to add here a protected property to call alter only once, mean cache generated value
Comment #228
catchShould be AccountInterface::getDisplayName() no?
Shouldn't this be user:account-name and user:display-name now?
Same question.
Hmm I had to read through the whole string to see if we really wanted display-name here, but we do use account-name later so they seem like good changes.
user:account-name again - still using user:name
Shouldn't this be getAccountName()?
Comment #229
dawehnerWorking on addressing the feedback.
Comment #230
dawehnerYeah, I think it is the right change, just imagine that users don't want to reveal their account login username.
Yeah I kinda agree that this is the thing, that should happen, but yeah people don't care that much, berdir isn't sure at least.
Comment #231
nlisgo commentedNeeds a comma at the end of the last value in the array.
Comment #232
nlisgo commentedAdded comma referred to in #231.
Comment #235
nlisgo commentedI totally screwed up that patch. Let me try again :(
Comment #236
dawehnerWe discussed that we actually want the display name. Imagine /admin/people and a user administrator. A user is removed and accidentally you see a different user is removed,
as the user name is displayed.
@nlisgo I just include your changes into the patch as well.
Comment #237
nlisgo commented@dawehner thanks. I tried to load it in but the wifi failed me. I can't blame the wifi for my patch though.
Comment #238
berdirMy own patch was already RTBC, so I think I can RTBC the changes since then, looks all good to me.
Comment #239
stefan.r commented+1 looks great!
Comment #240
webchickWalked through this patch with @dawehner at my side at DrupalCon. :)
The one thing I raised my eyebrows about is that this doesn't sound like a dangerous method, but it is a dangerous method. Like we could call it "getRawAccountName()" or something.
OTOH, after looking more into the old implementation of getUsername(), it also didn't escape anything, so I think this is fine.
I had a question about hunks like this... before we were using ->getUsername() in both, but here we swap logger's version for $account->getAccountName().
When asking dawehner about this, he said that this is because in admin UIs, when deleting a user, you want to see the name of the person you just deleted (which would have been their display name), but in logs you'd want to use the username in case you need to query for the person.
Other than that, this is pretty straight-forward. Introduces new methods, deprecates the old one, switches it everywhere.
It looks like @alexpott's most recent feedback was taken care of, soooooo....
Committed and pushed to 8.0.x. One critical down! :D Thanks!
Comment #242
mile23Added a follow-up: #2575213: Deprecate hook_user_format_name_alter()