user save() has some crufty code which needs cleaning. I clean what I can in this patch and leave the API changes for Drupal7. This patch
- Uses drupal_write_record() for writing to users table
- Updates user_fields() to use schema API instead of its own way to discover the fields in the table
- Fixes a buglet during registration and user edit where we insert form_build_id into users.data. thats an internal value of no interest to a user.
This patch adds a serialize param to users.data in hook_schema so you have to refresh your Schema to test (use devel's clear cache or empty cache table or start with a fresh Drupal).
There is no performance impact from this patch - just code cleanup/updating. The queries that get issued are unchanged.
This patch brings us closer to being able to drop in a data API as specified at http://cvs.drupal.org/viewvc.py/drupal/contributions/modules/object_driver/ or http://drupal.org/node/79684.
Comment | File | Size | Author |
---|---|---|---|
#34 | 181411_use_schema_api_during_user_save-34.patch | 4.84 KB | Freso |
#29 | mw.patch | 12.1 KB | moshe weitzman |
#20 | mw.patch | 12.37 KB | moshe weitzman |
#13 | mw.patch | 12.35 KB | moshe weitzman |
#10 | user-save-schema-181411-10.patch | 12.69 KB | bjaspan |
Comments
Comment #1
Dries CreditAttribution: Dries commentedI did a code review and the code looks good, Moshe. One remark: user_fields() is only called from one location. We should be able to nuke that function now.
(I haven't tested this patch yet.)
Comment #2
moshe weitzman CreditAttribution: moshe weitzman commentedThis version gets rid of user_fields().
Comment #3
chx CreditAttribution: chx commentedI cleaned up a bit more cruft around the ifs that set/unset $data parts.
Comment #4
moshe weitzman CreditAttribution: moshe weitzman commentedThanks chx.
In order to test this, i suggest the following:
- register a new user
- login as that user
- submit profile page edit but don't change password
- logout
- login as same user (checks that password was indeed unchanged)
- edit profile and this time change password.
- logout
- login with new pass and assure you get in.
Comment #5
moshe weitzman CreditAttribution: moshe weitzman commentedAdd to that test plan:
- submit a profile edit when the profile field appears on its own tab (i.e. not on the tab with username/pass).
Once I did that I found a need to handle the case when no changes are needed during a call to drupal_write_record(). Thats why the attached patch modifies that function slightly.
Comment #7
Dries CreditAttribution: Dries commentedI've tested this patch and it works. The quality of the code comments needs to improve though. For example
for ext. auth are
should be written in full so that it is accessible for less savvy developers. That line is _critical_ for security so let's not take that lightly. Thanks.Is the
+ if (!empty($data)) {
check in user_save() still required now?Comment #8
moshe weitzman CreditAttribution: moshe weitzman commentedI rewrote that comment and made drupal_write_record a bit more robust so that we don't have to check
f (!empty($data))
as Dries suggests.Note that all traces of distributed auth will be removed from user_save() with this patch - http://drupal.org/node/181578. I will reroll that one after this one lands.
Anyone testing this patch should remember to wipe schema cache before executing the test plan above.
Comment #9
moshe weitzman CreditAttribution: moshe weitzman commentedrerolled since one hunk failed. i rechecked the test plan and it works fine.
Comment #10
bjaspan CreditAttribution: bjaspan commentedI reviewed this patch and it works fine. Besides Moshe's test plan, I also tested the serialized data field: add a value, preserve a value if it is unset, remove a value if it is set to NULL. It probably would have taken less time to write simpletests than to test it manually.
I made some changes:
1. Instead of setting $user_fields = array_keys($user_table['fields']) and then testing in_array($key, $user_fields), I set $user_fields = $user_table['fields'] and then test empty($user_fields[$key]). This turns O(n^2) to O(n lg n) for no extra work.
2. I improved the docs for user_save() and moved a comment for coding standards.
A new patch with these changes is attached.
I also note that this patch introduces an API change: Previously, in hook_user('update'), $edit['pass'] was always set but was '' if the user did not enter a password. Now, $edit['pass'] is unset is the user enters no password. This triggered an E_ALL error in persistent_login.module which is how I noticed. I think the new behavior is fine but should be documented in hook_user and perhaps in the D5 > D6 module upgrade notes.
If Moshe reviews and approves my in_array() to empty() and comment change, this is RTBC. Whether or not this constitutes a "bugfix" that gets into D6 is a separate issue.
Comment #11
moshe weitzman CreditAttribution: moshe weitzman commentedbarry's changes are good. RTBC
Comment #12
moshe weitzman CreditAttribution: moshe weitzman commentedActually, the new comment on user_save() has some funky language in it. In fact, I can't figure out whats intended. Since thats my only concern, i ask Barry to re-word that and then RTBC.
Comment #13
moshe weitzman CreditAttribution: moshe weitzman commentedI fixed up that comment.
Comment #14
bjaspan CreditAttribution: bjaspan commentedSorry for not doing this myself, I was out of town all week at a client site. Just got back last night.
Comment #15
Dries CreditAttribution: Dries commentedThis looks a bit like a hack. I can see why it's necessary but it ain't pretty. Maybe there is a creative workaround that looks slightly prettier? ;-)
This looks really odd and not something we had in the old code, I believe. Is this an inherent drawback of the new mechanism?
Comment #16
bjaspan CreditAttribution: bjaspan commentedRegarding
unset($array['pass'])
, the current code does this:If no key of the array is 'pass' *or* if pass is empty, the query never sets that column. drupal_write_record() does the former ("don't set columns whose keys are unset in the passed object") but cannot assume that empty-string values also should not be set (because often they should be).
So, yes, this unset is effectively something we have in the current code in a different form, and requiring it is not a drawback of drupal_write_record(). It is just an example of having to normalize a data structure to comply with a slightly more general-purpose API function.
Comment #17
Dries CreditAttribution: Dries commentedThanks for clarifying, Barry! You're absolutely correct.
Comment #18
moshe weitzman CreditAttribution: moshe weitzman commentedIt is true that drupal_write_record() does some awkward type switching. But we try to be a convenient API function for all callers. The only solution I can see is to standardize on arrays or objects for our major objects and fapi. Since thats feasible in this patch, and neither Barry nor I nor Dries sees a better solution, I ask that we consider committing with this known awkwardness.
Comment #19
Gábor Hojtsy$ patch -p0 < mw_105.patch
patching file includes/common.inc
Hunk #1 succeeded at 3291 (offset 126 lines).
patching file modules/profile/profile.module
Hunk #1 FAILED at 344.
1 out of 1 hunk FAILED -- saving rejects to file modules/profile/profile.module.rej
patching file modules/user/user.install
patching file modules/user/user.module
Hunk #4 succeeded at 2081 (offset 3 lines).
patching file modules/user/user.pages.inc
Comment #20
moshe weitzman CreditAttribution: moshe weitzman commentedrerolled
Comment #21
Gábor HojtsyIn all honesty, I am not sure about what to do with this patch. We have seen several pass by reference (eg. in node revision saving), default value setting, database compatibility etc. issues around drupal_write_record() implementations elsewhere, and needed to work on fixing all those. As far as I see this code change is a nice cleanup, but does not fix a bug or introduce anything new. Changing the user saving implementation this late does not sound the best idea, although I wholeheartedly agree that the current implementation looks ugly, and it should be fixed when safe. Let us know if you think otherwise.
Comment #22
bjaspan CreditAttribution: bjaspan commentedI agree that this is not mandatory. We're way past where the line for D6 should have been drawn...
Comment #23
Gábor HojtsyThanks for understanding. Moving to D7. Keeping status, so it is committed early.
Comment #24
pwolanin CreditAttribution: pwolanin commentedlooks like a couple small parts of this should be for D6 - like
Comment #25
moshe weitzman CreditAttribution: moshe weitzman commentedyes, there are some bug fixes here too. hope someone will extract them.
Comment #26
leoman730 CreditAttribution: leoman730 commentedHey guys,
I need some info on this silly question, often time i see attachment with extension .patch. I know the intense of this file is to fix issue. My question is how can I use this file and apply it to the module. Could anyone provide me some steps on how to use it? Many thanks.
Comment #27
keith.smith CreditAttribution: keith.smith commentedleoman730: See http://drupal.org/patch/apply for more information.
Comment #28
hswong3i CreditAttribution: hswong3i commentedcatch judge that #211496 is duplicated with this issue, but sorry that I don't really think so: #211496 is introduce because of incorrect data type matching before we build the queries. I seems this as something more critical that refactor overall user_save() handling for elegant. BTW, I keep a message here as a reference of that bug, and so let's solve it after D6 ;-)
Comment #29
moshe weitzman CreditAttribution: moshe weitzman commentedHere is a reroll to fix a little decay. I resisted the temptation to expand this patch; nothing has changed so we preserve the RTBC status.
Comment #30
Dries CreditAttribution: Dries commentedCommitted to CVS HEAD. Thanks.
Comment #31
pwolanin CreditAttribution: pwolanin commentedAs I noted above, there are a few small pieces of this patch that should be in 6.x
Comment #32
Freso CreditAttribution: Freso commentedI think it would be good if someone who knew what to extract for 6.x (pwolanin? moshe?) either ported those changes to 6.x or were more specific so someone (me, perhaps) could easily tell what to port and what to discard.
Comment #33
pwolanin CreditAttribution: pwolanin commented@Freso - looks to me like this might qualify as 6.x bug fixes to be extracted from the patch:
all the changes to includes/common.inc
the change to modules/user/user.install
all changes to modules/user/user.pages.inc
the change to function user_register_submit() in modules/user/user.module
Comment #34
Freso CreditAttribution: Freso commentedAlright then. Here's a straight port of the things pwolanin picked out in #33. It is exactly the same code changes as those in #29, as that patch applied cleanly to DRUPAL-6 (with some offset).
I haven't tested this though, as I must admit I haven't even read the issue through to be sure what needs to be tested. I just thought I'd put some work towards cleaning out the 6.x "to be ported" queue. :)
Comment #35
moshe weitzman CreditAttribution: moshe weitzman commentedComment #36
pwolanin CreditAttribution: pwolanin commentedLooks like parts of this last patch already made it into core for drupal_write_record() - is this issue too old/duplciate now?
Comment #37
pwolanin CreditAttribution: pwolanin commented